# Web Hosting Stack — SNS Digital **Entity:** SNS Digital · **Status:** Buildable now ## What it is A self-hosted web hosting platform for client sites and internal properties. Caddy as reverse proxy/TLS terminator, static sites via Hugo or plain HTML, dynamic sites via WordPress (when clients insist) or Ghost. ## Stack | Component | Software | FOSS | Role | |-----------|----------|------|------| | Reverse proxy + TLS | Caddy 2 | Yes | Auto HTTPS, reverse proxy, static file server | | Static site generator | Hugo | Yes | Fast builds, no runtime dependencies | | CMS (when needed) | WordPress or Ghost | Yes | Client-managed content | | Database | MariaDB | Yes | WordPress backend | | Object storage | MinIO or S3 | Yes / Partial | Media uploads, large assets | | DNS | Route53 (AWS) | No | Reliable, cheap, API-driven | | Deployment | Git push → Gitea Actions → rsync/docker | Yes | Zero-touch deploys | ## Topology ``` Internet │ ▼ ┌─────────────────────────────────┐ │ Caddy (LXC on Proxmox) │ ← public IP via port-forward or Linode proxy │ - TLS termination │ │ - Rate limiting │ │ - Static file serving │ │ - Reverse proxy to backends │ └──────────┬──────────────────────┘ │ ┌─────┼──────────┐ ▼ ▼ ▼ Hugo WordPress Ghost (static) (VM/Docker) (Docker) ``` ### Where it runs | Site type | Runs on | Why | |-----------|---------|-----| | Static (Hugo) | Caddy serves files directly | No runtime, fastest possible | | WordPress | Docker Compose VM on Proxmox | Isolation, easy backup/restore | | Ghost | Docker Compose VM on Proxmox | Cleaner than WP for blogs | | High-traffic / client SLA | Linode or AWS (CloudFront + S3) | Uptime guarantee > home connection | ## Build Steps ### Static site (Hugo — default choice) 1. Scaffold site: `hugo new site client-name` 2. Add theme as git submodule. 3. Push to Gitea repo. 4. Gitea Actions workflow: build → rsync to Caddy's serve directory. 5. Caddyfile entry: ``` client-name.com { root * /srv/sites/client-name/public file_server encode gzip } ``` ### WordPress (when client requires it) 1. Clone Docker Compose template: ```yaml services: wordpress: image: wordpress:6-apache volumes: [./wp-content:/var/www/html/wp-content] environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_NAME: wp db: image: mariadb:11 volumes: [./data:/var/lib/mysql] environment: MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db_root_pw ``` 2. Caddy reverse proxies to `wordpress:80`. 3. Backup: PBS snapshots VM nightly + wp-content rsync to S3. ## Security Posture - **Caddy handles TLS** — automatic cert renewal, no manual certs to manage. - **No PHP on the proxy LXC.** WordPress runs isolated in its own VM/container. - **WordPress hardening:** disable XML-RPC, limit login attempts (Fail2ban or WP plugin), auto-update minor versions, restrict `wp-admin` to Tailscale IP if internal. - **Rate limiting** in Caddy for login pages and API endpoints. - **CSP headers** set per-site in Caddyfile. ## Upgrade Path - **Cloudflare Tunnel:** If home IP isn't reliable enough for client SLAs, put Caddy behind a Cloudflare tunnel (free tier, no public port needed). - **Multi-node:** If hosting 20+ WordPress sites, move to a dedicated VM cluster with shared MariaDB (Galera) and NFS/Ceph for wp-content. - **Coolify or CapRover:** Self-hosted PaaS if you want a client-facing deploy dashboard. YAGNI until you have 5+ active web clients.