|
1 | | -name: "traefik" |
| 1 | +name: "reverse-proxy" |
2 | 2 | services: |
3 | 3 | socket-proxy: |
4 | | - image: "11notes/socket-proxy:2.1.3" |
| 4 | + # this image is used to expose the docker socket as read-only to traefik |
| 5 | + # you can check https://github.com/11notes/docker-socket-proxy for all details |
| 6 | + image: "11notes/socket-proxy:2.1.4" |
5 | 7 | read_only: true |
6 | | - # make sure to use the same UID/GID as the owner of your docker socket! |
7 | | - user: "0:0" |
| 8 | + user: "0:108" |
| 9 | + environment: |
| 10 | + TZ: "Europe/Zurich" |
8 | 11 | volumes: |
9 | | - # mount host docker socket, the :ro does not mean read-only for the socket, just for the actual file |
10 | | - - "/run/docker.sock:/run/docker.sock:ro" |
11 | | - # this socket is run as 1000:1000, not as root! |
12 | | - - "socket-proxy:/run/proxy" |
| 12 | + - "/run/docker.sock:/run/docker.sock:ro" |
| 13 | + - "socket-proxy.run:/run/proxy" |
13 | 14 | restart: "always" |
14 | 15 |
|
15 | 16 | traefik: |
16 | | - image: "11notes/traefik:3.2.0" |
17 | 17 | depends_on: |
18 | 18 | socket-proxy: |
19 | 19 | condition: "service_healthy" |
20 | 20 | restart: true |
| 21 | + image: "11notes/traefik:3.5.0" |
| 22 | + read_only: true |
| 23 | + labels: |
| 24 | + - "traefik.enable=true" |
| 25 | + |
| 26 | + # default errors middleware |
| 27 | + - "traefik.http.middlewares.default-errors.errors.status=402-599" |
| 28 | + - "traefik.http.middlewares.default-errors.errors.query=/{status}" |
| 29 | + - "traefik.http.middlewares.default-errors.errors.service=default-errors" |
| 30 | + |
| 31 | + # default ratelimit |
| 32 | + - "traefik.http.middlewares.default-ratelimit.ratelimit.average=100" |
| 33 | + - "traefik.http.middlewares.default-ratelimit.ratelimit.burst=120" |
| 34 | + - "traefik.http.middlewares.default-ratelimit.ratelimit.period=1s" |
| 35 | + |
| 36 | + # default CSP |
| 37 | + - "traefik.http.middlewares.default-csp.headers.contentSecurityPolicy=default-src 'self' blob: data: 'unsafe-inline'" |
| 38 | + |
| 39 | + # default allowlist |
| 40 | + - "traefik.http.middlewares.default-ipallowlist-RFC1918.ipallowlist.sourcerange=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" |
| 41 | + |
| 42 | + # example on how to secure the traefik dashboard and api |
| 43 | + - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_FQDN}`)" |
| 44 | + - "traefik.http.routers.dashboard.service=api@internal" |
| 45 | + - "traefik.http.routers.dashboard.middlewares=dashboard-auth" |
| 46 | + - "traefik.http.routers.dashboard.entrypoints=https" |
| 47 | + # admin / traefik, please change! |
| 48 | + - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$2a$12$ktgZsFQZ0S1FeQbI1JjS9u36fAJMHDQaY6LNi9EkEp8sKtP5BK43C" |
| 49 | + |
| 50 | + # default catch-all router |
| 51 | + - "traefik.http.routers.default.rule=HostRegexp(`.+`)" |
| 52 | + - "traefik.http.routers.default.priority=1" |
| 53 | + - "traefik.http.routers.default.entrypoints=https" |
| 54 | + - "traefik.http.routers.default.service=default-errors" |
| 55 | + |
| 56 | + # default http to https redirection |
| 57 | + - "traefik.http.middlewares.default-http.redirectscheme.permanent=true" |
| 58 | + - "traefik.http.middlewares.default-http.redirectscheme.scheme=https" |
| 59 | + - "traefik.http.routers.default-http.priority=1" |
| 60 | + - "traefik.http.routers.default-http.rule=HostRegexp(`.+`)" |
| 61 | + - "traefik.http.routers.default-http.entrypoints=http" |
| 62 | + - "traefik.http.routers.default-http.middlewares=default-http" |
| 63 | + - "traefik.http.routers.default-http.service=default-http" |
| 64 | + - "traefik.http.services.default-http.loadbalancer.passhostheader=true" |
| 65 | + environment: |
| 66 | + TZ: "Europe/Zurich" |
21 | 67 | command: |
| 68 | + # ping is needed for the health check to work! |
| 69 | + - "--ping=true" |
| 70 | + - "--ping.terminatingStatusCode=204" |
22 | 71 | - "--global.checkNewVersion=false" |
23 | 72 | - "--global.sendAnonymousUsage=false" |
| 73 | + - "--accesslog=true" |
24 | 74 | - "--api.dashboard=true" |
25 | | - - "--api.insecure=true" |
| 75 | + # disable insecure api and dashboard access |
| 76 | + - "--api.insecure=false" |
26 | 77 | - "--log.level=INFO" |
27 | 78 | - "--log.format=json" |
28 | 79 | - "--providers.docker.exposedByDefault=false" |
| 80 | + - "--providers.file.directory=/traefik/var" |
29 | 81 | - "--entrypoints.http.address=:80" |
| 82 | + - "--entrypoints.http.http.middlewares=default-errors,default-ratelimit,default-ipallowlist-RFC1918,default-csp" |
30 | 83 | - "--entrypoints.https.address=:443" |
| 84 | + - "--entrypoints.https.http.tls=true" |
| 85 | + - "--entrypoints.https.http.middlewares=default-errors,default-ratelimit,default-ipallowlist-RFC1918,default-csp" |
| 86 | + # disable upstream HTTPS certificate checks (https > https) |
31 | 87 | - "--serversTransport.insecureSkipVerify=true" |
| 88 | + - "--experimental.plugins.rewriteResponseHeaders.moduleName=github.com/jamesmcroft/traefik-plugin-rewrite-response-headers" |
| 89 | + - "--experimental.plugins.rewriteResponseHeaders.version=v1.1.2" |
| 90 | + - "--experimental.plugins.geoblock.moduleName=github.com/PascalMinder/geoblock" |
| 91 | + - "--experimental.plugins.geoblock.version=v0.3.3" |
32 | 92 | ports: |
33 | 93 | - "80:80/tcp" |
34 | 94 | - "443:443/tcp" |
35 | | - - "8080:8080/tcp" |
| 95 | + volumes: |
| 96 | + - "var:/traefik/var" |
| 97 | + - "plugins:/traefik/plugins" |
| 98 | + # access docker socket via proxy read-only |
| 99 | + - "socket-proxy.run:/var/run" |
36 | 100 | networks: |
37 | | - frontend: |
38 | 101 | backend: |
39 | | - volumes: |
40 | | - - "socket-proxy:/var/run" |
| 102 | + frontend: |
41 | 103 | sysctls: |
| 104 | + # allow rootless container to access ports < 1024 |
42 | 105 | net.ipv4.ip_unprivileged_port_start: 80 |
43 | 106 | restart: "always" |
44 | 107 |
|
45 | | - nginx: # example container |
46 | | - image: "11notes/nginx:1.26.2" |
| 108 | + errors: |
| 109 | + # this image can be used to display a simple error message since Traefik can’t serve content |
| 110 | + image: "11notes/traefik:errors" |
| 111 | + read_only: true |
47 | 112 | labels: |
48 | 113 | - "traefik.enable=true" |
49 | | - - "traefik.http.routers.default.priority=1" |
50 | | - - "traefik.http.routers.default.rule=PathPrefix(`/`)" |
51 | | - - "traefik.http.routers.default.entrypoints=http" |
52 | | - - "traefik.http.routers.default.service=default" |
53 | | - - "traefik.http.services.default.loadbalancer.server.port=8443" |
54 | | - - "traefik.http.services.default.loadbalancer.server.scheme=https" # proxy from http to https since this image runs by default on https |
| 114 | + - "traefik.http.services.default-errors.loadbalancer.server.port=8080" |
| 115 | + environment: |
| 116 | + TZ: "Europe/Zurich" |
55 | 117 | networks: |
56 | | - backend: # allow container only to be accessed via traefik |
| 118 | + backend: |
| 119 | + restart: "always" |
| 120 | + |
| 121 | + # example container |
| 122 | + nginx: |
| 123 | + image: "11notes/nginx:stable" |
| 124 | + read_only: true |
| 125 | + labels: |
| 126 | + - "traefik.enable=true" |
| 127 | + - "traefik.http.routers.nginx-example.rule=Host(`${NGINX_FQDN}`)" |
| 128 | + - "traefik.http.routers.nginx-example.entrypoints=https" |
| 129 | + - "traefik.http.routers.nginx-example.service=nginx-example" |
| 130 | + ports: |
| 131 | + - "3000:3000/tcp" |
| 132 | + tmpfs: |
| 133 | + # needed for read_only: true |
| 134 | + - "/nginx/cache:uid=1000,gid=1000" |
| 135 | + - "/nginx/run:uid=1000,gid=1000" |
| 136 | + networks: |
| 137 | + backend: |
57 | 138 | restart: "always" |
58 | 139 |
|
59 | 140 | volumes: |
60 | | - socket-proxy: |
| 141 | + var: |
| 142 | + plugins: |
| 143 | + socket-proxy.run: |
61 | 144 |
|
62 | 145 | networks: |
63 | 146 | frontend: |
|
0 commit comments