Single-host operations repo for yggdrasil and the Docker services it runs.
- One main server:
yggdrasil - One environment
- Git as source of truth for host and service configuration
- Ansible for host bootstrap and service deployment
- Docker Compose for runtime
- Caddy as the shared reverse proxy
- Ntfy for self-hosted notifications
- Diun for image update notifications
- Watchtower for opt-in container auto-updates
- SOPS + age for encrypted service secrets
- Host:
yggdrasil
docs/: architecture, onboarding, runbooksbootstrap/ansible/: host bootstrap and service deploymentservices/: side projects, Compose files, and service-local secrets
This repo is currently focused on bootstrapping one Docker host, running core infrastructure services, and deploying side projects from services/*.
Use the top-level Makefile as the primary operator entrypoint.
make bootstrap
make validate
make ansible-syntax
make ansible-bootstrap
make ansible-deploy-service SERVICE=ntfy
make ansible-deploy-service SERVICE=diun
make ansible-deploy-service SERVICE=watchtower
make ansible-deploy-services
make ansible-deploy-service SERVICE=reverse-proxyEach deployable service lives in its own directory under services/<name>/.
Recommended contents:
services/<name>/
compose.yaml
.env
Dockerfile
.env.example
secrets/
README.mdFiles under services/<name>/secrets/ are intended to stay encrypted in git and are decrypted by Ansible during deployment.
Non-secret Compose variables should live in a tracked .env created from .env.example.
Services should normally run prebuilt Docker images and opt into update notifications with diun.enable=true. Add com.centurylinklabs.watchtower.enable=true only when automatic updates are acceptable.
- Bootstrap
yggdrasilwithmake ansible-bootstrap - Add the Cloudflare origin certificate and private key under
services/reverse-proxy/secrets/and deploy the shared reverse proxy withmake ansible-deploy-service SERVICE=reverse-proxy - Deploy
ntfywithmake ansible-deploy-service SERVICE=ntfy - Deploy
diunwithmake ansible-deploy-service SERVICE=diun - Deploy
watchtowerwithmake ansible-deploy-service SERVICE=watchtower - Deploy individual side projects with
make ansible-deploy-service SERVICE=<name>or all services withmake ansible-deploy-services
make ansible-bootstrap prompts for the remote sudo password because the bootstrap playbook uses privilege escalation.
Set an age recipient in .sops.yaml, then encrypt service secrets stored under services/*/secrets/.
Use the top-level Makefile to validate Ansible before deployment:
make validate
make ansible-lint