Skip to content

Instantly share code, notes, and snippets.

@mattdy
Last active April 14, 2025 13:43
Show Gist options
  • Save mattdy/d741344366a4fbb86f5034adfd1ad191 to your computer and use it in GitHub Desktop.
Save mattdy/d741344366a4fbb86f5034adfd1ad191 to your computer and use it in GitHub Desktop.
Traefik on Docker Swarm accessed via Cloudflare Tunnel
Please see https://mattdyson.org/blog/2024/02/using-traefik-with-cloudflare-tunnels for a detailed write-up of this configuration
ROOT_DOMAIN=yourdomain.com
HTTP_TIMEOUT=60
POLLING_INTERVAL=10
PROPAGATION_TIMEOUT=3600
TTL=300
PROVIDERS_GOOGLE_CLIENT_ID=<GOOGLE CLIENT ID>
PROVIDERS_GOOGLE_CLIENT_SECRET=<GOOGLE CLIENT SECRET>
SECRET=RandomTextGoesHere
WHITELIST=<YOUR GOOGLE ACCOUNT EMAIL>
LOG_LEVEL=INFO
ZONE_ID=<YOUR CLOUDFLARE ZONE ID>
TUNNEL_TOKEN=<YOUR CLOUDFLARE TUNNEL TOKEN>
version: '3.7'
services:
whoami:
image: traefik/whoami
command:
- --name=externalapp
deploy:
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.external.rule=Host(`external.yourdomain.com`)"
- "traefik.http.routers.external.entrypoints=websecure"
- "traefik.http.routers.external.tls=true"
- "traefik.http.routers.external.middlewares=forward-auth"
- "traefik.http.services.external.loadbalancer.server.port=80"
- "traefik.constraint=proxy-public"
networks:
traefik:
external: true
version: '3.7'
services:
whoami:
image: traefik/whoami
command:
- --name=internalapp
deploy:
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.internal.rule=Host(`internal.yourdomain.com`)"
- "traefik.http.routers.internal.entrypoints=websecure"
- "traefik.http.routers.internal.tls=true"
- "traefik.http.services.internal.loadbalancer.server.port=80"
networks:
traefik:
external: true
version: '3.7'
services:
reverse-proxy:
image: traefik:v2.10
command:
- "--log"
- "--log.level=${LOG_LEVEL:-INFO}"
- "--log.format=json"
- "--api.insecure=true"
- "--providers.docker"
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/config"
- "--providers.file.watch=true"
- "--serversTransport.insecureSkipVerify=true" # Allow self-signed certificates for target hosts - https://doc.traefik.io/traefik/routing/overview/#insecureskipverify
- "--metrics"
- "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.tls=true"
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
- "--entrypoints.webinternal.address=:82"
- "--certificatesresolvers.letsencrypt.acme.email=<YOUR EMAIL>"
- "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/letsencrypt.json"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=300"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=8.8.8.8:53"
secrets:
- cf_token
environment:
- CLOUDFLARE_DNS_API_TOKEN_FILE=/run/secrets/cf_token
- CLOUDFLARE_HTTP_TIMEOUT=${HTTP_TIMEOUT}
- CLOUDFLARE_POLLING_INTERVAL=${POLLING_INTERVAL}
- CLOUDFLARE_PROPAGATION_TIMEOUT=${PROPAGATION_TIMEOUT}
- CLOUDFLARE_TTL=${TTL}
deploy:
restart_policy:
condition: any
delay: 5s
max_attempts: 3
window: 120s
update_config: # Start new instance before stopping existing one
delay: 10s
order: start-first
parallelism: 1
rollback_config:
parallelism: 0
order: stop-first
placement:
constraints:
- node.role == manager
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`traefik.${ROOT_DOMAIN}`)
- traefik.http.routers.api.service=api@internal
- traefik.http.routers.api.entrypoints=websecure
- traefik.http.routers.api.tls=true
- traefik.http.services.api.loadbalancer.server.port=8080
ports:
# HTTP
- target: 80
published: 80
# HTTPS
- target: 443
published: 443
# Web UI (enabled by --api.insecure=true)
- target: 8080
published: 8080
networks:
- traefik
- internal
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
- acme:/etc/traefik/acme
- traefik:/config
- cloudflare:/cloudflare
traefik-forward-auth:
image: thomseddon/traefik-forward-auth:2.1.0
networks:
- traefik
environment:
- PROVIDERS_GOOGLE_CLIENT_ID=${PROVIDERS_GOOGLE_CLIENT_ID}
- PROVIDERS_GOOGLE_CLIENT_SECRET=${PROVIDERS_GOOGLE_CLIENT_SECRET}
- SECRET=${SECRET}
- AUTH_HOST=auth.${ROOT_DOMAIN}
- COOKIE_DOMAIN=${ROOT_DOMAIN}
- WHITELIST=${WHITELIST}
deploy:
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.routers.auth.rule=Host(`auth.${ROOT_DOMAIN}`)
- traefik.http.routers.auth.entrypoints=websecure
- traefik.http.routers.auth.tls=true
- traefik.http.routers.auth.tls.domains[0].main=${ROOT_DOMAIN}
- traefik.http.routers.auth.tls.domains[0].sans=*.${ROOT_DOMAIN}
- traefik.http.routers.auth.tls.certresolver=letsencrypt
- traefik.http.routers.auth.service=auth@docker
- traefik.http.services.auth.loadbalancer.server.port=4181
- traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181
- traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true
- traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User
- traefik.http.routers.auth.middlewares=forward-auth
- traefik.constraint=proxy-public
tunnel:
container_name: cloudflared-tunnel
image: cloudflare/cloudflared
restart: unless-stopped
command: tunnel run
deploy:
mode: replicated
replicas: 3
update_config:
delay: 30s
order: start-first
monitor: 20s
networks:
- traefik
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
error-pages:
image: tarampampam/error-pages:2.26.0
environment:
TEMPLATE_NAME: l7-dark
networks:
- traefik
deploy:
mode: replicated
replicas: 2
update_config:
delay: 20s
order: start-first
monitor: 10s
labels:
- traefik.enable=true
- traefik.docker.network=traefik
# use as "fallback" for any non-registered services (with priority below normal)
- traefik.http.routers.error-pages.rule=HostRegexp(`{host:.+}`)
- traefik.http.routers.error-pages.priority=10
# should say that all of your services work on https
- traefik.http.routers.error-pages.tls='true'
- traefik.http.routers.error-pages.entrypoints=websecure
- traefik.http.routers.error-pages.middlewares=error-pages
- traefik.http.services.error-pages.loadbalancer.server.port=8080
# "errors" middleware settings
- traefik.http.middlewares.error-pages.errors.status=400-599
- traefik.http.middlewares.error-pages.errors.service=error-pages
- traefik.http.middlewares.error-pages.errors.query=/{status}.html
cloudflare-companion:
image: ghcr.io/tiredofit/docker-traefik-cloudflare-companion:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
placement:
constraints:
- node.role == manager
environment:
- TIMEZONE=Europe/London
- LOG_TYPE=CONSOLE
- LOG_LEVEL=INFO
- TRAEFIK_VERSION=2
- RC_TYPE=CNAME
- TARGET_DOMAIN=${ROOT_DOMAIN}
- REFRESH_ENTRIES=TRUE
- DOCKER_SWARM_MODE=TRUE
- ENABLE_TRAEFIK_POLL=TRUE
- TRAEFIK_POLL_URL=https://traefik.${ROOT_DOMAIN}/api
- TRAEFIK_FILTER_LABEL=traefik.constraint
- TRAEFIK_FILTER=proxy-public
- DOMAIN1=${ROOT_DOMAIN}
- DOMAIN1_ZONE_ID=${ZONE_ID}
- DOMAIN1_PROXIED=TRUE
restart: always
networks:
- internal
secrets:
- cf_token
networks:
traefik:
external: true
internal:
volumes:
acme:
traefik:
cloudflare:
secrets:
cf_token:
external: true
@mattdy
Copy link
Author

