- Jinja 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
ci/woodpecker/push/linting Pipeline was successful
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
| .woodpecker | ||
| defaults | ||
| handlers | ||
| meta | ||
| roles | ||
| tasks | ||
| templates/traefik | ||
| .ansible-lint | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| .markdownlint-cli2.jsonc | ||
| .sops.yaml | ||
| .yamllint | ||
| AGENTS.md | ||
| ansible.cfg | ||
| playbook.yaml | ||
| readme.md | ||
| renovate.json | ||
Ansible Role: Traefik
Installs and runs Traefik as a Docker container on the host network. Traefik terminates TLS on port 443 with Let's Encrypt certificates (DNS-01 challenge through TransIP) and proxies each configured route to a backend. Routes are written to a Traefik file provider config.
Requirements
- A Docker host. The role uses the
community.dockercollection. - Access to the registry mirror
cr.simoncor.net(the image is pulled fromcr.simoncor.net/dockerhub). - A TransIP account with an API key, used for the ACME DNS challenge.
Dependencies
None in meta/main.yaml. The role does not install Docker itself; run the docker role first (as the s3 playbook
does). roles/requirements.yaml (note the .yaml extension) only lists this role
(https://git.simoncor.net/ansible/traefik.git).
Variables
| Variable | Required | Default | Description |
|---|---|---|---|
traefik_letsencrypt_email |
Yes | email@example.com |
E-mail address for Let's Encrypt registration |
traefik_routes |
Yes | one example route (service.example.com) |
List of routes, see below |
transip_user |
Yes | TransIP account name (not set in defaults) | |
transip_key |
Yes | TransIP private key (not set in defaults) | |
timezone |
Yes | Container timezone (TZ, not set in defaults) |
transip_user, transip_key and timezone are used by the tasks but have no default. Keep transip_key in
sops-encrypted inventory variables. The key may contain literal \n sequences, which are converted to newlines.
traefik_routes
Every item creates one router and one service in /mnt/traefik/http.yml.
| Key | Required | Default | Description |
|---|---|---|---|
name |
Yes | Public host name, matched with Host(...) |
|
service |
Yes | Name of the router; the service is called <service>-svc |
|
host |
Yes | Backend host or IP address | |
proto |
Yes | Backend protocol, http or https |
|
port |
Yes | Backend port |
The default route also has a waf: false key, which no template uses.
Each router listens on the websecure entrypoint only and uses the transip certificate resolver. The backend URL is
<proto>://<host>:<port>. If at least one route uses https, Traefik sets insecureSkipVerify: true for all
backends, so backend certificates are not verified.
Example
traefik_letsencrypt_email: "admin@example.com"
timezone: "Europe/Amsterdam"
# transip credentials: keep real values in sops-encrypted inventory vars
transip_user: "example-user"
transip_key: "CHANGE-ME"
traefik_routes:
- name: "app.example.com"
service: "webapp"
host: "192.168.1.10"
proto: "http"
port: "8080"
- name: "api.example.com"
service: "api"
host: "192.168.1.11"
proto: "https"
port: "443"
Usage
Run playbook.yaml through Semaphore. The playbook first runs ansible-galaxy install -f -r roles/requirements.yaml
on localhost, then includes the traefik role.
Operational notes
- The container is called
traefik, uses imagecr.simoncor.net/dockerhub/library/traefik:v3.7.13, host networking, restart policyunless-stoppedand is pulled on every run. - Entrypoints:
webon port 80 (redirects towebsecure) andwebsecureon port 443 (timeouts disabled, encoded slashes allowed). - Files in
/mnt/traefik:traefik.yml,http.yml(both mode0640),transip.keyandacme.json(mode0600). They are mounted into the container; changes to the config, routes or key restart the container. acme.jsonholds the issued certificates and is only touched (never overwritten) by the role.- After starting the container, the role runs a Docker cleanup (
tasks/cleanup.yaml): it prunes containers, images, networks, volumes and the builder cache and then runsdocker system prune --all --force --volumes. This removes everything unused on the host. - There are no tags.