Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update templates for Traefik version 2 #2

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
# Reverse Proxy
This role sets up a reverse proxy, to route HTTP traffic to the containers. Currently this is facilitated by traefik.

This role sets up a reverse proxy, facilitated by [Traefik](https://containo.us/traefik/), to route HTTP traffic to the containers.

> Current `master` targets Traefik 2.x, for Traefik 1.x support use [`traefik-1.x` branch](https://github.com/OneOffTech/ansible-role-reverseproxy/tree/traefik-1.x)

## Requirements
A working Docker installation on the host system is all you need. For automatic certificate generation via LetsEncrypt a domain name has to point toward your host address.

A working Docker installation with Docker Compose.

For automatic certificate generation via LetsEncrypt a domain name has to point toward your host address.

## Configuration Variables

```yaml
path: "/home/user/reverseproxy" # Where the VPN proxy service will reside
data: "/data/reverseproxy/cert" # Where the certificates will be persisted
conf: "/data/reverseproxy/conf" # Where the configuration will be persisted
letsencrypt_email: "[email protected]" # Email of the admin, will be used for notifications
reverseproxy:
# Email used for notify certificate expiration
letsencrypt_email: "[email protected]"
path: "/home/user/reverseproxy" # Where the proxy service will reside
data: "/data/reverseproxy/cert" # Where the certificates will be persisted
conf: "/data/reverseproxy/conf" # Where the configuration will be persisted
log_level: "ERROR"
api: "traefik.domain.com" # domain where the dashboard will be reachable
api_user: "user:passwd" # username and password to protect the access to the dashboard (Use htpasswd to generate the passwords) https://docs.traefik.io/middlewares/basicauth/
```

## Upgrading installations

To upgrade the installation it is sufficient to simply run this playbook again after increasing
the version number.

### Upgrade from Traefik 1 to Traefik 2

Traefik version 2 is a major release and introduce some breaking changes in the configuration files
and labels.

- Create a backup of all files and configuration;
- The network name to attach containers has been renamed to `traefik_web`.
The full network name depends on the deployment folder, so if the reverse proxy is deployed under `/home/user/reverseproxy`,
the complete network name will be `reverseproxy_traefik_web`;
- Change `cert` folder as the acme format changed in Traefik version 2 and is not backward compatible, e.g. `data: "/data/reverseproxy/cert-t2"`;
3 changes: 3 additions & 0 deletions defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
default_rule: "{% raw %}Host(`{{ normalize .Name }}.example.domain`){% endraw %}"
log_level: "ERROR"
9 changes: 9 additions & 0 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
state: directory
with_items:
- "{{ reverseproxy.path }}"
- "{{ reverseproxy.path }}/rules"
- "{{ reverseproxy.data }}"
- "{{ reverseproxy.conf }}"
- "{{ reverseproxy.logs }}"

- name: ensure docker service file exists
template:
Expand All @@ -22,6 +24,13 @@
notify:
- reload reverseproxy

- name: ensure default rules files exists
template:
src: "rules_middlewares.toml.j2"
dest: "{{ reverseproxy.path }}/rules/middlewares.toml"
notify:
- reload reverseproxy

- name: ensure proxy is registered as a system service
template:
src: "reverseproxy.service.j2"
Expand Down
37 changes: 28 additions & 9 deletions templates/docker-compose.yml.j2
Original file line number Diff line number Diff line change
@@ -1,23 +1,42 @@
version: '2'
version: '3.1'

networks:
web:
traefik_web:
driver: "bridge"

services:
proxy:
image: "traefik:1.7"
command: "--logLevel=ERROR"
image: "traefik:v2.2"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "{{ reverseproxy.data }}/:/cert/"
- "{{ reverseproxy.path }}/rules/:/rules/"
- "{{ reverseproxy.data }}/:/letsencrypt/"
{% if 'logs' in reverseproxy %}
- "{{ reverseproxy.logs }}/:/logs/"
{% endif %}
- "{{ reverseproxy.conf }}/:/etc/traefik/:ro"
security_opt:
- no-new-privileges:true # limit containers to gain new privileges https://docs.docker.com/engine/reference/run/#security-configuration
labels:
- "traefik.enable=false" # set to true to expose Monitoring & API
- "traefik.backend=proxy"
- "traefik.port=8080"
- "traefik.enable=true"
## global redirect to https
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
{% if 'api' in reverseproxy %}
- "traefik.http.routers.traefik-rtr.entrypoints=websecure"
- "traefik.http.routers.traefik-rtr.rule=Host(`{{ reverseproxy.api }}`)"
- "traefik.http.routers.traefik-rtr.tls=true"
- "traefik.http.routers.traefik-rtr.tls.certresolver=mytls"
- "traefik.http.routers.traefik-rtr.service=api@internal"
{% if 'api_user' in reverseproxy %}
- "traefik.http.routers.traefik-rtr.middlewares=middlewares-basic-auth@file"
{% endif %}
{% endif %}
networks:
- "web"
- "traefik_web"

4 changes: 2 additions & 2 deletions templates/reverseproxy.service.j2
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ WorkingDirectory={{ reverseproxy.path }}
Restart=on-failure

# Compose up
ExecStart=/usr/bin/docker-compose up
ExecStart=/usr/local/bin/docker-compose up

# Compose down, remove containers and non-persistent volumes
ExecStop=/usr/bin/docker-compose down -v
ExecStop=/usr/local/bin/docker-compose down -v

[Install]
WantedBy=multi-user.target
14 changes: 14 additions & 0 deletions templates/rules_middlewares.toml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[http.middlewares]
{% if 'api_user' in reverseproxy %}
[http.middlewares.middlewares-basic-auth]
[http.middlewares.middlewares-basic-auth.basicAuth]
users = [
"{{ reverseproxy.api_user }}",
]
realm = "Traefik2 Basic Auth"
{% endif %}

[http.middlewares.middlewares-rate-limit]
[http.middlewares.middlewares-rate-limit.rateLimit]
average = 100
burst = 50
102 changes: 49 additions & 53 deletions templates/traefik.toml.j2
Original file line number Diff line number Diff line change
@@ -1,58 +1,54 @@
# accept self-signed SSL certs for backends
InsecureSkipVerify = true
[global]
checkNewVersion = false
sendAnonymousUsage = false

defaultEntryPoints = ["http", "https"]

[acme]
email = "{{ reverseproxy.letsencrypt_email }}"
storage = "cert/acme.json"
entryPoint = "https"
onDemand = false
OnHostRule = true

[acme.httpChallenge]
entryPoint = "http"
[serversTransport]
insecureSkipVerify = false

[entryPoints]
[entryPoints.http]
[entryPoints.web]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]

[entryPoints.websecure]
address = ":443"
[entryPoints.https.tls]

[web]
# own web server address (displays statistics)
address = ":8080"

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "docker.local"
watch = true
exposedbydefault = false

# new domains and subdomains can be configured here.
# note that domains and subdomains not defined in this file will still work,
# when defined in a container Host-Rule. However, they will generate
# their own ACME request, and will count towards LetsEncrypt's rate limit.
#
#[[acme.domains]]
# main = "example.com"
# sans = [
# # services
# "mumble.example.com",
# # ...
#
# # web vhosts:
# "www.example.com",
# "git.example.com",
# "mail.example.com",
# "chat.example.com",
# ]

# You can define multiple of these blocks, each of which will result in one
# certificate.
#[[acme.domains]]
# main = "example.org"
# sans = ["www.example.org", "mail.example.org"]

{% if 'api' in reverseproxy %}
[api]
dashboard = true
{% endif %}

[log]
level = "{{ reverseproxy.log_level | default(log_level, true) }}"

[accessLog]
format = "common"
# filePath = "/logs/traefik.log"
# bufferingSize = 100 # Configuring a buffer of 100 lines

[accessLog.filters]
statusCodes = ["200", "400-500"]

# [metrics]
# [metrics.prometheus]
# entryPoint = "traefik"
# buckets = [0.1,0.3,1.2,5.0]
# [ping]

[providers.docker]
network = "reverseproxy_traefik_web"
exposedByDefault = false
defaultRule = "{{ reverseproxy.default_rule | default(default_rule, true) }}"

# Load dynamic configuration from one or more .toml or .yml files in a directory.
[providers.file]
directory = "/rules"
watch = true


[certificatesResolvers.mytls.acme]
email = "{{ reverseproxy.letsencrypt_email }}"
storage = "/letsencrypt/acme.json"
[certificatesResolvers.mytls.acme.httpChallenge]
# used during the challenge
entryPoint = "web"