Linderhof is an Ansible-based self-hosting infrastructure stack that deploys email, web server, git hosting, Matrix homeserver, monitoring, and backup services using Docker Compose on Ubuntu servers.
Note: Inventory and vault password are set via `ANSIBLE_INVENTORY` and `ANSIBLE_VAULT_PASSWORD_FILE` in `.envrc`, driven by `LINDERHOF_STACK`. No extra flags needed once the stack is selected.
## Architecture
**Deployment Pattern:** Each service is deployed to `/srv/<service>/` on the target host with a `compose.yml` and environment files.
**Mail TLS:** on first deployment, the mail role stops Caddy, runs certbot standalone to acquire a Let's Encrypt cert for `mail_hostname`, then restarts Caddy. subsequent runs skip this (cert already exists). Caddy owns port 80 so standalone is the only viable approach without a DNS challenge plugin.
**Docker Networks:** All networks are pre-created by the `docker_network` role before any service deploys. Services declare all networks as `external: true` in their `compose.yml.j2` — no service creates its own network. Networks are created conditionally based on `enable_*` flags:
| Network | Created when |
|---------|-------------|
| `caddy` | always |
| `mail` | `enable_mail` |
| `webmail` | `enable_mail` |
| `git` | `enable_forgejo` |
| `monitoring` | `enable_monitoring` |
| `tuwunel` | `enable_tuwunel` |
| `radicale` | `enable_radicale` |
Caddy's `compose.yml.j2` also conditionally declares network references using the same `enable_*` flags so it never references a network that wasn't created.
**Adding a new service:** create the network in `docker_network/tasks/main.yml` with the appropriate `when:` condition, declare it `external: true` in the service compose template, and add it to caddy's compose template if caddy needs to reach it.
## Available Tags
-`bootstrap` - Initial server setup (use `--tags bootstrap`)