Galaxy

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:

  1. Galaxy sends SIGTERM to your container
  2. Your app has 30 seconds to finish what it's doing (the grace period)
  3. After 30 seconds, Galaxy sends SIGKILL and 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-shutdown
import { 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

VariableExamplePurpose
PORT3000Port your app must listen on
ROOT_URLhttps://myapp.meteorapp.comYour app's base URL for generating links
METEOR_SETTINGS{"public": {...}}Your settings.json contents as Meteor.settings
METEOR_SIGTERM_GRACE_PERIOD_SECONDS30How long your app has to shut down gracefully

Variables Galaxy Manages

VariableExamplePurpose
GALAXY_APP_IDSs8o4Y6KrvFBKKkqMInternal identifier for your app
GALAXY_APP_VERSION_ID123The container's app version number
GALAXY_CONTAINER_IDSs8o4Y6KrvFBKKkqM-3n28Unique identifier for this container
HTTP_FORWARDED_COUNT1Tells your app it's running behind Galaxy's proxy
APM_*VariousConfiguration 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:

  1. Go to your app's Settings page in the Galaxy dashboard
  2. Look for IP addresses listed under outgoing connections
  3. 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

Common Issues


What's Next?