RocketChat/Rocket.Chat · warning

WARNING: Push APN is configured to production mode - but ser

Error message

WARNING: Push APN is configured to production mode - but server is running from localhost

What it means

The push APN init detected a contradiction: options.apn.gateway is the production Apple gateway, but the server's absolute URL is http://localhost*, i.e. a local development server sending through production APN. Production pushes require production credentials and a reachable server; this combo usually means leftover production push config on a dev box.

Source

Thrown at apps/meteor/server/lib/notifications/push/apn.ts:136

	logger.debug('APN configured');

	if (options.apn.gateway) {
		// We check the apn gateway i the options, we could risk shipping
		// server into production while using the production configuration.
		// On the other hand we could be in development but using the production
		// configuration. And finally we could have configured an unknown apn
		// gateway (this could change in the future - but a warning about typos
		// can save hours of debugging)
		//
		// Warn about gateway configurations - it's more a guide

		if (options.apn.gateway === 'gateway.sandbox.push.apple.com') {
			// Using the development sandbox
			logger.warn('WARNING: Push APN is in development mode');
		} else if (options.apn.gateway === 'gateway.push.apple.com') {
			// In production - but warn if we are running on localhost
			if (/http:\/\/localhost/.test(absoluteUrl)) {
				logger.warn('WARNING: Push APN is configured to production mode - but server is running from localhost');
			}
		} else {
			// Warn about gateways we dont know about
			logger.warn({
				msg: 'WARNING: Push APN unknown gateway',
				gateway: options.apn.gateway,
			});
		}
	} else if (options.production) {
		if (/http:\/\/localhost/.test(absoluteUrl)) {
			logger.warn('WARNING: Push APN is configured to production mode - but server is running from localhost');
		}
	} else {
		logger.warn('WARNING: Push APN is in development mode');
	}

	// Check certificate data
	if (!options.apn.cert?.length) {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. For local testing, switch to sandbox credentials and remove the production gateway
  2. If this server really is production-facing, set ROOT_URL to its public HTTPS URL so the check no longer matches localhost
  3. Keep per-environment config files so dev and prod push settings never mix
  4. Confirm the production push certificate/key are actually installed before relying on production sends

Example fix

// before
ROOT_URL='http://localhost:3000'
push: { apn: { gateway: 'gateway.push.apple.com' } }

// after
ROOT_URL='https://chat.example.com'
push: { apn: { gateway: 'gateway.push.apple.com' } }
Defensive patterns

Strategy: validation

Validate before calling

const isLocalhostUrl = (url: string): boolean => /http:\/\/localhost/.test(url);

if (options.apn.gateway === 'gateway.push.apple.com' && isLocalhostUrl(absoluteUrl)) {
  throw new Error('Production APN gateway with localhost ROOT_URL — fix ROOT_URL or use sandbox credentials');
}

Prevention

When it happens

Trigger: options.apn.gateway === 'gateway.push.apple.com' while ROOT_URL is http://localhost:PORT — e.g. testing push locally with the production push configuration copied from a live server.

Common situations: Developers cloning production settings to reproduce a push bug locally; docker-compose dev setups with production env vars; forgetting to switch ROOT_URL/gateway when moving configs between environments.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/3c79c2114d71f1c4. Report an issue: GitHub.