Galaxy
Meteor

Secure Secrets Management for Meteor Apps

Keep credentials out of Git and deploy safely using secrets managers and automation.

Ever committed an API key to Git by mistake? Your heart just sank and you had to rotate credentials immediately, right?

You're not alone. Storing secrets in your repository is a security risk that every developer faces.


Why This Matters

If your repository accidentally goes public, gets forked, or your Docker image ends up in a public registry, your credentials are exposed. Game over.

This guide shows you how to keep your secrets safe and deploy Meteor applications to Galaxy without worrying about credential leaks.

Good News: It's Fixable

Even if you've committed secrets before, there are tools and practices to clean it up and move forward safely.


The Problem with settings.json

The typical Meteor workflow involves storing credentials in a settings.json file:

{
  "galaxy.meteor.com": {
    "env": {
      "MONGO_URL": "mongodb://user:password@host/db",
      "MAIL_URL": "smtp://user:password@smtp.example.com:587"
    }
  },
  "private": {
    "stripeKey": "sk_live_xxx"
  },
  "public": {
    "appName": "My App"
  }
}

If this file gets committed to your repository, you've created several risks:

  • Repository goes public by mistake: A single misconfiguration can expose everything.
  • Public forks: When someone forks to a public repo, your entire commit history comes along.
  • Git history never forgets: Deleted files stay in history and can be recovered.
  • Docker images: Files get baked into image layers permanently.

Already Committed Secrets?

If you've ever committed secrets to your repository, removing them from current files isn't enough. They're still in your Git history. Keep reading to learn how to scrub them properly.


Setting Up Secure Secrets Handling

Let's fix this properly with a setup that keeps your secrets safe.

Update Your .gitignore File

Add these entries to ensure secrets files never get committed:

# Secret files
settings.json
settings-*.json
.settings-*.json

# Environment directories with secrets
env/

This catches the most common patterns and prevents accidental commits.

Create a Settings Template

Keep a settings.example.json in your repository as documentation:

{
  "galaxy.meteor.com": {
    "env": {
      "MONGO_URL": "YOUR_MONGO_URL",
      "MAIL_URL": "YOUR_MAIL_URL"
    }
  },
  "private": {
    "stripeKey": "YOUR_STRIPE_KEY"
  },
  "public": {
    "appName": "My App"
  }
}

This file is safe to commit since it contains no real secrets. It shows your team exactly what configuration they need without exposing credentials.

Remove Secrets from Git History

If you've previously committed secrets, you need to scrub them from history.

Use a tool like BFG Repo-Cleaner to clean your repository.

Important: Rotate After Cleanup

After cleaning your Git history, rotate any credentials that were ever committed. Assume they've been exposed.


Using a Secrets Manager

A secrets manager stores your credentials securely and lets you inject them at deploy time. No more secrets in code. No more secrets in Git.

Don't worry if you don't have one yet. Getting set up is straightforward.

We'll use Infisical for this guide since it's open source and has a generous free tier. The concepts apply to any secrets manager.


Setting Up Infisical

Create an Account

Head to app.infisical.com and create a free account. Then create a new project for your app.

Install the CLI

Follow the Infisical CLI installation docs for your operating system.

Authenticate and Initialize

infisical login
cd ~/projects/my-meteor-app
infisical init

This connects your local project to your Infisical project.

Add Your Secrets

In the Infisical dashboard, add your secrets. Store the entire settings object as a single SETTINGS_JSON variable. This keeps everything organized and easy to manage.


Deploy Script

Here's a deploy script that fetches secrets from Infisical and deploys to Galaxy. Create a deploy.sh file in your project root:

#!/bin/bash

# Exit immediately if any command fails
set -e

# ===========================================
# CONFIGURATION
# ===========================================
# Change these values for your app
APP_NAME="my-app.meteorapp.com"
ENVIRONMENT="prod"

echo "Deploying $APP_NAME ($ENVIRONMENT)"

# ===========================================
# STEP 1: Verify Infisical authentication
# ===========================================
if ! infisical secrets --env=$ENVIRONMENT &> /dev/null; then
    echo "Not authenticated. Run: infisical login"
    exit 1
fi

# ===========================================
# STEP 2: Export secrets to temporary file
# ===========================================
# Creates a unique temporary filename using the process ID ($$)
# This avoids conflicts if multiple deploys run at the same time
TEMP_SETTINGS=".settings-deploy-$$.json"