mattdy commented May 22, 2024

It's not clear to me if it's supposed to be automatically created or if I need to create it manually.

I should perhaps make this more clear in my write-up, but you shouldn't be exposing Traefik externally via Cloudflare. You need to create a local DNS entry for traefik.mydomain.com and have this pointed at the IP address of your Swarm cluster.

@possebon
Copy link

possebon commented Jun 2, 2024

Thanks @mattdy for your clarification. I managed to make it work, not exactly as your scenario, but I figured out some stuff, at least I was able to publish a nginx and expose it by traefik. On cloudflare tunnel I had to put the IP address of my host where Docker Swarm is running. When I put the stack name (service name) does not work. And I had to set also TRAEFIK_POLL_URL to HTTP not HTTPS and for the host IP. Now I need to figure out how to change everything to make work with multiple domains :-)

@NEP1192
Copy link

NEP1192 commented Nov 7, 2024

Hey @mattdy

I know its been a while since you made this, but I've run into a couple problems. I've gotten to the point DNS records are being made. But when I go to that site, I get a 1033 tunnel error. Googling it most people just say the tunnel itself isn't running. Though mine says healthy and running. I am running all this off Unraid (Linux distro) so I'm not able to follow everything 100% with the compose, as they use fields instead of compose files.

My thought is my tunnel's public hostname is incorrect. I had the service type as HTTPS and the URL originally as the private IP for the container running it, then switched it to be "traefik" the name of the container.

