Container Environment
Understand how Galaxy runs your app. Learn about the PORT variable, graceful shutdowns, environment variables, and network configuration.
Galaxy runs your app inside Docker containers on 64-bit Linux machines in the UTC timezone. Most apps deploy without special configuration, but understanding this environment helps you build apps that scale gracefully.
Works Out of the Box
Most apps run fine without any special setup. This guide explains what's happening under the hood when you need to dig deeper.
The PORT Variable
Here's the most important thing: Galaxy tells your app which port to listen on via the PORT environment variable. Your app must read this variable. Don't hardcode port 3000, 5000, or any number. Galaxy assigns ports dynamically.
// Node.js / Meteor
const port = process.env.PORT || 3000;
app.listen(port);# Python
import os
port = int(os.getenv('PORT', 5000))
app.run(port=port)If your app doesn't listen on the correct port, Galaxy can't route traffic to it. Health checks fail, and your container gets marked unhealthy.
Don't Hardcode Ports
This is the number one deployment issue. Always read the PORT environment variable, Galaxy assigns ports dynamically and your app must respect that.
ROOT_URL
Galaxy sets the ROOT_URL environment variable to your app's default hostname. For Meteor apps, this powers Meteor.absoluteUrl() to generate correct links.
The value includes the protocol (http:// or https://) based on your Force HTTPS setting. Using a custom domain with SSL? Make sure Force HTTPS is on so your generated URLs use https://.
You can override ROOT_URL in your environment variables if needed (for example, when using a custom domain different from your default Galaxy hostname).
Graceful Shutdown
When Galaxy needs to stop your container (new deployment, scaling down, infrastructure maintenance), it doesn't just kill your app. You get time to clean up.
Here's the sequence:
- Galaxy sends
SIGTERMto your container - Your app has 30 seconds to finish what it's doing (the grace period)
- After 30 seconds, Galaxy sends
SIGKILLand the container dies
The grace period is your chance to close database connections, finish processing requests, and notify connected clients.
Handling SIGTERM
Catch the signal in your app to do cleanup:
process.on('SIGTERM', () => {
console.log('Received SIGTERM, shutting down gracefully...');
// Close server to stop accepting new connections
server.close(() => {
console.log('Server closed');
process.exit(0);
});
// Force exit after grace period if cleanup takes too long
setTimeout(() => {
console.log('Forcing exit');
process.exit(1);
}, 25000); // Leave some buffer before SIGKILL
});Gradual Client Transitions for Meteor
Running a Meteor app with many connected users? You want to migrate them gracefully to new containers during deploys. The @meteorjs/ddp-graceful-shutdown package handles this automatically:
meteor npm install @meteorjs/ddp-graceful-shutdownimport { DDPGracefulShutdown } from '@meteorjs/ddp-graceful-shutdown';
Meteor.startup(() => {
DDPGracefulShutdown.configure({
// Gradually close connections over the grace period
});
});This spreads client reconnections over time instead of forcing everyone to reconnect at once.
Adjusting the Grace Period
The default 30-second grace period works for most apps. If your app needs more time (heavy background processing, long-running requests), adjust it in your app's Settings page in the Galaxy dashboard.
Galaxy tells your app the grace period via the METEOR_SIGTERM_GRACE_PERIOD_SECONDS environment variable.
Plan for Shutdown
Design your app to handle shutdown gracefully. Don't start long-running tasks that can't be interrupted, or use job queues that persist work across restarts.
Environment Variables
Galaxy automatically sets several environment variables. Some you'll use directly, others work behind the scenes.
Variables You'll Use
| Variable | Example | Purpose |
|---|---|---|
PORT | 3000 | Port your app must listen on |
ROOT_URL | https://myapp.meteorapp.com | Your app's base URL for generating links |
METEOR_SETTINGS | {"public": {...}} | Your settings.json contents as Meteor.settings |
METEOR_SIGTERM_GRACE_PERIOD_SECONDS | 30 | How long your app has to shut down gracefully |
Variables Galaxy Manages
| Variable | Example | Purpose |
|---|---|---|
GALAXY_APP_ID | Ss8o4Y6KrvFBKKkqM | Internal identifier for your app |
GALAXY_APP_VERSION_ID | 123 | The container's app version number |
GALAXY_CONTAINER_ID | Ss8o4Y6KrvFBKKkqM-3n28 | Unique identifier for this container |
HTTP_FORWARDED_COUNT | 1 | Tells your app it's running behind Galaxy's proxy |
APM_* | Various | Configuration for Monti APM (Professional plan) |
What You Can Override
Add your own environment variables or override most Galaxy-set variables through your settings.json or the Galaxy dashboard.
Cannot override: GALAXY_CONTAINER_ID, KADIRA_OPTIONS_HOSTNAME, and GALAXY_LOGGER (these are container-specific).
Memory Management
Modern Node.js (v12+) is container-aware. It automatically detects your container's memory limits and sets the heap to about 50% of the container size, up to a maximum of 2GB. For most apps, this works without any configuration.
If you're experiencing out-of-memory crashes, traffic spikes overwhelming your containers, or need more than the 2GB default heap cap, you can tune memory allocation manually using GALAXY_NODE_OPTIONS (for Meteor apps) or NODE_OPTIONS (for Web Apps).
For detailed recommendations on heap size settings for each container type, see the Memory Management guide.
Network Environment
Incoming Connections
Galaxy runs your containers in a firewalled network. Only one port is exposed: the one Galaxy assigns via $PORT.
Galaxy handles the routing: HTTP connections (port 80) route to your container, HTTPS connections (port 443) route to your container if you've configured SSL. You cannot serve connections on any other ports.
All external traffic comes through Galaxy's load balancer, so your app sees requests coming from the proxy (that's why HTTP_FORWARDED_COUNT is set to 1).
Outgoing Connections and IP Whitelisting
When your app connects to external services (databases, APIs, third-party services), those connections appear to come from fixed IP addresses. These aren't the actual machine IPs, they're Galaxy's outgoing proxy addresses.
This matters for IP whitelisting. Many database providers require you to whitelist the IP addresses that can connect. If you're using MongoDB Atlas, AWS RDS, or similar services, you'll need to whitelist Galaxy's outgoing IPs.
To find your outgoing IPs:
- Go to your app's Settings page in the Galaxy dashboard
- Look for IP addresses listed under outgoing connections
- Add these addresses to your database or service's whitelist
Professional Plan Required
IP whitelisting information is available for Professional plan apps. Upgrade if you need to access these IP addresses.
CIDR notation: If your service wants IP addresses in CIDR format, add /32 to each IP. For example, 203.0.113.42 becomes 203.0.113.42/32.
Shared IP Addresses
Whitelisted IP addresses are shared among all Galaxy Professional customers. Whitelisting adds a security layer but shouldn't be your only protection. Always use strong authentication for databases and services.
IPv6 Support
Galaxy supports IPv6 for apps on the Professional plan. Enable it in your app's Settings page, then configure DNS at your domain registrar.
IPv6 helps future-proof your app as IPv4 addresses become scarcer.
Health Checking
Galaxy monitors your app's health by making HTTP requests. Understanding this helps you deploy reliably.
How Health Checks Work
Galaxy expects your app to:
- Listen on the port from
$PORT - Respond to
GET /requests - Return valid HTTP within 5 seconds
Health check requests include a User-Agent header containing Galaxybot/.
Galaxy currently just checks that the response is valid HTTP. But returning a 5xx status code is a bad idea, as Galaxy may refine what "healthy" means in the future.
What Happens When Containers Are Unhealthy
If your container fails health checks:
- New containers get 10 minutes to become healthy before replacement
- Previously healthy containers get 5 minutes to recover before replacement
- Unhealthy containers don't receive new client connections
- Galaxy logs unhealthy events and can send notifications
You can disable automatic unhealthy container replacement in your app's Settings page. Useful if your app legitimately runs heavy processes that temporarily block health checks.
Create a Health Endpoint
While Galaxy checks /, consider creating a dedicated /health endpoint that verifies your app's critical dependencies (database connection, external services) and returns meaningful status information.
Load Balancing
Galaxy distributes incoming connections across your healthy containers using a least loaded algorithm (the container with the fewest existing connections gets new requests).
How Load Balancing Works
- New connections go to the least loaded healthy container
- Existing connections stick to their current container (no active rebalancing)
- If a container becomes unhealthy, its users get routed to healthy containers
- High CPU or memory usage doesn't trigger rebalancing (only unhealthy status does)
If one container gets into trouble but stays "healthy" (responds to health checks), its connected users won't automatically move to other containers.
Deploy Behavior
When you deploy a new version:
- Galaxy waits for all new containers to become healthy (at least 10 minutes, longer for many containers)
- If new containers don't become healthy, Galaxy rolls back to the previous version
- Connected users transition gradually if you've configured graceful shutdown
