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.
Popular Options
Infisical
Open source with excellent developer experience
Doppler
Universal secrets platform with team features
HashiCorp Vault
Enterprise-grade secrets management
AWS Secrets Manager
Native AWS integration
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 initThis 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.shThe 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.shSame 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.jsonRequired 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 |
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.jsonDon'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?
Deploy with CLI
Learn all deployment options via command line
Push to Deploy
Set up automatic deployments from GitHub
Your secrets are now secure. Deploy with confidence knowing your credentials won't accidentally end up in the wrong hands.
