ci(deploy): make API-domain reconciliation opt-in, document the real host layout
The Reconcile tenant API domains step ran on every push to main. On the production host that is actively harmful: api.gorbushka.market already has a hand-written vhost, and configure-api-domain.sh writes its own file per domain - so the step would hand nginx a second server block for a server_name that already has one and re-run certbot against a live API, once per deploy. Shipping frontend files needs none of it. Gate it behind a workflow_dispatch input, off by default, for standing up a NEW base domain. This also shrinks the secrets a normal deploy requires to four (DEPLOY_HOST, DEPLOY_USER, DEPLOY_SSH_KEY, DEPLOY_KNOWN_HOSTS); STOREFRONT_DOMAINS, CERTBOT_EMAIL and BACKEND_UPSTREAM are now read only on the opt-in path. Document the production host as it actually is: provisioned by hand before server-setup.sh existed, per-domain vhosts rooted at /var/www/dexarmarket/browser, which is now a symlink to /srv/marketplaces/current/frontend. Before 2026-08-22 it pointed straight at a pinned release with no `current` in between, so releases14d46ceand98c39f6uploaded successfully and were never served.
This commit is contained in:
@@ -37,6 +37,21 @@ host; tenant subdomains do not create additional API DNS names.
|
||||
|
||||
nginx root is `/srv/marketplaces/current/frontend`. Activation is a symlink swap, so no request is ever served from a half-written directory, and a rollback is a symlink change rather than a rebuild.
|
||||
|
||||
**On the current production host there is one extra hop.** That server predates
|
||||
`server-setup.sh` and was provisioned by hand, so instead of the catch-all vhost
|
||||
it has per-domain configs (`gorbushka.conf`, `dexarmarket.conf`,
|
||||
`gorbushka-admin.conf`, `gorbushka-landing.conf`) whose `root` is
|
||||
`/var/www/dexarmarket/browser`. That path is itself a symlink:
|
||||
|
||||
```
|
||||
/var/www/dexarmarket/browser -> /srv/marketplaces/current/frontend
|
||||
```
|
||||
|
||||
so the release/`current` model above still holds and the workflow needs no
|
||||
per-host special-casing. Until 2026-08-22 `browser` pointed straight at one
|
||||
pinned release directory with no `current` in between, which is why two
|
||||
successfully-uploaded releases sat unserved.
|
||||
|
||||
---
|
||||
|
||||
## 3. First-time setup
|
||||
@@ -82,18 +97,26 @@ The output is the `DEPLOY_KNOWN_HOSTS` secret. Pinning it means a rebuilt or imp
|
||||
|
||||
### 3.4 Add CI secrets
|
||||
|
||||
Required for every deploy:
|
||||
|
||||
| Secret | Value |
|
||||
|---|---|
|
||||
| `DEPLOY_HOST` | server IP or hostname |
|
||||
| `DEPLOY_USER` | `deploy` |
|
||||
| `DEPLOY_SSH_KEY` | contents of the **private** key file |
|
||||
| `DEPLOY_KNOWN_HOSTS` | output of `ssh-keyscan -H <server-ip>` |
|
||||
|
||||
Required **only** when running the workflow with `reconcile_api_domains` on
|
||||
(§4.6) — a normal release deploy never reads these:
|
||||
|
||||
| Secret | Value |
|
||||
|---|---|
|
||||
| `STOREFRONT_DOMAINS` | space-separated full hosts, e.g. `gorbushka.market store1.example.com` |
|
||||
| `CERTBOT_EMAIL` | operations email used for Let's Encrypt |
|
||||
| `BACKEND_UPSTREAM` | optional; defaults to `https://127.0.0.1:445` |
|
||||
|
||||
Before deploying, point each base domain's shared API hostname at the server.
|
||||
For `gorbushka.market` and `store1.gorbushka.market`, only
|
||||
When that step does run, point each base domain's shared API hostname at the
|
||||
server first. For `gorbushka.market` and `store1.gorbushka.market`, only
|
||||
`api.gorbushka.market` is required. The workflow deduplicates
|
||||
`STOREFRONT_DOMAINS` by base domain and deliberately stops before release
|
||||
activation if DNS, certificate issuance, nginx validation, or the JSON
|
||||
@@ -175,7 +198,24 @@ For a single domain, outside the reconciler:
|
||||
sudo bash add-domain.sh shop.example.com --email ops@example.com --with-www
|
||||
```
|
||||
|
||||
### 4.5 Verify
|
||||
### 4.5 API domains in CD are opt-in
|
||||
|
||||
The deploy workflow's **Reconcile tenant API domains** step is gated behind the
|
||||
`reconcile_api_domains` input and is **off for push-triggered deploys**.
|
||||
|
||||
`configure-api-domain.sh` writes `/etc/nginx/sites-available/api.<domain>` and
|
||||
enables it. The API vhosts on the current production host were created by hand
|
||||
under different filenames (`gorbushka-api.conf`), so running the helper there
|
||||
produces a *second* server block for a `server_name` that already has one, and
|
||||
re-runs certbot against a live API — on every deploy. Shipping frontend files
|
||||
needs none of that.
|
||||
|
||||
Turn it on from the workflow-dispatch form only when standing up a **new** base
|
||||
domain. Before the first such run, reconcile the naming: either delete the
|
||||
hand-made vhost and let the helper own the name, or leave the step off and keep
|
||||
managing API domains manually.
|
||||
|
||||
### 4.6 Verify
|
||||
|
||||
```bash
|
||||
curl -I https://shop.example.com/health
|
||||
@@ -197,6 +237,11 @@ sudo systemctl reload nginx
|
||||
|
||||
Only the last 5 releases are retained. Older ones need a rebuild from the tag.
|
||||
|
||||
The production host reaches releases through `/var/www/dexarmarket/browser ->
|
||||
/srv/marketplaces/current/frontend` (§2), so moving `current` is all a rollback
|
||||
needs there too — do not repoint `browser` at a release directly, or the next
|
||||
deploy's swap will silently stop taking effect.
|
||||
|
||||
---
|
||||
|
||||
## 6. Operational checks
|
||||
|
||||
Reference in New Issue
Block a user