Server Topology
The production stack runs across two servers connected via a Tailscale overlay network. An external Nginx Proxy Manager instance handles TLS termination and reverse proxying for all public-facing services.| Server | Tailscale IP | Role | What runs here |
|---|---|---|---|
| Chat (Server A) | ATL_CHAT_IP (e.g. 100.64.7.0) | Primary | All Docker services: UnrealIRCd, Atheme, Prosody, Bridge, The Lounge, WebPanel, cert-manager |
| Gateway (Server B) | ATL_GATEWAY_IP (e.g. 100.64.1.0) | Reverse proxy | Nginx Proxy Manager (TLS termination — not part of this compose stack) |
atl-chat bridge network. IRC ports bind to ATL_CHAT_IP so they are only reachable via Tailscale. Atheme shares the UnrealIRCd container’s network namespace (network_mode: service:atl-irc-server) so it communicates with UnrealIRCd over 127.0.0.1. The Nginx Proxy Manager on Server B reverse-proxies public traffic over Tailscale to Server A’s services. ATL_GATEWAY_IP is passed to UnrealIRCd so it can identify the gateway’s Tailscale IP in its configuration.
Tailscale Setup
Tailscale provides encrypted mesh networking between servers. This means internal services are never exposed on public IPs — only the Tailscale interface carries inter-server traffic.Installing Tailscale on a New Server
-
Install Tailscale:
-
Authenticate and bring the node up:
-
Note the assigned Tailscale IP:
-
Update
.envon the deployment host with the Tailscale IPs:
Firewall Rules
On each server, only the Tailscale UDP port needs to be open between hosts. Public-facing ports are handled by Nginx Proxy Manager on the gateway.Docker Compose Production Configuration
Production usesjust prod, which runs scripts/init.sh prod and then starts
Docker Compose with .env + .env.prod. Development uses just dev, which
runs scripts/init.sh dev and starts Compose with .env + .env.dev.
The root compose.yaml includes all service fragments from infra/compose/:
| Fragment | Services |
|---|---|
infra/compose/networks.yaml | atl-chat bridge network |
infra/compose/irc.yaml | atl-irc-server (UnrealIRCd), atl-irc-services (Atheme), atl-irc-webpanel |
infra/compose/xmpp.yaml | atl-xmpp-server (Prosody), atl-xmpp-nginx (HTTPS proxy) |
infra/compose/bridge.yaml | atl-bridge (Discord↔IRC↔XMPP) |
infra/compose/thelounge.yaml | atl-thelounge (web IRC client) |
infra/compose/obsidianirc.yaml | atl-obsidianirc (modern web IRC client) |
infra/compose/cert-manager.yaml | cert-manager (Lego / Let’s Encrypt) |
Key Differences: Production vs Development
| Aspect | Production (just prod) | Development (just dev) |
|---|---|---|
| Env files loaded | .env + .env.prod | .env + .env.dev |
| Port binding IP | ATL_CHAT_IP (Tailscale IP) | 127.0.0.1 |
| Domains | irc.atl.chat, atl.chat | irc.localhost, xmpp.localhost |
| TLS certificates | Let’s Encrypt (cert-manager) | Self-signed (generated by init.sh) |
| TLS verification | Enforced | Disabled (BRIDGE_IRC_TLS_VERIFY=false) |
| Prosody encryption | Required (PROSODY_S2S_SECURE_AUTH=true) | Relaxed for self-signed certs |
| Dozzle log viewer | Not started (no --profile dev) | Started on port 8082 |
Pre-Deployment Checklist
Complete these checks before deploying to production:-
Environment file configured —
.envexists with production values: -
Secrets rotated — all default passwords have been changed:
See Security — Secret Management for generation commands.
-
Tailscale connected — both servers are on the Tailscale network:
-
DNS records configured — public DNS points to the gateway’s public IP:
See Architecture — Networking for the full DNS zone layout.
-
TLS certificates ready — Let’s Encrypt certificates exist in
data/certs/:If certificates are not yet provisioned, cert-manager will attempt to obtain them on first start. EnsureCLOUDFLARE_DNS_API_TOKENis set in.envfor DNS-01 challenges. -
Docker available — Docker daemon is running and compose plugin is installed:
Deployment Commands
First-Time Deployment
For a brand-new server, run the full initialization and startup sequence:-
Clone the repository:
-
Create and configure the environment file:
Edit
.envwith production values — set real domains, rotate all secrets (anything containingchange_me), and configure Tailscale IPs. See Environment Variables for the full reference. -
Run the production startup command:
This command does two things:
- Runs
scripts/init.sh prod— createsdata/directories, sets permissions, sets up the CA bundle, generates config files from templates viaenvsubst, and runsscripts/prepare-config.sh - Starts all Docker Compose services with production overlay:
docker compose -f compose.yaml -f compose.prod-override.yaml --env-file .env --env-file .env.prod up -d
- Runs
-
Verify all containers are running:
Updating an Existing Deployment
To deploy updates (new code, config changes, or image rebuilds):-
Pull the latest code:
-
Rebuild images if Dockerfiles or application code changed:
-
Re-run the production startup to regenerate configs and restart services:
This is safe to run repeatedly —
init.shis idempotent (it skips directories and certs that already exist).
Restarting Individual Services
To restart a single service without affecting others:Post-Deployment Verification
After deploying, verify each service is healthy:1. Check Container Status
2. Verify UnrealIRCd
3. Verify Atheme
4. Verify Prosody
5. Verify The Lounge
6. Verify the Bridge
7. Verify WebPanel
8. Verify cert-manager
Rollback Procedure
If a deployment causes issues, roll back to the previous working state:Quick Rollback (Code Revert)
-
Stop the current stack:
-
Revert to the previous commit:
-
Rebuild and restart:
- Verify services are healthy using the post-deployment checks above.
Data Rollback
If the issue involves corrupted data rather than code, restore from backups:-
Stop the affected service:
-
Restore the data directory from your most recent backup:
-
Restart the service:
Configuration Rollback
If a configuration change (.env or template) caused the issue:
-
Restore the previous
.env: -
Regenerate configs and restart:
Tip: Always back up your.envfile before making changes:cp .env .env.backup
Ongoing Maintenance
Viewing Logs
Stopping the Production Stack
Cleaning Up Docker Resources
Related Pages
- SSL/TLS — certificate management and renewal
- Monitoring — health checks and alerting
- Backups — backup and restore procedures
- Troubleshooting — cross-service diagnostic commands and common issues
- Security — secret management and network isolation
- Environment Variables — complete variable reference
- Architecture — system design and networking