Articles on: Meteor Apps

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.


Coming soon: Galaxy will support METEOR_SETTINGS as an environment variable in the dashboard. This will simplify secrets management for Push to Deploy users.


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


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 Setup

  1. Create an account at app.infisical.com
  2. Create a new project for your app
  3. Install the CLI (see installation docs)
  4. Authenticate and initialize your project:
infisical login
cd ~/projects/my-meteor-app
infisical init
  1. Add your secrets in the Infisical dashboard. Store the entire settings object as a single SETTINGS_JSON variable.


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

  1. In the Infisical dashboard, go to Project Settings > Machine Identities
  2. Create a new identity
  3. Add it to your project with access to the appropriate environment
  4. Copy the Client ID and Client Secret


Local Development

For local development, create a dev.sh script:

#!/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.


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