diff --git a/.gitea/workflows/deploy-site.yml b/.gitea/workflows/deploy-site.yml index bf59ca3..d5717e7 100644 --- a/.gitea/workflows/deploy-site.yml +++ b/.gitea/workflows/deploy-site.yml @@ -10,9 +10,6 @@ name: Deploy test site # VPS_PORT optional, default 22 # VPS_KNOWN_HOSTS optional pinned host key line(s); # without it the key is scanned per run -# CLOUDFLARE_ZONE_ID, CLOUDFLARE_API_TOKEN -# optional; cache purge for cnxvinyl.lol -# (token needs Zone > Cache Purge) on: push: @@ -111,25 +108,8 @@ jobs: echo "live on server: $live" [ "$live" = "$(cat site/dist/version.txt)" ] || { echo "::error::server holds $live, expected $(cat site/dist/version.txt)"; exit 1; } - - name: Purge Cloudflare cache - env: - CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - run: | - if [ -z "$CLOUDFLARE_ZONE_ID" ] || [ -z "$CLOUDFLARE_API_TOKEN" ]; then - echo "::warning::CLOUDFLARE_ZONE_ID / CLOUDFLARE_API_TOKEN not set; skipping cache purge" - exit 0 - fi - response=$(curl -sS -X POST \ - "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \ - -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ - -H "Content-Type: application/json" \ - --data '{"purge_everything":true}') - echo "$response" - echo "$response" | grep -q '"success":\s*true' || { echo "::error::Cloudflare cache purge failed"; exit 1; } - - name: Check the public URL - # Warning only: DNS, Cloudflare or a basic_auth login can make this + # Warning only: DNS or a basic_auth login can make this # fail while the files on the server are already correct. run: | expected=$(cat site/dist/version.txt) diff --git a/docs/digital-factory.md b/docs/digital-factory.md index 9d43a86..36a3442 100644 --- a/docs/digital-factory.md +++ b/docs/digital-factory.md @@ -1003,7 +1003,8 @@ Build onward, part-time at launch; add it to the headcount. - Customer portal domain: the plant's brand domain (new zone on ns1/ns2, second cert on `web01`) or a name under `cnx.network` for launch. Internal testing has its own domain, `cnxvinyl.lol` (registered - 2026-10-02, DNS on Cloudflare): a static demo site built from + 2026-10-02 at Porkbun; DNS moved from Cloudflare to the fleet nameservers + ns1/ns2 in October 2026, mail on `mx1`): a static demo site built from [`site/`](../site/README.md) and served by the buildfor.life web server, not a plant service. The brand domain decision stays open. - Portal availability during a plant WAN outage: accept it (the portal is diff --git a/site/Caddyfile b/site/Caddyfile index a36d637..3f3ca2a 100644 --- a/site/Caddyfile +++ b/site/Caddyfile @@ -2,22 +2,17 @@ # Static web root /var/www/cnxvinyl.lol, filled by # .gitea/workflows/deploy-site.yml in the cnx_vinyl repo. # -# Append these blocks to /etc/caddy/Caddyfile on s1. They reuse the -# cloudflare_only and security_headers snippets defined there for -# buildfor.life (buildfor_life_web: infra/caddy/Caddyfile.example); if -# they are missing, validate fails with "File to import not found: -# cloudflare_only" and they have to be copied in from the example first. +# Append these blocks to /etc/caddy/Caddyfile on s1, then # caddy validate --config /etc/caddy/Caddyfile # systemctl reload caddy +# This file mirrors what s1 runs (checked 2026-10-23); keep the two in step. # -# Cloudflare: both names proxied (orange cloud), SSL/TLS mode "Full (strict)". -# "Flexible" sends plain HTTP to Caddy, which redirects to HTTPS: a loop. -# Same rule as the buildfor.life apex: if a record is ever switched to DNS -# only, remove "import cloudflare_only" first or that name goes dark. +# DNS: the cnxvinyl.lol zone lives in the cnx-network-clan repo +# (modules/dns/zones/cnxvinyl.lol.zone, served by ns1/ns2.cnx.network) and +# points straight at s1, not through Cloudflare. Caddy gets its own +# certificates (HTTP-01/TLS-ALPN on 80/443), so no Cloudflare-only rule. cnxvinyl.lol { - import cloudflare_only - import security_headers header X-Frame-Options "SAMEORIGIN" # Internal testing: keep every page and file out of search engines. header X-Robots-Tag "noindex, nofollow" @@ -35,6 +30,5 @@ cnxvinyl.lol { } www.cnxvinyl.lol { - import cloudflare_only redir https://cnxvinyl.lol{uri} permanent } diff --git a/site/README.md b/site/README.md index a99521f..cc2bd6a 100644 --- a/site/README.md +++ b/site/README.md @@ -3,7 +3,7 @@ `https://cnxvinyl.lol/` is the internal test site for this repository: demo pages from `docs/` (the [plant operation page](../docs/plant-operation.html) first) and any static site we want to show by link. It runs on the same web -server as buildfor.life (Debian VPS `s1`, Caddy behind Cloudflare) and is +server as buildfor.life (Debian VPS `s1`, Caddy; not behind Cloudflare) and is not a plant service; plant systems follow the [digital factory plan](../docs/digital-factory.md). Every page and file is sent with `noindex` and `robots.txt` disallows everything; nothing is behind @@ -30,8 +30,7 @@ touches `site/`, an HTML page under `docs/`, or the workflow itself, and on demand (Actions tab, "Run workflow"). It builds, rsyncs `site/dist` into the idle one of `/var/www/cnxvinyl.lol` and `/var/www/cnxvinyl.lol-prev`, swaps them by rename (the blog's pattern), checks `version.txt` on the -server, purges the Cloudflare cache when the token is set, and finally -checks the public URL (warning only). +server, and finally checks the public URL (warning only). The deploy owns the whole web root: anything put into `/var/www/cnxvinyl.lol` by hand disappears on the next deploy. Static sites @@ -39,15 +38,14 @@ go into `public/` instead. ## One-time setup -1. DNS in Cloudflare, both proxied (orange cloud): - `cnxvinyl.lol CNAME s1.buildfor.life` and `www CNAME cnxvinyl.lol` - (Cloudflare flattens the apex CNAME, so the site follows s1 if its - address changes). SSL/TLS mode **Full (strict)**: "Flexible" makes a - redirect loop with Caddy. +1. DNS: the zone is in the cnx-network-clan repo + (`modules/dns/zones/cnxvinyl.lol.zone`, served by `ns1`/`ns2.cnx.network`, + October 2026; until then it was Cloudflare): apex A/AAAA straight at s1 + and `www CNAME cnxvinyl.lol`. If s1's address changes, change it there. 2. Caddy on s1: append [`Caddyfile`](Caddyfile) to `/etc/caddy/Caddyfile` (the comments in it list the checks), `caddy validate`, then - `systemctl reload caddy`. Caddy gets the certificate the same way it - does for the buildfor.life apex. + `systemctl reload caddy`. Caddy gets its own certificates over + HTTP-01/TLS-ALPN (ports 80 and 443 are open on s1). 3. Web root: the deploy user must be able to create and rename directories in `/var/www`, as it already does for the blog. If not: `sudo install -d -o /var/www/cnxvinyl.lol /var/www/cnxvinyl.lol-prev` @@ -56,9 +54,8 @@ go into `public/` instead. 4. Secrets in Gitea (repo: Settings > Actions > Secrets, or user level so every repo of the account gets them): `VPS_HOST`, `VPS_USER`, `VPS_SSH_KEY`, optionally `VPS_PORT` (default 22), `VPS_KNOWN_HOSTS` - (output of `ssh-keyscan -p s1.buildfor.life`, pins the host key), - `CLOUDFLARE_ZONE_ID` and `CLOUDFLARE_API_TOKEN` (Zone > Cache Purge on - cnxvinyl.lol). The names match the blog's workflow, so the blog's + (output of `ssh-keyscan -p s1.buildfor.life`, pins the host key). + The names match the blog's workflow, so the blog's deploy key and values work unchanged: s1 only checks the key against the deploy user's `authorized_keys`, whichever repository sends it. Gitea secrets cannot be read back, so they are entered again here from