← back to Greenland Onboard
DEPLOY-NOTES.md
34 lines
# Deploy notes — greenland-internal
Live (internal, basic-auth `admin/DW2024!`):
**https://greenland.internal.designerwallcoverings.com** → Kamatera pm2 `greenland-internal` :9973
## Gotchas learned on the 2026-07-26 go-live
1. **Not zero-dependency anymore.** `server.js` `require`s `express` + `pg`
(the vendor-requests sub-app). rsync excludes `node_modules`, so the deploy
MUST run `npm install --omit=dev` on the origin or pm2 crashes with
`Cannot find module 'express'`.
2. **nginx vhost must use the fleet's IP-specific listener.** Use
`listen 45.61.58.125:80;` / `listen 45.61.58.125:443 ssl http2;`, NOT
`listen 80;`. The fleet has IP-specific listeners; a `0.0.0.0:80` block only
ever receives `127.0.0.1` traffic (public conns bind to the more-specific
`45.61.58.125:80` socket), so an exact-name `listen 80` vhost silently loses
to the fleet blocks for public requests.
3. **TLS = Let's Encrypt on origin (DNS-only / gray cloud), not CF-proxied.**
CF free Universal SSL covers only `*.designerwallcoverings.com` (one level),
NOT the two-level `greenland.internal.*`. So the CF A record is **gray**
(proxied=false) and the origin holds the LE cert
(`certbot certonly --webroot -w /var/www/html`, auto-renews). The `:80`
block keeps a `^~ /.well-known/acme-challenge/ { root /var/www/html; }`
location for renewals and 301-redirects everything else to https.
## Verify live
```sh
curl -s https://greenland.internal.designerwallcoverings.com/healthz # {"ok":true,"products":213,...}
curl -s -o /dev/null -w '%{http_code}\n' https://greenland.internal.designerwallcoverings.com/ # 401
curl -s -u admin:DW2024! -o /dev/null -w '%{http_code}\n' https://greenland.internal.designerwallcoverings.com/ # 200
```