external.mydomain.com and traefik.mydomain.com were both made as cnames. Both giving 1033 argo tunnel errors. If you have any advice I'd be very appreciative!

@mattdy
Copy link
Author

mattdy commented Nov 7, 2024

Both giving 1033 argo tunnel errors. If you have any advice I'd be very appreciative!

Hi @NEP1192

When you view the tunnel (Network / Tunnels) within Cloudflare, does it show as 'healthy'? If not, then there's a problem with the configuration of the tunnel on your system. If it is showing 'healthy', then perhaps you've not put the correct Tunnel ID into your CNAMEs?

@NEP1192
Copy link

NEP1192 commented Nov 7, 2024

If it is showing 'healthy', then perhaps you've not put the correct Tunnel ID into your CNAMEs?

Yep put in the connector ID not the tunnel ID, thank you!

Also figured out the 404 error I was having is because I needed to add the reverse proxy inside traefik's fileConfig.yml as well.

@frntman
Copy link

frntman commented Dec 22, 2024

Hi @mattdy

My docker setup is pretty simple, and I have a healthy green tunnel, however when I start the companion container the logs are scrolling these errors and I can't figure out if this is because my public hostname for my tunnel is incorrect or if I have something else set incorrectly in my configuration?

2024-12-21T21:41:06-0600 INFO | Found Service ID: b5d138964e2a84dea9803750fa791d9946aeef27b837090a773961f57a4c8c07 with Hostname my.domain.com
Traceback (most recent call last):
  File "/usr/lib/python3.12/site-packages/requests/models.py", line 974, in json
    return complexjson.loads(self.text, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/json/decoder.py", line 338, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/json/decoder.py", line 356, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/sbin/cloudflare-companion", line 551, in <module>
    sync_mappings(get_initial_mappings(traefik_included_hosts, traefik_excluded_hosts), doms)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/sbin/cloudflare-companion", line 432, in get_initial_mappings
    add_to_mappings(mappings, check_traefik(included_hosts, excluded_hosts))
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/sbin/cloudflare-companion", line 358, in check_traefik
    for router in r.json():
                  ^^^^^^^^
  File "/usr/lib/python3.12/site-packages/requests/models.py", line 978, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)```

@mattdy
Copy link
Author

mattdy commented Dec 22, 2024

My docker setup is pretty simple, and I have a healthy green tunnel, however when I start the companion container the logs are scrolling these errors and I can't figure out if this is because my public hostname for my tunnel is incorrect or if I have something else set incorrectly in my configuration?

Hi @frntman

It's a bit difficult to know what's happening there without seeing the rest of the setup.

Have you definitely got a Traefik Router set up for your Service? From a quick look at the code, you might get an error here if the Service is found, but there's no Router specified? Try enabling debug logging and see what that says.

@hateitwtf
Copy link

hateitwtf commented Jan 22, 2025

Hi, @mattdy

having trouble with API.
With api token set to

Zone : Zone Settings : Read, Zone : Zone : Read and Zone : DNS : Edit

I'm gettin

Traceback (most recent call last): File "/usr/sbin/cloudflare-companion", line 551, in <module> sync_mappings(get_initial_mappings(traefik_included_hosts, traefik_excluded_hosts), doms) File "/usr/sbin/cloudflare-companion", line 405, in sync_mappings if point_domain(k, domain_infos): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/sbin/cloudflare-companion", line 177, in point_domain records = cf.zones.dns_records.get(domain_info['zone_id'], params={u'name': name}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/CloudFlare/cloudflare.py", line 747, in get raise CloudFlareAPIError(e=e) from None CloudFlare.exceptions.CloudFlareAPIError: Unable to authenticate request

But with full global Api key everything working. Whats missing from permissions?

@hateitwtf
Copy link

hateitwtf commented Jan 22, 2025

Oh, found solution!

You need to remove the CF_EMAIL in companion;s compose!

And no need in *. in origin server name(or add No TLS Verify option)!

Thx for awesome guide!

@frntman
Copy link

frntman commented Jan 30, 2025

Hi @frntman

It's a bit difficult to know what's happening there without seeing the rest of the setup.

Have you definitely got a Traefik Router set up for your Service? From a quick look at the code, you might get an error here if the Service is found, but there's no Router specified? Try enabling debug logging and see what that says.

Hi @mattdy,
Just wondering if this is dependent on "TRAEFIK_VERSION" as the options are 1 or 2 and I'm actually running 3 ???

@mattdy
Copy link
Author

mattdy commented Jan 30, 2025

Just wondering if this is dependent on "TRAEFIK_VERSION" as the options are 1 or 2 and I'm actually running 3 ???

I'm successfully running traefik v3 with TRAEFIK_VERSION set to 2, so this shouldn't be a problem

@jstimmer
Copy link

Thanks for the writeup. I've been struggling with acme timeout/ cloudflare propagation issues and it looks like you've got a fix in here. I'm just adapting / integrating your (wow, comprehensive) solution into what I've got but noticed one small item [TUNNEL_TOKEN] is missing from your env file.

@mattdy
Copy link
Author

mattdy commented Feb 13, 2025

noticed one small item [TUNNEL_TOKEN] is missing from your env file.

Good spot @jstimmer, thanks very much - I've updated the environment file to include that. Unfortunately cloudflared can't accept a file name containing the token yet - it looks like this functionality is in development though: cloudflare/cloudflared#645

Glad you found the writeup useful!

@kazesaurav
Copy link

@mattdy Thank you for the writeup!! trying to set it up but not using docker swarm. Below is my whole config and it throws error for companion app:

`version: '3.7'

