Traefik+docker socket proxy / doesn't seems to work

Hello,
I am trying to make working the docker socket proxy.
My docker-compose file:

version: '3.8'
services:
  docker-socket-proxy:
    container_name: docker-socket-proxy
    image: tecnativa/docker-socket-proxy
    privileged: true
    restart: always
    logging:
      driver: journald
    environment:
      - CONTAINERS=1
    networks:
      - proxy
    ports:
      - 127.0.0.1:2375:2375
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
  traefik:
    image: traefik:v3.0
    container_name: traefik
    #command: 
      #- "--providers.docker.endpoint=tcp://docker-socket-proxy:2375"
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 1180:80
      - 11443:443
      - 8087:8080
      - 1181:1181
      - 11444:11444
    environment:
      - CF_API_EMAIL=my email
      - CF_DNS_API_TOKEN=nejxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-
      - TZ=Europe/Helsinki
      - DOCKER_HOST=tcp://docker-socket-proxy:2375
    volumes:
      - /etc/localtime:/etc/localtime:ro
      #- /var/run/docker.sock:/var/run/docker.sock:ro
      - /mnt/user/appdata/docker/traefik/data/traefik.yml:/traefik.yml:ro
      - /mnt/user/appdata/docker/letsencrypt:/letsencrypt
      - /mnt/user/appdata/docker/traefik/data/dynamic_conf.yml:/dynamic_conf.yml:ro
      - /var/log/crowdsec/:/var/log/crowdsec
    
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.mydomain.tld`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.mydomain.tld`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=dns-cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=mydomain.tld"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.mydomain.tld"
      - "traefik.http.routers.traefik-secure.service=api@internal"

      # middlewares
      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:passwd"
      # middlewares security headers
      - "traefik.http.middlewares.security-headers.headers.accesscontrolallowmethods=GET, OPTIONS, PUT"
      - "traefik.http.middlewares.security-headers.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.security-headers.headers.addvaryheader=true"
      - "traefik.http.middlewares.security-headers.headers.hostsproxyheaders=X-Forwarded-Host"
      - "traefik.http.middlewares.security-headers.headers.sslredirect=true"
      - "traefik.http.middlewares.security-headers.headers.sslproxyheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.security-headers.headers.stsseconds=63072000"
      - "traefik.http.middlewares.security-headers.headers.stsincludesubdomains=true"
      - "traefik.http.middlewares.security-headers.headers.stspreload=true"
      - "traefik.http.middlewares.security-headers.headers.forcestsheader=true"
      - "traefik.http.middlewares.security-headers.headers.framedeny=true"
      - "traefik.http.middlewares.security-headers.headers.contenttypenosniff=true"
      - "traefik.http.middlewares.security-headers.headers.browserxssfilter=true"
      - "traefik.http.middlewares.security-headers.headers.referrerpolicy=same-origin"
      - "traefik.http.middlewares.security-headers.headers.featurepolicy=camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
      - "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Robots-Tag=none,noarchive,nosnippet,notranslate,noimageindex"
  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=http"

  
networks:
  proxy:
    external: true

When looking at the server who run all my dockers, I can see:

#netstat -tunlp
tcp        0      0 127.0.0.1:2375          0.0.0.0:*               LISTEN      563720/docker-proxy

When checking the traefik web management page:

	
Host(`whoami.localhost`)	http    whoami@docker	  whoami-traefik	24

There is no, as you can see, there is no service "whoami-docker-socket-proxy" as it should be ...

I am running out of ideas ....

Thx

You are doing it wrong, multiple ways. I am sure there are at least 5 good tutorials out there, did you check those?

Tecnativa socket proxy is crap, because they are too dumb or lazy to update their latest image (link). So all the people not using a version tag will get a 3 year old image with outdated haproxy, not sure if that really increases the security. And I did try to inform them (link). Sorry, they make me mad.

Have a socket network your share with Traefik and socket-proxy, the socket-proxy does not need to open ports. Set providers.docker.endpoint=tcp://socket-proxy-service-name:port.

Use a separate proxy network for Traefik and the target services. Set providers.docker.network=proxy

