- Published on
cloudflared + traefik + docker for web-hosting without opened ports
Introduction
It's time for another homelab revamp. This time, I am moving most of my infrastructure from the cloud onto a bare metal server in colocation. Due to some peculiarities, every global firewall port rule has to be requested from the network operating center of my network provider. Therefore, I was looking into some options to serve web-content from my server without having to request a firewall rule for every VM. Theoretically, this setup could also be used to service web-content from behind a NAT or another situation where there is no global IP available. Turns out, only one additonal component is necessary: Cloudflare Tunnels. They provide a link between your server and Cloudflare and do not require any opened ports. In this blog post, I'll go over my setup for full encryption between the web-service and my users and some considerations to take when building something similar.
Configuration
traefik + cloudflared
Cloudflare Tunnels run via cloudflared
, a software-daemon from Cloudflare that opens an outgoing connection to the closest Cloudflare points-of-presence to proxy your internet traffic. Since Cloudflare Tunnels only provide limited routing functionality (only path based), we use it together with the popular reverse-proxy Traefik, that integrates well with Docker. Traffic will be routed by Cloudflare to Traefik, which then routes to the individual Docker containers which contain the web-services we want to expose.
I am using the following docker-compose.yml
for Traefik and cloudflared.
version: "3.9"
services:
tunnel:
container_name: cloudflared-tunnel
image: cloudflare/cloudflared
restart: unless-stopped
command: tunnel run
environment:
- TUNNEL_TOKEN=<YOUR TUNNEL TOKEN>
networks:
- cftunnel-transport
traefik:
image: traefik:2.9
container_name: traefik
restart: always
networks:
- cftunnel-transport
- cloudflaretunnel
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yaml:/traefik.yaml:ro
- ./certificates.yaml:/certificates.yaml:ro
- ./origin-certificates/:/origin-certificates:ro
networks:
cftunnel-transport:
cloudflaretunnel:
external: true
The Compose file defines a container for Traefik and a container for cloudflared. The Docker network cftunnel-transport
is used for transport between Traefik and cloudflared. The Docker network cloudflaretunnel
is used to expose Docker containers to Traefik.
To secure traffic between Traefik and cloudflared, a Cloudflare Origin Certificate is used. This can be generated in the Cloudflare dashboard and the files should be saved as mydomain.tld.pem
and mydomain.tld.key
into the origin-certificates
folder. We will instruct Traefik to secure all TLS traffic with these certificates.
tls:
stores:
default:
defaultCertificate:
certFile: /origin-certificates/mydomain.tld.pem
keyFile: /origin-certificates/mydomain.tld.key
certificates:
- certFile: /origin-certificates/mydomain.tld.pem
keyFile: /origin-certificates/mydomain.tld.key
log:
level: DEBUG
entryPoints:
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: certificates.yaml
Note that there is only a websecure
entrypoint. We don't need a HTTP entrypoint, since we will configure services in the Cloudflare Tunnel to use HTTPS for connecting to Traefik only.
Adding a service
To add a service, simply expose it as normal to Traefik.
version: '3'
services:
vaultwarden:
image: traefik/whoami
container_name: whoami
restart: always
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.mydomain.tld`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls=true
- traefik.http.routers.whoami.service=whoami
- traefik.http.services.whoami.loadbalancer.server.port=80
networks:
- cloudflaretunnel
networks:
cloudflaretunnel:
external: true
To configure a service in the Cloudflare tunnel, add simply https://traefik
as the destination. For Traefik to know which service to route the request to, we also have to specify the origin server name. Since Traefik can also speak HTTP/2, we can enable that as well.
Conclusion
Cloudflare Tunnels offer an easy way to expose a web-service securely without having to open any ports. However, using such a service has the drawback of being fully reliant on Cloudflare. It should also be noted that, while traffic between users and Cloudflare is encrypted, and traffic is encrypted between Cloudflare and your origin server, Cloudflare could still see the request contents.
Photo by Thomas Jensen on Unsplash.