services:
reverse-proxy:
image: traefik:v2.10
container_name: traefik1
command:
- "--log"
- "--log.level=${LOG_LEVEL:-INFO}"
- "--log.format=json"
- "--api.insecure=true"
- "--providers.docker"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/config"
- "--providers.file.watch=true"
- "--serversTransport.insecureSkipVerify=true"
- "--metrics"
- "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.tls=true"
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
- "--entrypoints.webinternal.address=:82"
- "--certificatesresolvers.letsencrypt.acme.email=EMAIL"
- "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/letsencrypt.json"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=300"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53"
environment:
- CF_DNS_API_TOKEN=${CF_TOKEN}
- CLOUDFLARE_HTTP_TIMEOUT=${HTTP_TIMEOUT}
- CLOUDFLARE_POLLING_INTERVAL=${POLLING_INTERVAL}
- CLOUDFLARE_PROPAGATION_TIMEOUT=${PROPAGATION_TIMEOUT}
- CLOUDFLARE_TTL=${TTL}
restart: always
ports:
- "80:80"
- "443:443"
- "8080:8080"
networks:
- traefik
- internal
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./acme:/etc/traefik/acme
- ./traefik:/config
- ./cloudflare:/cloudflare
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(traefik.${ROOT_DOMAIN})
- traefik.http.routers.api.service=api@internal
- traefik.http.routers.api.entrypoints=websecure
- traefik.http.routers.api.tls=true
- traefik.http.services.api.loadbalancer.server.port=8080

