[object Object]

← back to Greenland Onboard

greenland-internal: capture go-live deploy notes (express/pg npm install, IP-specific nginx listen, gray-cloud LE TLS)

a1b0e3b6fdff0f921842da597e8631ce4125d4e7 · 2026-07-26 20:02:57 -0700 · Steve Abrams

Files touched

Diff

commit a1b0e3b6fdff0f921842da597e8631ce4125d4e7
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 26 20:02:57 2026 -0700

    greenland-internal: capture go-live deploy notes (express/pg npm install, IP-specific nginx listen, gray-cloud LE TLS)
---
 DEPLOY-NOTES.md | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/DEPLOY-NOTES.md b/DEPLOY-NOTES.md
new file mode 100644
index 0000000..32ea914
--- /dev/null
+++ b/DEPLOY-NOTES.md
@@ -0,0 +1,33 @@
+# 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
+```

← 33f8806 greenland-onboard: add Memo/Stock/Price chip actions via sha  ·  back to Greenland Onboard  ·  gitignore locally-served product images after history purge d3f4af8 →