Docker Swarm example with self-made socket-proxy. Not sure if that works, just for concept, note that Swarm has labels under deploy section and the required URLs are a bit different.

version: '3.9'

services:
  traefik:
    image: traefik:v2.11
    hostname: '{{.Node.Hostname}}'
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
    networks:
      - proxy
      - socket
    volumes:
      #- /var/log:/var/log
      - letsencrypt:/letsencrypt
    command:
      - --api.dashboard=true
      - --ping
      - --log.level=DEBUG
      #- --log.filepath=/var/log/traefik.log
      - --accesslog=true
      #- --accesslog.filepath=/var/log/traefik-access.log
      #- --providers.docker.swarmMode=true
      - --providers.docker.network=proxy
      - --providers.docker.exposedByDefault=false
      - --providers.docker.endpoint=tcp://socketproxy:2375
      - --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.certresolver=myresolver
      - --certificatesresolvers.myresolver.acme.email=mail@example.com
      - --certificatesresolvers.myresolver.acme.tlschallenge=true
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
      labels:
        - traefik.enable=true
        - traefik.http.routers.mydashboard.rule=Host(`traefik.example.com`)
        - traefik.http.routers.mydashboard.service=api@internal
        - traefik.http.routers.mydashboard.middlewares=myauth
        - traefik.http.services.mydashboard.loadbalancer.server.port=1337
        - traefik.http.middlewares.myauth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/ping"]
      interval: 30s
      timeout: 3s
      start_period: 5s

  whoami:
    image: traefik/whoami:v1.10
    hostname: '{{.Node.Hostname}}'
    networks:
      - proxy
    deploy:
      mode: global
      labels:
        - 'traefik.enable=true'
        - 'traefik.http.routers.whoami.rule=Host(`whoami.example.com`) || PathPrefix(`/whoami`)'
        - 'traefik.http.services.whoami.loadbalancer.server.port=80'

  socketproxy:
    image: node:lts-alpine
    hostname: '{{.Node.Hostname}}'
    networks:
      - socket
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        cat <<EOF > server.js
        const http = require('http')

        const prefixes = [
          '/v1.24/services',
          '/v1.24/version',
          '/v1.24/networks',
          '/v1.24/tasks'
        ]

        const server = http.createServer((req, res) => {
            if (process.env.LOG) {
              console.log(new Date().toISOString(), req.method, req.url)
            }

            if (req.method != 'GET' || !prefixes.some(prefix => req.url.startsWith(prefix))) {
              console.log(new Date().toISOString(), 'FORBIDDEN', req.method, req.url)
              res.statusCode = 403
              res.end('Forbidden: ' + req.method + ' ' + req.url)
              return
            }

            const options = {
                socketPath: '/var/run/docker.sock',
                method: req.method,
                path: req.url,
                headers: req.headers,
            }

            const proxy = http.request(options, (targetRes) => {
                res.writeHead(targetRes.statusCode, targetRes.headers)
                targetRes.pipe(res, { end: true })
            })

            proxy.on('error', (err) => {
                console.log(new Date().toISOString(), 'Proxy error:', err)
                res.statusCode = 500
                res.end('Server error')
            })

            req.pipe(proxy, { end: true })
        })

        server.listen(2375, '0.0.0.0', () => {
            console.log('Server running on port 2375')
        })
        EOF
        node server.js
    expose:
      - 2375
    environment:
      - LOG=true

networks:
  proxy:
    name: proxy
    attachable: true

  socket:
    name: socket
    attachable: true


volumes:
  letsencrypt:
    name: letsencrypt

You can use tecnative, but please add a version tag to the image name, and you should not use ports and should not need privileged.

Hi,
Harsh answer no ?
I have followed your pro advises.
To be a bit more clear, I have separated both dockers:

services:
  socketproxy:
    image: node:lts-alpine
    hostname: '{{.Node.Hostname}}'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      mode: global
      placement:
        constraints:
          - node.role==manager
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        cat <<EOF > server.js
        const http = require('http')

        const prefixes = [
          '/v1.24/services',
          '/v1.24/version',
          '/v1.24/networks',
          '/v1.24/tasks'
        ]

        const server = http.createServer((req, res) => {
            if (process.env.LOG) {
              console.log(new Date().toISOString(), req.method, req.url)
            }

            if (req.method != 'GET' || !prefixes.some(prefix => req.url.startsWith(prefix))) {
              console.log(new Date().toISOString(), 'FORBIDDEN', req.method, req.url)
              res.statusCode = 403
              res.end('Forbidden: ' + req.method + ' ' + req.url)
              return
            }

            const options = {
                socketPath: '/var/run/docker.sock',
                method: req.method,
                path: req.url,
                headers: req.headers,
            }

            const proxy = http.request(options, (targetRes) => {
                res.writeHead(targetRes.statusCode, targetRes.headers)
                targetRes.pipe(res, { end: true })
            })

            proxy.on('error', (err) => {
                console.log(new Date().toISOString(), 'Proxy error:', err)
                res.statusCode = 500
                res.end('Server error')
            })

            req.pipe(proxy, { end: true })
        })

        server.listen(2375, '0.0.0.0', () => {
            console.log('Server running on port 2375')
        })
        EOF
        node server.js
    expose:
      - 2375
    environment:
      - LOG=true
networks:
  proxy_net:
    internal: true
    name: proxy_net
  socket:
    name: socket
    attachable: true
volumes:
  letsencrypt:
    name: letsencrypt
services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - mynet
      - proxy_net
    ports:
      - 1180:80
      - 11443:443
      - 8087:8080
      - 1181:1181
      - 11444:11444
    environment:
      - CF_API_EMAIL=emaiol
      - CF_DNS_API_TOKEN=nejxxxxxxxxxxxxxxxxxxxxxxxxxxxxxB-
      - TZ=Europe/Helsinki
    volumes:
      - /etc/localtime:/etc/localtime:ro
      #- /var/run/docker.sock:/var/run/docker.sock:ro
      - /mnt/user/appdata/docker/traefik/data/traefik.yml:/traefik.yml:ro
      - /mnt/user/appdata/docker/letsencrypt:/letsencrypt
      - /mnt/user/appdata/docker/traefik/data/dynamic_conf.yml:/dynamic_conf.yml:ro
      - /var/log/crowdsec/:/var/log/crowdsec
    command: 
      - "--providers.docker.endpoint=tcp://dockerproxy:2375"
      - "--providers.docker.network=proxy_net"

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.domain.tld`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.domain.tld`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=dns-cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=domain.tld"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.domain.tld"
      - "traefik.http.routers.traefik-secure.service=api@internal"

      # middlewares
      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:passwd"
      # middlewares security headers
      - "traefik.http.middlewares.security-headers.headers.accesscontrolallowmethods=GET, OPTIONS, PUT"
      - "traefik.http.middlewares.security-headers.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.security-headers.headers.addvaryheader=true"
      - "traefik.http.middlewares.security-headers.headers.hostsproxyheaders=X-Forwarded-Host"
      - "traefik.http.middlewares.security-headers.headers.sslredirect=true"
      - "traefik.http.middlewares.security-headers.headers.sslproxyheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.security-headers.headers.stsseconds=63072000"
      - "traefik.http.middlewares.security-headers.headers.stsincludesubdomains=true"
      - "traefik.http.middlewares.security-headers.headers.stspreload=true"
      - "traefik.http.middlewares.security-headers.headers.forcestsheader=true"
      - "traefik.http.middlewares.security-headers.headers.framedeny=true"
      - "traefik.http.middlewares.security-headers.headers.contenttypenosniff=true"
      - "traefik.http.middlewares.security-headers.headers.browserxssfilter=true"
      - "traefik.http.middlewares.security-headers.headers.referrerpolicy=same-origin"
      - "traefik.http.middlewares.security-headers.headers.featurepolicy=camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
      - "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Robots-Tag=none,noarchive,nosnippet,notranslate,noimageindex"
  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=http"

networks:
  mynet:
    external: true
  proxy_net:
    internal: true

