Files
cameleer-website/OPERATOR-CHECKLIST.md
hsiegeln 93131461b8
Some checks failed
ci / build-test (push) Failing after 46s
Fix CI build: read PUBLIC_* values from secrets context, broaden TODO guard
- Switch ci.yml + deploy.yml env bindings from ${{ vars.* }} to
  ${{ secrets.* }}. Gitea lets you put non-sensitive Actions values in
  either tab, and the secrets tab was used in practice — workflow was
  reading the wrong context and getting empty strings.
- Broaden the "no TODO markers ship" guard to accept both TODO: and
  legacy TBD: prefixes, matching the imprint/privacy page markers that
  were recently renamed.
- Document the secret-vs-variable choice in OPERATOR-CHECKLIST so the
  next operator doesn't get tripped up by the same thing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 18:04:16 +02:00

4.8 KiB

Operator Checklist — cameleer-website

One-time setup that lives outside code. Do these before the first main merge that ships live.

1. Hetzner Webhosting L

  • Provision Webhosting L plan. Note the SSH hostname and SFTP path.
  • In the Hetzner control panel, enable SSH access for the main user.
  • Generate an ed25519 SSH key pair locally (once): bash ssh-keygen -t ed25519 -f ~/.ssh/cameleer-website-deploy -C "cameleer-website CI"
  • Add the public key to ~/.ssh/authorized_keys on the Hetzner account.
  • Test SSH: ssh -i ~/.ssh/cameleer-website-deploy user@hetzner-host "ls -la".
  • Create a subdirectory for the site (typical path: public_html/www.cameleer.io/).
  • Grab the SSH host key for pinning: bash ssh-keyscan -t ed25519 hetzner-host > hetzner-known-hosts.txt
  • Install Let's Encrypt (or use Hetzner's built-in) for the origin hostname. Cloudflare Full (strict) requires a valid origin cert.

2. Cloudflare (zone: cameleer.io)

DNS

  • A record www.cameleer.io → Hetzner IP. Proxied (orange).
  • A record @ (apex) → Hetzner IP. Proxied (orange).
  • A/CNAME for auth.cameleer.io → SaaS ingress. Proxied.
  • A/CNAME for platform.cameleer.io → SaaS ingress. Proxied.
  • NO bare MX. If email is needed at @cameleer.io, use Cloudflare Email Routing or a distinct hostname on a different provider.

SSL/TLS

  • Mode: Full (strict).
  • Minimum TLS: 1.2.
  • TLS 1.3: on.
  • Always Use HTTPS: on.
  • Automatic HTTPS Rewrites: on.
  • HSTS: max-age=31536000; includeSubDomains; preload. (Add the domain to https://hstspreload.org/ only after the site is stable and serving HSTS cleanly for a couple of weeks.)

Security

  • WAF → Cloudflare Managed Ruleset: enabled (Free plan includes this since 2024).
  • Bot Fight Mode: on.
  • Browser Integrity Check: on.
  • Security Level: medium.
  • Email Obfuscation: on.
  • Rate Limiting rule: 20 req/min per IP on /* (marketing pages).

Transform Rules (edge-level security headers)

Create a Transform Rule — "Modify Response Header" — matching http.host eq "www.cameleer.io":

Operation Header Value
Set Content-Security-Policy default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'none'; object-src 'none'
Set X-Content-Type-Options nosniff
Set X-Frame-Options DENY
Set Referrer-Policy strict-origin-when-cross-origin
Set Permissions-Policy geolocation=(), microphone=(), camera=(), payment=(), usb=()

Page Rules / Redirect

  • cameleer.io/*https://www.cameleer.io/$1 (301 permanent).

3. Gitea Actions secrets (in the repo settings)

Add these under Repository settings → Actions → Secrets (or variables):

Name Type Value
SFTP_HOST secret Hetzner SSH hostname
SFTP_USER secret Hetzner SSH user
SFTP_PATH secret Absolute path to document root (e.g., /usr/home/cameleer/public_html/www.cameleer.io)
SFTP_KEY secret Contents of ~/.ssh/cameleer-website-deploy (private key, PEM)
SFTP_KNOWN_HOSTS secret Contents of hetzner-known-hosts.txt (captured via ssh-keyscan)
PUBLIC_AUTH_SIGNIN_URL secret https://auth.cameleer.io/sign-in
PUBLIC_AUTH_SIGNUP_URL secret https://auth.cameleer.io/sign-in?first_screen=register
PUBLIC_SALES_EMAIL secret sales@cameleer.io (or whatever sales alias you set up)

These three are not actually secret (they end up in the built HTML), but Gitea's Actions UI puts them in the Secrets tab alongside the SFTP credentials. The workflows read them via the ${{ secrets.* }} context.

4. Content TODO — before go-live

  • Fill in src/pages/imprint.astro operator object with real legal details.
  • Fill in operatorContact in src/pages/privacy.astro.
  • Review the "Why us" / nJAMS wording in src/components/sections/WhyUs.astro for trademark safety.
  • Confirm MID-tier retention: spec says 7 days; cameleer-saas/HOWTO.md says 30 days. Reconcile one side or the other.

5. First deploy

  1. Merge a PR to main.
  2. Watch the Gitea Actions run: build, then deploy.
  3. The workflow includes a post-deploy smoke check — if HSTS / CSP / XFO are missing from the live response, the deploy fails and must be debugged at the Cloudflare Transform Rule layer.
  4. Manually verify:
    • curl -sI https://www.cameleer.io/ returns all six security headers.
    • https://cameleer.io/https://www.cameleer.io/ 301 redirect.
    • Open the site in an incognito window on desktop + mobile.