tunnel:
container_name: cloudflared-tunnel1
image: cloudflare/cloudflared
restart: unless-stopped
command: tunnel run
networks:
- traefik
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}

error-pages:
image: tarampampam/error-pages:2.26.0
container_name: error-pages1
environment:
TEMPLATE_NAME: l7-dark
networks:
- traefik
restart: always
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.routers.error-pages.rule=HostRegexp({host:.+})
- traefik.http.routers.error-pages.priority=10
- traefik.http.routers.error-pages.tls='true'
- traefik.http.routers.error-pages.entrypoints=websecure
- traefik.http.routers.error-pages.middlewares=error-pages
- traefik.http.services.error-pages.loadbalancer.server.port=8080
- traefik.http.middlewares.error-pages.errors.status=400-599
- traefik.http.middlewares.error-pages.errors.service=error-pages
- traefik.http.middlewares.error-pages.errors.query=/{status}.html

cloudflare-companion:
image: ghcr.io/tiredofit/docker-traefik-cloudflare-companion:latest
container_name: cloudflare-companion1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./cf_token:/run/secrets/cf_token:ro
environment:
- TIMEZONE=Asia/Kolkata
- LOG_TYPE=CONSOLE
- LOG_LEVEL=INFO
- TRAEFIK_VERSION=2
- RC_TYPE=CNAME
- TARGET_DOMAIN=${ROOT_DOMAIN}
- REFRESH_ENTRIES=TRUE
- ENABLE_TRAEFIK_POLL=TRUE
- CF_EMAIL=${YOUR_EMAIL}
- CF_TOKEN=${CF_TOKEN}
- TRAEFIK_POLL_URL=https://traefik.${ROOT_DOMAIN}/api
- TRAEFIK_FILTER_LABEL=traefik.constraint
- TRAEFIK_FILTER=proxy-public
- DOMAIN1=${ROOT_DOMAIN}
- DOMAIN1_ZONE_ID=${ZONE_ID}
- DOMAIN1_PROXIED=TRUE
restart: always
networks:
- internal

networks:
traefik:
name: traefik
external: true
internal:
name: internal

