Cockpit behind traefik

Howdy,

I managed to solve this problem thanks to a few other resources and finally this thread!

In my case I had:

  • cockpit-ws (provided alongside my Centos 9) on the host
  • traefik v3 running in Docker as a container

The goal is to make cockpit-ws operate in non-ssl or HTTP only mode and have it only accessible on localhost and to docker. Then we let traefik talk to cockpit-ws to show it on my domain at cockpit.example.com via HTTPS only.

This is the setup (create any files that don't already exist).

/etc/systemd/system/cockpit.socket.d/listen.conf

[Socket]
ListenStream=
ListenStream=127.0.0.1:9090
ListenStream=172.17.0.1:9090
FreeBind=yes

From the TCP Port and Address docs, we make cockpit only accessible on localhost (127.0.0.1) and docker (172.17.0.1) .

Don't use 0.0.0.0 because then you're exposing it to the internet with HTTP on your servers IP!

After modifying this file, run:

sudo systemctl daemon-reload
sudo systemctl restart cockpit.socket

/etc/cockpit/cockpit.conf

[WebService]
Origins = http://cockpit.example.com ws://cockpit.example.com https://cockpit.example.com wss://cockpit.example.com
ProtocolHeader = X-Forwarded-Proto
AllowUnencrypted=true

Replace the example subdomain with your own. Origins and ProtocolHeader are required to allow a successful connection post login. Cockpit enforces a HTTPS requirement for non local host addresses so we allow HTTP by setting AllowUnencrypted.

After modifying this file, run:

sudo systemctl restart cockpit

traefik/compose.yml

services:
  traefik:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik_static.yml:/etc/traefik/traefik.yml
      - ./dynamic:/etc/traefik/dynamic
    extra_hosts:
      - "host.docker.internal:host-gateway"
    networks:
      - web
    restart: unless-stopped

networks:
  web:
    external: true

Set extra_hosts to bind host.docker.internal to host-gateway.
Note: If you don't want to do this you can also use the 172.17.0.1 directly to refer to the host from inside docker containers but this is not recommended.

traefik_dynamic.yml

# Cockpit setup
http:
  routers:
    cockpit:
      rule: "Host(`cockpit.example.com`)"
      entrypoints:
        - https
      tls: true
      service: cockpit-service

  services:
    cockpit-service:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:9090"

Add the above to your dynamic config. Replace the example subdomain with your own. Don't forget to setup the tls certificates as you normally would for this subdomain (not included in above config).

Note: You can use 172.17.0.1 here if you didn't want to use extra_hosts in previous step.


Test everything

Redeploy traefik on docker if needed, then test.
Make sure cockpit is working from your subdomain and localhost via curl. :slight_smile: