Aller au contenu

Cosmos (Corporate Site)

Scope

This page covers Cosmos infrastructure managed from the Aether repo — the nginx vhost, the cosmos-init bootstrap, and the aether-side deployment pattern.

For Cosmos application specifics (content, pages, the lead form), see the Cosmos repo's own README.md.

Architecture

Cosmos is the Groupe Suffren corporate site (groupe-suffren.com) — a separate, static-first Next.js app, deliberately distinct from the Helios practice sites. All page content is local (lib/content.ts); there is no backend/CMS dependency. The one runtime integration is the contact/lead form.

              ┌───────────────────────────────────────┐
              │            nginx (aether)             │
              │  cosmos-staging.groupe-suffren.com  ──┼── cosmos-staging-web:3000
              │  (groupe-suffren.com — prod, later) ──┘
              └───────────────────────────────────────┘
                    ┌──────────────────────────┐
                    │   cosmos-{env}-web       │
                    │   (Next.js standalone)   │
                    └────────────┬─────────────┘
                                 │ POST lead (only when configured)
                    ┌──────────────────────────┐
                    │   LEAD_WEBHOOK_URL       │
                    │   (email relay / Make /  │
                    │    future crm.Prospect)  │
                    └──────────────────────────┘

One Next.js container per environment. Because content is static, the image builds offline (no build args, no API calls at build time).

Managed by Aether

Nginx vhosts

In nginx/conf.d/:

  • cosmos-staging.conf.bootstrap — port-80-only, used once by cosmos-init to serve the ACME challenge before the cert exists
  • cosmos-staging.conf.full + .conf.temp — the HTTPS vhost and its maintenance variant (proxied by deploy.sh's container-swap)

The full vhost proxies to cosmos-staging-web:3000 and is basic-auth gated (shared /etc/nginx/.htpasswd) — staging is private and non-indexable pre-launch. There is an edge rate-limit on /api/lead (the forms zone).

Environment files

Cosmos has no secrets today, so there is no envs/cosmos/*.enc in aether and no SECRET_FILES entry. Its only config is:

Variable Purpose
LEAD_WEBHOOK_URL Where /api/lead POSTs each validated lead (email relay / Make / future crm.Prospect). Unset + NODE_ENV=production → the route returns 503 (fail-loud).
ENVIRONMENT staging/prod — container naming/labels (set by deploy.sh).

When LEAD_WEBHOOK_URL is set it lives in /opt/docker/cosmos/envs/.env.<env> and becomes the first thing to bring under aether's SOPS management (add it to SECRET_FILES and make encrypt).

Bootstrapping a new Cosmos install

For a brand-new deployment (fresh server or first Cosmos deploy on an existing server):

cd /opt/docker/aether/repo && make cosmos-init

This target:

  1. Creates /opt/docker/cosmos/{repo,envs}/ on the server
  2. Activates the port-80 bootstrap vhost and reloads nginx (ACME reachable)
  3. Obtains the SSL cert for cosmos-staging.groupe-suffren.com
  4. Installs the .full/.temp variants, activates the HTTPS vhost, reloads nginx

After cosmos-init:

  1. Clone the Cosmos repo: git clone git@github.com:baudry-suffren/cosmos.git /opt/docker/cosmos/repo
  2. Deploy: cd /opt/docker/cosmos/repo && make deploy ENV=staging
  3. (When the delivery target exists) add LEAD_WEBHOOK_URL to /opt/docker/cosmos/envs/.env.staging, then make encrypt in aether once it's registered in SECRET_FILES

cosmos-init is required — make deploy cannot replace it

Aether's make deploy copies the .conf.full/.conf.temp variants but nginx ignores those (only *.conf loads), and it never issues the cert nor activates the vhost. Activating a full vhost that references a missing cert would break nginx -t and risk the whole shared proxy on its next restart. cosmos-init issues the cert before activating HTTPS.

Deploying Cosmos updates

Cosmos-side deploys (code, content) happen from the Cosmos repo:

cd /opt/docker/cosmos/repo
make deploy ENV=staging          # deploys develop
make deploy ENV=prod REF=v1.0    # deploys a tag (once prod exists)

Aether-side deploys are only needed when the nginx vhost changes:

Change How to deploy
Edit cosmos-staging.conf.full (routing, auth, rate-limit) cd aether && make deploy && make restart-nginx
First-ever bootstrap / new environment make cosmos-init (see above)
LEAD_WEBHOOK_URL change Edit the server env file → make restart ENV=staging in cosmos repo → (if secret-managed) make encrypt in aether

Production — staged, waiting on the DNS cutover

Everything for prod is pre-staged: the cosmos-prod vhosts (cosmos-prod.conf.{bootstrap,full,temp}), the cosmos-prod-init target, and MANAGED_FILES entries are all in place. The prod vhost serves the apex publicly (no basic auth) and 301-redirects www → apex.

The one thing that cannot be pre-done is the TLS cert: Let's Encrypt (HTTP-01) needs groupe-suffren.com to already resolve to this server, and today it points to 199.60.103.64/164 (elsewhere). So the cert issues at cutover.

Cutover runbook

  1. Repoint DNS — apex groupe-suffren.com + www A records → this server (54.36.99.184). Confirm: dig +short groupe-suffren.com.
  2. Set the webhook (do this first — a live public form with no target 503s): add LEAD_WEBHOOK_URL=… to /opt/docker/cosmos/envs/.env.prod.
  3. Cert + vhost (issues the cert, leaves a maintenance page up — no 502 gap):
    cd /opt/docker/aether/repo && make cosmos-prod-init
    
  4. Deploy the app (builds, starts cosmos-prod-web, swaps maintenance → live, smoke):
    cd /opt/docker/cosmos/repo && ./deploy.sh prod <tag>
    
    Prod requires a tag (cut one off main, which now carries the Docker setup: git tag v0.1.0 && git push origin v0.1.0).

That's it — DNS + two commands. If certbot fails at step 3, DNS hasn't propagated yet (dig +short groupe-suffren.com must show this server); retry.

Troubleshooting

cosmos-staging returns 502: the container is down. Check docker ps --filter name=cosmos-staging and docker logs cosmos-staging-web.

/api/lead returns 503: LEAD_WEBHOOK_URL is unset — by design (fail-loud). Set it in /opt/docker/cosmos/envs/.env.staging and make restart ENV=staging.

nginx won't reload after a cosmos change: almost always a missing cert — docker exec nginx-proxy ls /etc/letsencrypt/live/cosmos-staging.groupe-suffren.com/. If absent, run make cosmos-init (idempotent; certbot skips a valid cert).

Basic-auth prompt won't accept credentials: the shared /etc/nginx/.htpasswd is used; see environment management.