Doesn(t work ....
There might be a problem with the proxy network, when checking the network in my portainer regarding my docker proxy ... His IP is on 192.168.XXX.XXX ....
And on the server running all my dockers, there is no "port 2375" listenning.

Thx

Try tecnativa, but make sure to add an image version tag like edge.

version: '3.9'

services:
  traefik:
    image: traefik:v2.11
    ports:
      - 80:80
      - 443:443
    networks:
      - socket
      - proxy
    volumes:
      - letsencrypt:/letsencrypt
      #- /var/log:/var/log
    command:
      - --api.dashboard=true
      - --log.level=INFO
      #- --log.filepath=/var/log/traefik.log
      - --accesslog=true
      #- --accesslog.filepath=/var/log/traefik-access.log
      - --providers.docker.endpoint=tcp://socketproxy:2375
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=proxy
      - --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.certresolver=myresolver
      - --certificatesresolvers.myresolver.acme.email=mail@example.com
      - --certificatesresolvers.myresolver.acme.tlschallenge=true
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
    labels:
      - traefik.enable=true
      - traefik.http.routers.mydashboard.rule=Host(`traefik.example.com`)
      - traefik.http.routers.mydashboard.service=api@internal
      - traefik.http.routers.mydashboard.middlewares=myauth
      - traefik.http.middlewares.myauth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/

  socketproxy:
    image: tecnativa/docker-socket-proxy:edge
    networks:
      - socket
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - LOG_LEVEL=warning
      - EVENTS=1
      - PING=1
      - VERSION=1
      - CONTAINERS=1

  whoami:
    image: traefik/whoami:v1.10
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.mywhoami.rule=Host(`whoami.example.com`) || PathPrefix(`/whoami`)
      - traefik.http.services.mywhoami.loadbalancer.server.port=80

networks:
  proxy:
    name: proxy
  socket:
    name: socket

volumes:
  letsencrypt:
    name: letsencrypt

Hi and thx again for your support.
I have merged all dockers used for this:

services:
  socketproxy:
    image: demyx/docker-socket-proxy:latest
    container_name: dockersocket
    networks:
      - socket
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - LOG_LEVEL=warning
      - EVENTS=1
      - PING=1
      - VERSION=1
      - CONTAINERS=1

  whoami:
    image: traefik/whoami:v1.10
    networks:
      - mynet
    labels:
      - traefik.enable=true
      - traefik.http.routers.mywhoami.rule=Host(`whoami.example.com`) || PathPrefix(`/whoami`)
      - traefik.http.services.mywhoami.loadbalancer.server.port=http

  
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - mynet
      - socket
    ports:
      - 1180:80
      - 11443:443
      - 8087:8080
      - 1181:1181
      - 11444:11444
    environment:
      - CF_API_EMAIL=email
      - CF_DNS_API_TOKEN=nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzB-
      - TZ=Europe/Helsinki
    volumes:
      - /etc/localtime:/etc/localtime:ro
      #- /var/run/docker.sock:/var/run/docker.sock:ro
      - /mnt/user/appdata/docker/traefik/data/traefik.yml:/traefik.yml:ro
      - /mnt/user/appdata/docker/letsencrypt:/letsencrypt
      - /mnt/user/appdata/docker/traefik/data/dynamic_conf.yml:/dynamic_conf.yml:ro
      - /var/log/crowdsec/:/var/log/crowdsec
    command: 
      - "--providers.docker.endpoint=tcp://dockersocket:2375"
      - "--providers.docker.network=socket"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.mynet-tld.org`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.mynet-tld.org`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=dns-cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=mynet-tld.org"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.mynet-tld.org"
      - "traefik.http.routers.traefik-secure.service=api@internal"

      # middlewares
      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:passwwd"
      # middlewares security headers
      - "traefik.http.middlewares.security-headers.headers.accesscontrolallowmethods=GET, OPTIONS, PUT"
      - "traefik.http.middlewares.security-headers.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.security-headers.headers.addvaryheader=true"
      - "traefik.http.middlewares.security-headers.headers.hostsproxyheaders=X-Forwarded-Host"
      - "traefik.http.middlewares.security-headers.headers.sslredirect=true"
      - "traefik.http.middlewares.security-headers.headers.sslproxyheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.security-headers.headers.stsseconds=63072000"
      - "traefik.http.middlewares.security-headers.headers.stsincludesubdomains=true"
      - "traefik.http.middlewares.security-headers.headers.stspreload=true"
      - "traefik.http.middlewares.security-headers.headers.forcestsheader=true"
      - "traefik.http.middlewares.security-headers.headers.framedeny=true"
      - "traefik.http.middlewares.security-headers.headers.contenttypenosniff=true"
      - "traefik.http.middlewares.security-headers.headers.browserxssfilter=true"
      - "traefik.http.middlewares.security-headers.headers.referrerpolicy=same-origin"
      - "traefik.http.middlewares.security-headers.headers.featurepolicy=camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
      - "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Robots-Tag=none,noarchive,nosnippet,notranslate,noimageindex"
networks:
  mynet-tld:
    name: mynet
    external: true
  socket:
    internal: true
    name: socket

I have replace Tecnativa with Demyx ... But the problem still ...
No port 2375 is listenning.

I am using proxmox and I think there might be a problem to enable TCP port 2375 for external use ...
I have done things on the file "daemon.json" without any sccess .... Or there is again a pb with my config ...

This needs to be the network that Traefik uses to forward requests to target services.

Why would you enable Docker Socket externally? It should all happen inside the compose setup.

My last example was a working version, so start from there.

I have traefik and tecnativa:edge running.

I have read the OWASP Docker cheatsheet (#1):

Do not expose /var/run/docker.sock to other containers
It seems to be fixed by tecnativa

Do not enable tcp Docker daemon socket If you are running docker daemon with -H tcp://0.0.0.0:XXX or similar you are exposing un-encrypted and unauthenticated direct access to the Docker daemon

In my opinion this exactly happens: tcp://socketproxy:2375

Am'I right? I'm new to docker/traefik, I don't want to run into security issues.

Thx

Hope this time the config is ok:

services:
  socketproxy:
    image: tecnativa/docker-socket-proxy:edge
    container_name: dockersocket
    networks:
      - socket
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - LOG_LEVEL=warning
      - EVENTS=1
      - PING=1
      - VERSION=1
      - CONTAINERS=1

  whoami:
    image: traefik/whoami:v1.10
    networks:
      - mynet
    labels:
      - traefik.enable=true
      - traefik.http.routers.mywhoami.rule=Host(`whoami.example.com`) || PathPrefix(`/whoami`)
      - traefik.http.services.mywhoami.loadbalancer.server.port=http

  
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - mynet
      - socket
    ports:
      - 1180:80
      - 11443:443
      - 8087:8080
      - 1181:1181
      - 11444:11444
    environment:
      - CF_API_EMAIL=email
      - CF_DNS_API_TOKEN=nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzB-
      - TZ=Europe/Helsinki
    volumes:
      - /etc/localtime:/etc/localtime:ro
      #- /var/run/docker.sock:/var/run/docker.sock:ro
      - /mnt/user/appdata/docker/traefik/data/traefik.yml:/traefik.yml:ro
      - /mnt/user/appdata/docker/letsencrypt:/letsencrypt
      - /mnt/user/appdata/docker/traefik/data/dynamic_conf.yml:/dynamic_conf.yml:ro
      - /var/log/crowdsec/:/var/log/crowdsec
    command: 
      - --providers.docker.endpoint=tcp://dockersocket:2375
      - --providers.docker.network=mynet
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.mynet-tld.org`)"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.mynet-tld.org`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=dns-cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=mynet-tld.org"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.mynet-tld.org"
      - "traefik.http.routers.traefik-secure.service=api@internal"

      # middlewares
      - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:passwwd"
      # middlewares security headers
      - "traefik.http.middlewares.security-headers.headers.accesscontrolallowmethods=GET, OPTIONS, PUT"
      - "traefik.http.middlewares.security-headers.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.security-headers.headers.addvaryheader=true"
      - "traefik.http.middlewares.security-headers.headers.hostsproxyheaders=X-Forwarded-Host"
      - "traefik.http.middlewares.security-headers.headers.sslredirect=true"
      - "traefik.http.middlewares.security-headers.headers.sslproxyheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.security-headers.headers.stsseconds=63072000"
      - "traefik.http.middlewares.security-headers.headers.stsincludesubdomains=true"
      - "traefik.http.middlewares.security-headers.headers.stspreload=true"
      - "traefik.http.middlewares.security-headers.headers.forcestsheader=true"
      - "traefik.http.middlewares.security-headers.headers.framedeny=true"
      - "traefik.http.middlewares.security-headers.headers.contenttypenosniff=true"
      - "traefik.http.middlewares.security-headers.headers.browserxssfilter=true"
      - "traefik.http.middlewares.security-headers.headers.referrerpolicy=same-origin"
      - "traefik.http.middlewares.security-headers.headers.featurepolicy=camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
      - "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Robots-Tag=none,noarchive,nosnippet,notranslate,noimageindex"
networks:
  mynet:
    name: mynet
    external: true
  socket:
    name: socket

You should not expose Docker socket. A malicious actor could use it to spy on secrets and launch/delete containers.

But Traefik need access to enable automatic configuration discovery.

Instead of giving Traefik, which is the first line of access from the Internet for bad actors, full access to Docker socket, you only give a socket proxy access to the Docker socket.

The socket proxy can restrict services (no secrets) and methods (no POST, only GET).

The socket proxy is connected to a Docker network, which is only shared with Traefik. No other service should have access.

So in the end Traefik should have restrictive access to the Docker socket.

On the other side you increase your attack surface by adding another service from a supplier you don’t know and you can’t be sure how locked down their processes are. Tecnative can’t even update their latest Docker image - it seems for years.

Workaround for that: create you own Docker proxy by creating a simple config for nginx or haproxy (not Traefik in case it already got hijacked). Or write your own code.

2 Likes

@bluepuma77 is right with his opinion about tecnativa/docker-socket-proxy.

I was not happy with this either, so I created my own socket proxy a few months ago. Works great for me.

See GitHub - wollomatic/socket-proxy: A secure unix socket proxy. Similar to tecnativa/docker-socket-proxy, but more flexible and written in Go with no dependencies (and find it on Docker Hub)

And this is my example for a hardened Traefik deployment: GitHub - wollomatic/traefik-hardened: hardened rootless Traefik v2 deployment without mounting the Docker socket into the Traefik container

Hi and thx for your help.
I think that @bluepuma77 hasn't understand yet that I do not have any skills on development :frowning: And I know is right :slight_smile:
I have add in /etc:default/docker the value DOCKER_OPTS="-H unix:///var/run/docker.sock"

I have done as you ... Traefik is still working has it should be, web service is still accessible from outside, but how to check if what I have done is working ??
Thx again to both [of you @bluepuma77 and @wollomatic)

1 Like

Hi,

if you use wollomatic/socket-proxy, you can set the socket-proxy's log level to debug ('-loglevel=debug'). Then, socket-proxy logs all requests (allowed and blocked) to the standard output.

With the configuration of my example repo, there should not be any blocked traffic. Every time a container starts or stops (so that the traefik docker provider is informed about the configuration change), you should see some activity.

With log level info, only blocked requests are logged.

(Only the requested path is logged, there is no logging of the request body, if any)

BTW tecnativa released a new version of tecnativa/docker-socket-proxy yesterday.

lol

I have add the "debug" mode in your proxysocket but:

root@proxmox-ve:/var/log# docker exec -it 172d604b9468 sh
OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown

Is there any shell available in your socket proxy ??

Thx

No, due to security reasons there is no shell in the container.

Hopefully the right people control the Docker Hub account.

That's why I sign my docker images :wink:

Depending on your Docker environment, you could view the logs with docker logs -f containername.

I really appreciate your answer. In the end tecnativa should do the work.

About the quoted lines: I'm a database engineer, I do not have the experience yet to create a proxy by myself