volumes:
acme:
traefik:
cloudflare:`

The error I am getting is:

cloudflare-companion1 | Traceback (most recent call last):
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/connectionpool.py", line 716, in urlopen
cloudflare-companion1 | httplib_response = self._make_request(
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/connectionpool.py", line 404, in _make_request
cloudflare-companion1 | self._validate_conn(conn)
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/connectionpool.py", line 1061, in validate_conn
cloudflare-companion1 | conn.connect()
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/connection.py", line 419, in connect
cloudflare-companion1 | self.sock = ssl_wrap_socket(
cloudflare-companion1 | ^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/util/ssl
.py", line 458, in ssl_wrap_socket
cloudflare-companion1 | ssl_sock = ssl_wrap_socket_impl(
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/util/ssl
.py", line 502, in _ssl_wrap_socket_impl
cloudflare-companion1 | return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/ssl.py", line 455, in wrap_socket
cloudflare-companion1 | return self.sslsocket_class._create(
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/ssl.py", line 1041, in _create
cloudflare-companion1 | self.do_handshake()
cloudflare-companion1 | File "/usr/lib/python3.12/ssl.py", line 1319, in do_handshake
cloudflare-companion1 | self._sslobj.do_handshake()
cloudflare-companion1 | ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1000)
cloudflare-companion1 |
cloudflare-companion1 | During handling of the above exception, another exception occurred:
cloudflare-companion1 |
cloudflare-companion1 | Traceback (most recent call last):
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/requests/adapters.py", line 667, in send
cloudflare-companion1 | resp = conn.urlopen(
cloudflare-companion1 | ^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/connectionpool.py", line 802, in urlopen
cloudflare-companion1 | retries = retries.increment(
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/urllib3/util/retry.py", line 594, in increment
cloudflare-companion1 | raise MaxRetryError(_pool, url, error or ResponseError(cause))
cloudflare-companion1 | urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='traefik.domain.com', port=443): Max retries exceeded with url: /api/api/http/routers (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1000)')))
cloudflare-companion1 |
cloudflare-companion1 | During handling of the above exception, another exception occurred:
cloudflare-companion1 |
cloudflare-companion1 | Traceback (most recent call last):
cloudflare-companion1 | File "/usr/sbin/cloudflare-companion", line 551, in
cloudflare-companion1 | sync_mappings(get_initial_mappings(traefik_included_hosts, traefik_excluded_hosts), doms)
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/sbin/cloudflare-companion", line 432, in get_initial_mappings
cloudflare-companion1 | add_to_mappings(mappings, check_traefik(included_hosts, excluded_hosts))
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/sbin/cloudflare-companion", line 356, in check_traefik
cloudflare-companion1 | r = requests.get("{}/api/http/routers".format(TRAEFIK_POLL_URL))
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/requests/api.py", line 73, in get
cloudflare-companion1 | return request("get", url, params=params, **kwargs)
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/requests/api.py", line 59, in request
cloudflare-companion1 | return session.request(method=method, url=url, **kwargs)
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/requests/sessions.py", line 589, in request
cloudflare-companion1 | resp = self.send(prep, **send_kwargs)
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/requests/sessions.py", line 703, in send
cloudflare-companion1 | r = adapter.send(request, **kwargs)
cloudflare-companion1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cloudflare-companion1 | File "/usr/lib/python3.12/site-packages/requests/adapters.py", line 698, in send
cloudflare-companion1 | raise SSLError(e, request=request)
cloudflare-companion1 | requests.exceptions.SSLError: HTTPSConnectionPool(host='traefik.domain.com', port=443): Max retries exceeded with url: /api/api/http/routers (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1000)')))

@mattdy
Copy link
Author

mattdy commented Mar 2, 2025

@kazesaurav - Unless you've obfuscated the logs, it looks like you haven't set the ROOT_DOMAIN correctly - it's trying to connect to "traefik.domain.com"

@1kazekage
Copy link

@kazesaurav - Unless you've obfuscated the logs, it looks like you haven't set the ROOT_DOMAIN correctly - it's trying to connect to "traefik.domain.com"

It's obfuscated.

@mattdy
Copy link
Author

mattdy commented Mar 3, 2025

It's obfuscated.

In that case, it looks like there's an issue with verifying your SSL certificate for that domain, I'd check that the certificate is being provisioned properly by Traefik

@kazesaurav
Copy link

kazesaurav commented Mar 5, 2025

@mattdy got the SSL working, but companion is failing to authenticate with cloudflare:

2025-03-06.01:00:14 [STARTING] ** [traefik-cloudflare-companion] [6] Starting Traefik Cloudflare Companion

2025-03-06T01:00:14+0530 INFO | Found Service ID: {obfuscate} with Hostname webtop.{obfuscate}

Traceback (most recent call last):

File "/usr/sbin/cloudflare-companion", line 551, in

sync_mappings(get_initial_mappings(traefik_included_hosts, traefik_excluded_hosts), doms)

File "/usr/sbin/cloudflare-companion", line 405, in sync_mappings

if point_domain(k, domain_infos):

   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/usr/sbin/cloudflare-companion", line 177, in point_domain

records = cf.zones.dns_records.get(domain_info['zone_id'], params={u'name': name})

          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/usr/lib/python3.12/site-packages/CloudFlare/cloudflare.py", line 747, in get

raise CloudFlareAPIError(e=e) from None

CloudFlare.exceptions.CloudFlareAPIError: Unable to authenticate request

2025-03-06.01:00:16 [STARTING] ** [traefik-cloudflare-companion] [7] Starting Traefik Cloudflare Companion

2025-03-06T01:00:16+0530 INFO | Found Service ID: {obfuscate} with Hostname webtop.{obfuscate}

Traceback (most recent call last):

File "/usr/sbin/cloudflare-companion", line 551, in

sync_mappings(get_initial_mappings(traefik_included_hosts, traefik_excluded_hosts), doms)

File "/usr/sbin/cloudflare-companion", line 405, in sync_mappings

if point_domain(k, domain_infos):

   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/usr/sbin/cloudflare-companion", line 177, in point_domain

records = cf.zones.dns_records.get(domain_info['zone_id'], params={u'name': name})

          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/usr/lib/python3.12/site-packages/CloudFlare/cloudflare.py", line 747, in get

raise CloudFlareAPIError(e=e) from None

CloudFlare.exceptions.CloudFlareAPIError: Unable to authenticate request

My config for companion app:

cloudflare-companion:
image: ghcr.io/tiredofit/docker-traefik-cloudflare-companion:latest
container_name: cloudflare-companion2
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# - ./cf-token:/run/secrets/cf-token:ro
environment:
- TIMEZONE=Asia/Kolkata
- LOG_TYPE=CONSOLE
- LOG_LEVEL=INFO
- TRAEFIK_VERSION=2
- CF_EMAIL={obfuscate}
- CF_TOKEN={obfuscate}
- RC_TYPE=CNAME
- CF_DNS_API_TOKEN={obfuscate}
- TARGET_DOMAIN=htb.in.net
- REFRESH_ENTRIES=TRUE
- DOCKER_SWARM_MODE=FALSE
- ENABLE_TRAEFIK_POLL=TRUE
- TRAEFIK_POLL_URL=https://traefik.${ROOT_DOMAIN}/api
- TRAEFIK_FILTER_LABEL=traefik.constraint
- TRAEFIK_FILTER=proxy-public
- DOMAIN1={obfuscate}
- DOMAIN1_ZONE_ID={obfuscate}
- DOMAIN1_PROXIED=TRUE
restart: always
networks:
- internal

@kazesaurav
Copy link

@mattdy okay I see it authenticated now but seeing below error:

Max retries exceeded with url: /api/api/http/routers (Caused by SSLError(SSLError(1, '[SSL: TLSV1_UNRECOGNIZED_NAME] tlsv1 unrecognized name (_ssl.c:1000)')))

@jstimmer
Copy link

jstimmer commented Mar 6, 2025

@mattdy okay I see it authenticated now but seeing below error:

Max retries exceeded with url: /api/api/http/routers (Caused by SSLError(SSLError(1, '[SSL: TLSV1_UNRECOGNIZED_NAME] tlsv1 unrecognized name (_ssl.c:1000)')))

I had so many issues with acme that I just disabled it and only manage DNS (direct CNAME) records via cloudflare-companion and left SSL to be sorted out by Cloudflare but allowing https through the tunnel (using no TLSVerify and 443 on CF tunnel path | CF SSL/TLS: Full (strict) and edge certificates: 'always use HTTPS' & 'automatic HTTPS rewrites' set to true.)

@1kazekage
Copy link

@mattdy okay I see it authenticated now but seeing below error:
Max retries exceeded with url: /api/api/http/routers (Caused by SSLError(SSLError(1, '[SSL: TLSV1_UNRECOGNIZED_NAME] tlsv1 unrecognized name (_ssl.c:1000)')))

I had so many issues with acme that I just disabled it and only manage DNS (direct CNAME) records via cloudflare-companion and left SSL to be sorted out by Cloudflare but allowing https through the tunnel (using no TLSVerify and 443 on CF tunnel path | CF SSL/TLS: Full (strict) and edge certificates: 'always use HTTPS' & 'automatic HTTPS rewrites' set to true.)

Did you do this config only on Cloudflare portal or something on docker compose as well, if you can help on that.

@mattdy
Copy link
Author

mattdy commented Mar 6, 2025

@mattdy okay I see it authenticated now but seeing below error:

Max retries exceeded with url: /api/api/http/routers (Caused by SSLError(SSLError(1, '[SSL: TLSV1_UNRECOGNIZED_NAME] tlsv1 unrecognized name (_ssl.c:1000)')))

Maybe try without /api at the end of TRAEFIK_POLL_URL? Other than that, I'm afraid I don't know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment