Production deployment

Put Netstamp behind HTTPS, configure public origins and trusted proxies, harden secrets, and verify a production installation.

A production Netstamp instance should have one stable HTTPS origin, a private database, persistent secrets, tested backups, and an explicit upgrade process.

Required settings

Set these values in .env before exposing the service:

dotenv
APP_ENV=production
BACKEND_BASE_URL=https://netstamp.example.com
PUBLIC_WEB_BASE_URL=https://netstamp.example.com
NETSTAMP_VERSION=<tested tag or digest>
DATABASE_PASSWORD=<unique random value>
LOG_PSEUDONYM_KEY=<unique random value>
SYSTEM_SETTINGS_ENCRYPTION_KEY=<unique random value>
AUTH_SESSION_HASH_KEY=<unique random value>
AUTH_API_TOKEN_HASH_KEY=<unique random value>

BACKEND_BASE_URL is used for OAuth/OIDC callback URLs, email links, and controller-served probe installer URLs. PUBLIC_WEB_BASE_URL is used for browser-facing links. Both values must be origins only: scheme and host, with no path, query, or fragment.

With APP_ENV=production, session cookies use the __Host- prefix, Secure, HttpOnly, SameSite=Strict, and Path=/. Users must access the site over HTTPS.

Reverse proxy requirements

Terminate TLS in a reverse proxy and forward the complete origin to the container. Preserve these headers:

  • Host
  • X-Forwarded-Proto
  • X-Forwarded-For
  • X-Real-IP when your proxy provides it
  • Authorization

Example Nginx server block:

nginx
server {
listen 443 ssl http2;
server_name netstamp.example.com;

ssl_certificate /etc/letsencrypt/live/netstamp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/netstamp.example.com/privkey.pem;

location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Authorization $http_authorization;
}
}

Bind the Compose port to loopback when the reverse proxy runs on the same host:

yaml
services:
netstamp:
ports:
- "127.0.0.1:3000:8080"

If Netstamp must trust client addresses from the proxy, set HTTP_TRUSTED_PROXIES to the proxy’s exact address or CIDR prefixes, separated by commas. Do not trust all addresses unless the container port is otherwise unreachable.

Firewall and network direction

The controller needs:

  • inbound HTTPS from browsers, API clients, and probe agents;
  • outbound access to configured OAuth/OIDC providers and notification endpoints;
  • outbound SMTP when email is enabled;
  • database access to PostgreSQL.

Probe agents initiate outbound HTTP(S) connections to the controller. The controller does not need inbound access to probe hosts.

Account bootstrap

The first successfully registered account is granted system administrator access. Create that account before opening registration broadly, then use Admin → System settings to:

  1. verify backend and public web origins;
  2. configure SMTP if needed;
  3. decide whether registration remains enabled;
  4. decide whether new accounts must verify email;
  5. add at least one additional system administrator for recovery.

System administrators do not automatically gain access to projects. Project owners must invite them when project access is required.

Production checklist

  • APP_ENV=production is set.
  • Every placeholder and development secret was replaced independently.
  • The Netstamp and TimescaleDB image versions are pinned and recorded.
  • The database port is not exposed publicly.
  • HTTPS is valid and HTTP redirects to HTTPS.
  • BACKEND_BASE_URL and PUBLIC_WEB_BASE_URL match the public origin.
  • Trusted proxy ranges are no broader than necessary.
  • Registration and email-verification policy are intentional.
  • SMTP and every alert notification are tested.
  • /healthz and /api/v1/healthz are monitored.
  • A database backup was created and restored in a test environment.
  • Probe hosts can reach the public controller origin.
  • Secrets and .env are excluded from backups that leave your control, or encrypted before storage.

Verification

bash
curl --fail https://netstamp.example.com/healthz
curl --fail https://netstamp.example.com/api/v1/healthz
curl --fail https://netstamp.example.com/api/v1/openapi.json >/dev/null
curl --fail https://netstamp.example.com/api/v1/install/agent.sh >/dev/null

Create a disposable probe, confirm its heartbeat, run one check, test one notification, and load a public status page before declaring the deployment ready.