Operations

Environments & Deployment

Where each component runs, how it ships, and the domains that front it.

Hosting at a glance

ComponentHostingDeploy mechanism
Public website (web2)Linode (Apache/PHP), CloudFlare in frontDocker image build (GitHub Actions) + legacy git-deploy.php webhook
REST APILinode, PM2 cluster behind a load balancerPM2 deploy (ecosystem.config.js): git pullnpm installpm2 startOrRestart
API workerapi-3 (Linode), managed via CoolifyCoolify builds/runs Dockerfile.worker; control plane on the coolify host
Admin panelHeroku (not Linode)Branch-based CI/CD: develop / staging / master apps; Heroku review apps per PR
MongoDBLinode — 3-node replica set (mongo-1/2/3)Managed directly on the DB servers

Domains

Public site (prod)
*.macaronikid.com — e.g. national.macaronikid.com
API (prod)
api.macaronikid.com
Admin (prod)
admin.macaronikid.com
Status page
status.macaronikid.com
Dev
*.macaronikidlab.com, api.macaronikidlab.com
Internal (API nodes)
api1/api2/api3.internal.macaronikid.com, api-develop.internal.…

Server inventory

Confirmed from the Linode account (June 10, 2026). All instances are in us-east. Two NodeBalancers front production: one across the API nodes, one across the web front ends.

Production API — PM2, behind a NodeBalancer

ServerPublic IPv4PlanNotes
api-145.33.85.145g6-standard-4PM2, multiple instances
api-2172.104.21.186g6-standard-4PM2, multiple instances
api-445.33.73.175g6-dedicated-8PM2, multiple instances (largest API node)

API worker / Coolify

ServerPublic IPv4PlanNotes
api-350.116.60.72g6-standard-4Managed by Coolify — does not run PM2 like the others; runs the API worker
coolify50.116.54.22g6-standard-2 (Ubuntu 24.04)Coolify control plane (self-hosted PaaS)
api-dev66.228.41.190g6-standard-4Development API server

MongoDB — 3-node replica set

ServerPublic IPv4PlanNotes
mongo-166.228.44.13g6-standard-8The backed-up node (preferred primary)
mongo-2104.237.144.131g6-standard-16Often acts as primary; largest RAM (64 GB); historically hottest
mongo-366.228.36.184g6-standard-8Replica member
mongo-dev173.255.231.89g6-standard-4Available for development; not wired into anything. Refreshed by spinning up a new instance from a backup (no streamlined prod→dev sync)

Front end (web2) — behind a NodeBalancer

ServerPublic IPv4PlanNotes
web-front-166.228.38.183g6-standard-6Production front end
web-front-245.33.94.22g6-standard-6Production front end
web-front-develop97.107.141.152g6-standard-4Front end used only for newsletter generation, e.g. national.www3.macaronikid.com/dynamic-newsletter/[id]/[townslug]
web-front-preview69.164.210.83g6-standard-4/var/www/html = Yodel-calendar preview for publishers who haven't enabled it (e.g. erie.preview.macaronikid.com/events); /var/www/dev = active development on the develop branch

Being retired (offline as of June 10, 2026)

ServerPublic IPv4Notes
analytics45.79.159.187The Matomo box — offline; being deleted (see Analytics Decommission)
api-script104.237.147.163One-off script server — offline; being retired
Stale deploy config
The API repo's ecosystem.config.js defines a single deploy host (198.74.62.36) that does not match any current Linode. Production API deploys actually target api-1, api-2, and api-4 (PM2 behind a NodeBalancer); api-3 is Coolify-managed. Treat the committed ecosystem.config.js host as outdated.

Edge & delivery

The CDN/proxy setup is split by domain type:

DomainsFronted byWhy
Production town subdomains — national.macaronikid.com, erie.macaronikid.com, etc.CloudFlare (proxied)Each town is defined manually in CloudFlare to use its proxy
*.dev.…, *.preview.…, *.www3.…AWS CloudFrontWildcard coverage — avoids defining every subdomain by hand
Load balancing
Linode NodeBalancers — one across the API nodes (api-1/2/4), one across the web front ends (web-front-1/2)

Local development

The macaroni-kid-2.docker-compose repo wires the stack together for local work. docker-compose.yml builds the API (port 3000:8080), admin (3003), web (3001:80), and a local mongo:3.4 with a db-init seed step. docker-compose.prod.yml is a production-style reference (note: it still points at the older macaroni-kid-2.web rather than web2, and maps the API on port 3000 instead of 8080).

CI workflows

RepoWorkflowPurpose
web2.github/workflows/docker.ymlBuild the Docker image
admin-panel.github/workflows/docker.ymlBuild the Docker image
apiclaude.yml, claude-code-review.ymlAutomated code review (no deploy step in CI; deploy via PM2)