Aller au contenu

Helios (Practice Websites)

Scope

This page covers Helios infrastructure managed from the Aether repo — nginx configs, environment files, monitoring rules, and the aether-side deployment pattern.

For Helios application specifics (content editing, adding a practice workflow, Next.js deploy via Helios's own Makefile), see the Helios repo's own docs:

  • helios/repo/docs/adding-a-practice.md — full practice onboarding walkthrough
  • helios/repo/docs/operations.md — content updates, image pipeline, cache invalidation

Architecture

Helios is a multi-tenant Next.js frontend serving 9+ dental practice websites from a single codebase. Each practice has its own domain and its own config in Aletheia.

                      ┌──────────────────────────────────────┐
                      │         nginx (aether)               │
                      │  cabinet-dentaire-aubagne.fr       ──┐
                      │  le-canet.chirurgiens-dentistes.fr ──┤
                      │  cabinet-bodin.fr                  ──┼── helios-prod-web:3000
                      │  dr-david-simon...                 ──┤
                      │  ~^[^.]+\.prod\.groupe-suffren\.com$──┤  (any {code}.prod, derived)
                      │  ...                               ──┘
                      └──────────┬───────────────────────────┘
                     ┌──────────────────────────┐
                     │   helios-{env}-web       │
                     │   (Next.js + Node.js)    │
                     └────────────┬─────────────┘
                                  │ REST
                     ┌──────────────────────────┐
                     │   aletheia-{env}-web     │
                     │   /api/v1/websites       │
                     └──────────────────────────┘

One Next.js container per environment serves all practice sites; routing by Host header is done in nginx and in the Next.js middleware.

Managed by Aether

Nginx vhosts

Three base configs (one per environment) in nginx/conf.d/:

  • helios-prod.conf.full + .conf.temp
  • helios-staging.conf.full + .conf.temp
  • helios-dev.conf.full + .conf.temp

Each prod vhost routes the real .fr practice domains (explicit, auth-off) plus any {code}.prod.groupe-suffren.com preview host — matched by a single regex server_name ~^[^.]+\.prod\.groupe-suffren\.com$ (Phase C: preview codes are derived, never enumerated) — to the same helios-prod-web:3000 upstream. Staging and dev vhosts are the same regex per env (.staging./.dev.), gated whole-vhost by basic auth. Distinguishing by practice is done by Helios itself via the Host header (codeFromHost). Onboarding a preview needs no nginx edit.

Monitored domains

SSL certificate monitoring:

  • https://aletheia.groupe-suffren.com
  • https://aletheia-staging.groupe-suffren.com
  • https://aletheia-dev.groupe-suffren.com
  • https://monitoring.groupe-suffren.com
  • https://analytics.groupe-suffren.com
  • https://cosmos-staging.groupe-suffren.com

Aletheia backend health monitoring (HealthCheckFailing):

  • https://aletheia.groupe-suffren.com/health/
  • https://aletheia-staging.groupe-suffren.com/health/
  • https://aletheia-dev.groupe-suffren.com/health/
  • https://aletheia-staging.groupe-suffren.com/api/v1/websites/sites/cda/config/

Helios-specific alerts

Alert Condition Source
HeliosContainerRestarting > 2 restarts in 15 min helios.rules.yml
HeliosHealthCheckFailing Practice site probe failing > 5 min helios.rules.yml
HeliosSSLExpiringSoon Practice domain cert < 14 days helios.rules.yml

See runbooks for the response procedures.

Environment files

Encrypted env files for Helios live in envs/helios/ in the aether repo (see environment management for the full list):

  • envs/helios/.env.dev.enc
  • envs/helios/.env.staging.enc
  • envs/helios/.env.prod.enc

Each contains:

Variable Purpose
ALETHEIA_API_URL Internal URL Helios uses to fetch content (e.g., http://aletheia-prod-web:8000/api/v1/websites)
REVALIDATION_SECRET Shared secret for Aletheia → Helios ISR webhook (Next.js cache invalidation)
NODE_ENV Always production (even for dev/staging — this is about Next.js optimization, not environment)
ENVIRONMENT prod, staging, or dev — used for logging/sentry tagging

Bootstrapping a new Helios install

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

Preflight for the cert step: the wildcard is issued via DNS-01, so the certbot container must run the certbot/dns-ovh image with /etc/ovh/dns_ovh.ini mounted. Run make decrypt (drops the OVH creds onto the server) then make restart-nginx (recreates certbot with the plugin) before helios-init.

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

This target:

  1. Creates /opt/docker/helios/{repo,envs}/ on the server
  2. Generates .env.{prod,staging,dev} with fresh REVALIDATION_SECRET values (skips any env file that already exists — safe to re-run without rotating secrets)
  3. Issues the per-env wildcard cert (--cert-name helios, DNS-01 via OVH) — one cert file with three SANs *.prod. + *.staging. + *.dev.groupe-suffren.com, covering every {code}.{env} preview host, write-once (Phase C dotted env)
  4. Deploys nginx configs for Helios domains
  5. Deploys monitoring rules (helios.rules.yml)
  6. Reloads nginx and Prometheus

After helios-init:

  1. Copy the printed REVALIDATION_SECRET values into the matching Aletheia env files (HELIOS_REVALIDATION_SECRET)
  2. Clone the Helios repo: git clone git@github.com:baudry-suffren/helios.git /opt/docker/helios/repo
  3. Preview hosts need no cert work — the per-env wildcard from helios-init (*.{prod,staging,dev}.groupe-suffren.com) covers them. Real .fr practice-domain certs are separate and minted at cutover (see Adding a New Practice)
  4. Deploy: cd /opt/docker/helios/repo && make deploy ENV=prod
  5. Run make encrypt in aether to persist the new secrets

Deploying Helios updates

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

cd /opt/docker/helios/repo
make deploy ENV=prod        # deploys current branch
make deploy ENV=prod REF=v1.2  # deploys a tag

Aether-side deploys only needed when Helios infrastructure changes:

Change How to deploy
New practice preview onboarded Nothing in aether (Phase C: host is derived; only the Aletheia SiteConfig row is created)
New practice .fr cutover (real domain goes live) cd aether && make deploy && make restart-nginx (add the .fr server_name + cert + monitoring — see below)
New alert rule in helios.rules.yml cd aether && make deploy (Prometheus auto-reloads)
Env variable change Edit server env file → make restart in helios repo → make encrypt in aether
New environment added (e.g. helios-qa) Create new .env.qa + new nginx config + redeploy

Adding a New Practice

Preview (before cutover) — zero aether changes

Phase C: a preview host is {code}.{env}.groupe-suffren.com, derived by nginx (the per-env regex server_name) and by Helios (codeFromHost), and already covered by the per-env wildcard cert + wildcard DNS. From aether you do nothing. Onboarding a preview is a single action in Aletheia: create the SiteConfig row. It is then live at {code}.{env}.groupe-suffren.com behind the shared basic-auth gate.

Cutover (real .fr goes live) — make helios-golive CODE=… (Phase D)

Only when a practice's real domain goes live do aether touchpoints appear. Phase D turns this into one command that reads the domain from the one source (Aletheia SiteConfig.domain, never re-typed), issues the cert, and prints the lines to paste — it does not auto-edit the hand-maintained files.

Pre-flight: the .fr (+ www.) must already resolve to THIS server (HTTP-01, like cosmos-prod-init), and SiteConfig.domain must be set in the CMS (the command aborts loudly otherwise, so golive never emits empty/broken config).

make helios-golive CODE=pds

It does two things and prints the rest:

  1. Reads the domain: manage.py site_domain <CODE> on aletheia-prod reads the model directly (no is_active gate, no auth) so it works mid-cutover.
  2. Issues the per-domain HTTP-01 cert (--cert-name <domain>, -d <domain> -d www.<domain>) — a separate cert, not the helios DNS-01 wildcard (the wildcard doesn't cover a .fr, so a real domain served on the preview vhost gets the wrong cert).
  3. Prints (paste by hand): a whole .fr server block (own cert, auth-off — from nginx/conf.d/helios-fr.conf.template) to save as helios-fr-<code>.conf; the server_name + $helios_preview_realm map lines to remove from helios-prod.conf.full (else conflicting server name); the 2 prometheus targets (blackbox-ssl + blackbox-helios-frontend); the Helios practices.ts realDomain→code entries.
  4. Reminds you of the two manual gates: set the DNS A-record (external), then flip SiteConfig.is_active = True once it resolves.

For everything else (SiteConfig in Aletheia, Helios deploy, DNS setup, content creation), see Helios's adding-a-practice guide.

Troubleshooting

Practice site returns 502: Helios container is down or network-isolated. Check docker ps --filter name=helios-prod and docker logs helios-prod-web.

Content changes don't appear on the site: ISR revalidation webhook failed. Check Aletheia's logs for REVALIDATION_SECRET mismatches, and verify Next.js is reachable from Aletheia: docker exec aletheia-prod-web curl http://helios-prod-web:3000/api/revalidate.

SSL cert expiring: see SSL Certificate Expiring runbook. Practice domains renew the same way as groupe-suffren.com domains.

New practice added but site 404s: verify the domain resolves, reaches nginx (curl -v https://newdomain.fr), that nginx has a matching server_name, and that Helios's Next.js router knows about the practice (Aletheia SiteConfig with matching domain).