# Fetches the SETTINGS_JSON secret from Infisical
infisical secrets get SETTINGS_JSON --env=$ENVIRONMENT --plain > $TEMP_SETTINGS

# ===========================================
# STEP 3: Validate JSON
# ===========================================
if ! python3 -c "import json; json.load(open('$TEMP_SETTINGS'))" 2>/dev/null; then
    echo "Invalid JSON in SETTINGS_JSON"
    rm -f $TEMP_SETTINGS
    exit 1
fi

# ===========================================
# STEP 4: Deploy to Galaxy
# ===========================================
meteor deploy $APP_NAME --settings $TEMP_SETTINGS

# ===========================================
# STEP 5: Clean up
# ===========================================
# Removes the temporary file so secrets don't stay on disk
rm -f $TEMP_SETTINGS

echo "Done!"

Make it executable and deploy:

chmod +x deploy.sh
./deploy.sh

The script fetches your secrets, validates they're proper JSON, deploys to Galaxy, then cleans up the temporary file. Simple and secure.


Multiple Environments

Configure different secrets in Infisical for each environment (dev, staging, prod). Deploy to different environments by changing the parameters:

# Deploy to staging
ENVIRONMENT=staging APP_NAME=staging.myapp.com ./deploy.sh

# Deploy to production
ENVIRONMENT=prod APP_NAME=myapp.com ./deploy.sh

Same script, different secrets, different targets. Clean and consistent.


CI/CD with GitHub Actions

Want automated deployments? Here's a GitHub Actions workflow that fetches secrets from Infisical and deploys to Galaxy on every push to main.

Create .github/workflows/deploy.yml:

name: Deploy to Galaxy

on:
  push:
    branches:
      - main
  workflow_dispatch:

env:
  APP_NAME: my-app.meteorapp.com
  INFISICAL_ENV: prod

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install Meteor
        run: curl https://install.meteor.com/ | sh

      - name: Install Infisical CLI
        run: |
          curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | sudo -E bash
          sudo apt-get update && sudo apt-get install -y infisical

      - name: Login to Infisical
        run: |
          infisical login --method=universal-auth \
            --client-id=${{ secrets.INFISICAL_CLIENT_ID }} \
            --client-secret=${{ secrets.INFISICAL_CLIENT_SECRET }}

      - name: Fetch secrets from Infisical
        run: |
          infisical secrets get SETTINGS_JSON \
            --env=${{ env.INFISICAL_ENV }} \
            --projectId=${{ secrets.INFISICAL_PROJECT_ID }} \
            --plain > settings.json

      - name: Validate settings.json
        run: python3 -c "import json; json.load(open('settings.json'))"

      - name: Setup Meteor credentials
        run: |
          mkdir -p ~/.meteor
          echo '${{ secrets.METEOR_TOKEN }}' > ~/.meteor/meteor_token.json

      - name: Deploy to Galaxy
        run: meteor deploy ${{ env.APP_NAME }} --settings settings.json

      - name: Clean up
        if: always()
        run: rm -f settings.json

Required GitHub Secrets

Add these secrets in your repository settings (Settings > Secrets and variables > Actions):

SecretDescription
INFISICAL_CLIENT_IDMachine Identity client ID from Infisical
INFISICAL_CLIENT_SECRETMachine Identity client secret from Infisical
INFISICAL_PROJECT_IDYour Infisical project ID
METEOR_TOKENContents of ~/.meteor/meteor_token.json

Creating a Machine Identity in Infisical

Go to Machine Identities

In the Infisical dashboard, go to Project Settings > Machine Identities.

Create Identity

Create a new identity and add it to your project with access to the appropriate environment.

Get Credentials

Copy the Client ID and Client Secret and add them as GitHub secrets.


Local Development

For local development, create a dev.sh script that fetches secrets and runs your app:

#!/bin/bash
set -e

# Fetch development secrets
infisical secrets get SETTINGS_JSON --env=dev --plain > .settings-local.json

# Run Meteor
meteor run --settings .settings-local.json

# Clean up when Meteor exits
rm -f .settings-local.json

Don't forget to add .settings-local.json to your .gitignore.

Alternative Approach

Some developers prefer to keep a local settings-dev.json file that's gitignored. That works too, just make sure it never gets committed. The Infisical approach is more secure since secrets never touch disk except temporarily.


Security Best Practices


Common Questions


What's Next?

Your secrets are now secure. Deploy with confidence knowing your credentials won't accidentally end up in the wrong hands.