ci(deploy): make API-domain reconciliation opt-in, document the real host layout
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Deploy Frontend / deploy (push) Has been cancelled

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 releases 14d46ce and
98c39f6 uploaded successfully and were never served.
This commit is contained in:
sdarbinyan
2026-08-22 16:08:13 +04:00
parent d4959bd4da
commit 846004e6d8
2 changed files with 63 additions and 3 deletions

View File

@@ -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