← 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
```