Secrets Management: How to Secure Your settings.json and Deploy Meteor Safely
Storing secrets in your repository is a security risk. If your repository is accidentally made public, forked, or your Docker image is pushed to a public registry, your credentials will be exposed.
This guide covers best practices for managing secrets when deploying Meteor applications to Galaxy.
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 is committed to your repository, it creates several risks:
- Repository made public by mistake: A misconfiguration can expose your secrets
- Public forks: Forking to a public repository exposes the entire commit history
- Git history: Deleted files remain in Git history and can be recovered
- Docker images: Files copied during build are baked into image layers
Recommended Setup
1. Update .gitignore
Add these entries to ensure secrets files are never committed:
# Secret files
settings.json
settings-*.json
.settings-*.json
# Environment directories with secrets
env/
2. 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.
3. Remove secrets from Git history
If you have previously committed secrets, removing them from current files is not enough. Use tools like BFG Repo-Cleaner to scrub them from history. Rotate any credentials that were ever committed.Using a Secrets Manager
A secrets manager stores your credentials securely and allows you to inject them at deploy time. Popular options include:
- Infisical (open source)
- Doppler
- HashiCorp Vault
- AWS Secrets Manager
Infisical Setup
- Create an account at app.infisical.com
- Create a new project for your app
- Install the CLI (see installation docs)
- Authenticate and initialize your project:
infisical login
cd ~/projects/my-meteor-app
infisical init
- Add your secrets in the Infisical dashboard. Store the entire settings object as a single
SETTINGS_JSONvariable.
Deploy Script
Create a deploy.sh script that fetches secrets and deploys to Galaxy:
#!/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
# ===========================================
# Tries to fetch secrets from Infisical
# If it fails, the user is not logged in or the project is not initialized
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 and saves to the temp file
infisical secrets get SETTINGS_JSON --env=$ENVIRONMENT --plain > $TEMP_SETTINGS
# ===========================================
# STEP 3: Validate JSON
# ===========================================
# Uses Python to check if the file contains valid 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
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
CI/CD with GitHub Actions
For automated deployments, 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):
Secret | Description |
|---|---|
INFISICAL_CLIENT_ID | Machine Identity client ID from Infisical |
INFISICAL_CLIENT_SECRET | Machine Identity client secret from Infisical |
INFISICAL_PROJECT_ID | Your Infisical project ID |
METEOR_TOKEN | Contents of ~/.meteor/meteor_token.json after running meteor login |
Creating a Machine Identity in Infisical
- In the Infisical dashboard, go to Project Settings > Machine Identities
- Create a new identity
- Add it to your project with access to the appropriate environment
- Copy the Client ID and Client Secret
Local Development
For local development, create a dev.sh script:
#!/bin/bashDon't forget to add
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
.settings-local.json to your .gitignore.Security Best Practices
- Rotate secrets regularly: Set a reminder to rotate credentials every 90-180 days
- Use least privilege access: Not everyone needs access to production secrets
- Audit access logs: Periodically check who is accessing your secrets
- Don't trust private repositories completely: They can become public by accident
Updated on: 03/01/2026