Add the building blocks the provisioning CLI renders per site. Base images (site-templates/images): - php-fpm: non-root (www-data) php:<ver>-fpm-alpine with pdo_mysql, mysqli, gd, intl, zip, opcache, exif; tuned php.ini + pool; built per PHP version. - nginx: hardened nginx:1.27-alpine with shared security + fastcgi snippets; per-site server block mounted at runtime. - build.sh: build + Trivy-scan (+ optional push) for both images. Profile templates (site-templates/profiles), Jinja2 rendered: - static, redirect (tiny nginx 301/302), custom-php (nginx + our php-fpm, optional DB), wordpress (nginx + official wordpress-fpm, DB required, upload-exec denied). Only nginx carries Traefik labels and joins proxy; php-fpm uses the private <slug>_net and joins platform only when a DB is needed. Secrets stay in a git-ignored .env, not the compose. CI: .forgejo/workflows/images.yml builds/scans images (gitleaks + Trivy). README documents the render context and the Phase 4 web-root ownership item. Templates validated: all profiles render to valid compose YAML across the database on/off branches and single/multi-domain host rules. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
3.2 KiB
Markdown
70 lines
3.2 KiB
Markdown
# site-templates
|
|
|
|
Building blocks the provisioning CLI (Phase 4) renders into
|
|
`deployments/<customer>/<site>/`. Two parts: **base images** and **profile
|
|
templates**.
|
|
|
|
## Images (`images/`)
|
|
|
|
Hardened base images, built and pushed to the Forgejo registry.
|
|
|
|
| Image | Base | Notes |
|
|
|-------|------|-------|
|
|
| `nginx` | `nginx:1.27-alpine` | Hardened `nginx.conf` + reusable snippets (`security.conf`, `fastcgi-php.conf`). Per-site server block mounted at runtime. |
|
|
| `php-fpm` | `php:<ver>-fpm-alpine` | **Runs as non-root** (`www-data`). Extensions: pdo_mysql, mysqli, gd, intl, zip, opcache, exif. OPcache tuned. Built per PHP version. |
|
|
|
|
Build (and Trivy-scan) locally:
|
|
```bash
|
|
REGISTRY=git.example.com/heleos ./images/build.sh # build + scan
|
|
REGISTRY=git.example.com/heleos PUSH=1 ./images/build.sh # also push
|
|
```
|
|
CI does the same on push — see [`.forgejo/workflows/images.yml`](../.forgejo/workflows/images.yml).
|
|
|
|
WordPress uses the official `wordpress:<ver>-fpm-alpine` image directly (it
|
|
bundles WordPress + php-fpm); only `custom-php` uses our `php-fpm` image.
|
|
|
|
## Profiles (`profiles/`)
|
|
|
|
One directory per profile (see
|
|
[../docs/04-site-profiles.md](../docs/04-site-profiles.md)). Each has a
|
|
`docker-compose.yml.j2` and its nginx config template.
|
|
|
|
| Profile | Containers | DB | Networks |
|
|
|---------|-----------|----|---------|
|
|
| `static` | nginx (web root ro) | — | proxy |
|
|
| `redirect` | nginx (301/302) | — | proxy |
|
|
| `custom-php` | nginx + php-fpm | optional | proxy, site, [platform] |
|
|
| `wordpress` | nginx + wordpress-fpm | required | proxy, site, platform |
|
|
|
|
Routing pattern (all profiles): only **nginx** carries Traefik labels and joins
|
|
`proxy`; php-fpm joins the private `site` network (`<slug>_net`) and, when a DB
|
|
is used, the shared internal `platform` network to reach MariaDB. nginx reaches
|
|
php-fpm at `fpm:9000`.
|
|
|
|
## Render context
|
|
|
|
The CLI renders the `.j2` files with these variables (source: the site's
|
|
`site.yaml` + platform config):
|
|
|
|
| Variable | Example | Meaning |
|
|
|----------|---------|---------|
|
|
| `customer` / `site` | `acme` / `shop` | Ids. |
|
|
| `slug` | `acme-shop` | `<customer>-<site>`; Docker/router key. |
|
|
| `slug_underscored` | `acme_shop` | For DB names (`db_`, `u_`). |
|
|
| `domains` | `[shop.acme.com]` | Host rule is `Host(\`d1\`) || Host(\`d2\`)…` |
|
|
| `webroot` | `/tank/customers/acme/shop/web` | Bind-mounted web root. |
|
|
| `database` | `true`/`false` | custom-php only; wordpress is always true. |
|
|
| `redirect_to` / `redirect_code` | `https://acme.com` / `301` | redirect profile. |
|
|
| `nginx_image` / `php_image` / `wordpress_image` | `git.example.com/heleos/nginx:latest` | Resolved image refs. |
|
|
| `resources.cpu` / `resources.memory` | `1.0` / `512m` | Per-project limits. |
|
|
|
|
Secrets (DB password) are **not** rendered into the compose file — they go into a
|
|
git-ignored `.env` (from `secrets.enc.yaml`) that the compose reads via
|
|
`env_file`.
|
|
|
|
## Provisioning note (for Phase 4)
|
|
|
|
The web root dataset must be writable by the php-fpm user (`www-data`, uid 82 in
|
|
these alpine images) **and** by the customer's SFTP user. Provisioning will set
|
|
web-root ownership/permissions accordingly (e.g. shared group + setgid) — this is
|
|
an open item to finalize in the Phase 4 CLI, not baked into these templates.
|