# Expose docker service locally and publicly

**URL:** <https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398>\
**Category:** Traefik v2\
**Tags:** tcp, docker\
**Created:** [February 2, 2023, 2:33pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398 "2023-02-02T14:33:06Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![williamwoldum](https://avatars.discourse-cdn.com/v4/letter/w/f08c70/32.png) [@williamwoldum](https://community.traefik.io/u/williamwoldum)\
**Post date:** [February 2, 2023, 2:33pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/1 "2023-02-02T14:33:06Z")

</div>

Hi everyone\   
I have a couple of services (vaultwarden and homepage) that I want to access both publically via:  
`vaultwarden.example.com` and `homepage.example.com`

And locally via:  
`vaultwarden.local.example.com` and `homepage.local.example.com`

The `.local` domains are DNS entries in my pihole pointing to my local server ip running traefik

The public domains are exposed via Cloudflare tunnels and map the domain to a port on my local server.

This is my traefik docker-compose file:

```auto
version: '3'

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_API_EMAIL=REDACTED
      - CF_API_KEY=REDACTED
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/pi/traefik/data/traefik.yml:/traefik.yml:ro
      - /home/pi/traefik/data/acme.json:/acme.json
      - /home/pi/traefik/data/config.yml:/config.yml:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik.local.example.com`)"

      - "traefik.http.middlewares.traefik-auth.basicauth.users=REDACTED"
      - "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.local.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=local.example.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.local.example.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true

```

This is the traefic.yml file:

```auto
accessLog: {}
log:
  level: DEBUG
api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
  https:
    address: ":443"
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yml
certificatesResolvers:
  cloudflare:
    acme:
      email: REDACTED
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        #disablePropagationCheck: true # uncomment this if you have issues pulling certificates through cloudflare, By setting this flag to true disables the need to wait for the propagation of the TXT record to all authoritative name servers.
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

```

Setting up ´vaultwarden` works perfectly fine. If I explicitly map port 8080 to 80 I can access the service via the public and local domain. Set up like this:

```auto
version: '3'

services:
  vaultwarden:
    image: vaultwarden/server
    container_name: vaultwarden
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - "8080:80"
    volumes:
      - ./vw-data/:/data/
    environment:
      - ADMIN_TOKEN=REDACTED
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.entrypoints=http"
      - "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.local.example.dev`)"
      - "traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.vaultwarden.middlewares=vaultwarden-https-redirect"
      - "traefik.http.routers.vaultwarden-secure.entrypoints=https"
      - "traefik.http.routers.vaultwarden-secure.rule=Host(`vaultwarden.local.example.dev`)"
      - "traefik.http.routers.vaultwarden-secure.tls=true"
      - "traefik.http.routers.vaultwarden-secure.service=vaultwarden"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

```

However, if I do the exact same thing setting up `homepage` I get a 502 error on both domains. This is the traefik log:\

```auto
time="2023-02-02T15:14:22+01:00" level=debug msg="'502 Bad Gateway' caused by: dial tcp 172.20.0.2:80: connect: connection refused"
10.0.0.5 - - [02/Feb/2023:14:14:22 +0000] "GET / HTTP/2.0" 502 11 "-" "-" 3739 "homepage-secure@docker" "http://172.20.0.2:80" 2ms

```

```auto
version: "3"
services:
  homepage:
    image: ghcr.io/benphelps/homepage:latest
    container_name: homepage
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - "3000:80"
    volumes:
      - /home/pi/homepage/config:/app/config # Make sure your local config directory exists
      - /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.homepage.entrypoints=http"
      - "traefik.http.routers.homepage.rule=Host(`homepage.local.example.dev`)"
      - "traefik.http.middlewares.homepage-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.homepage.middlewares=homepage-https-redirect"
      - "traefik.http.routers.homepage-secure.entrypoints=https"
      - "traefik.http.routers.homepage-secure.rule=Host(`homepage.local.example.dev`)"
      - "traefik.http.routers.homepage-secure.tls=true"
      - "traefik.http.routers.homepage-secure.service=homepage"
      - "traefik.http.services.homepage.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"
networks:
  proxy:
    external: true

```

I know the container works because different ip configs let me access the service via one or the other domains.

```auto
# Neither domains work
ports:
  - "3000:80"
labels:
  - "traefik.http.services.homepage.loadbalancer.server.port=80"

# Only works with local domain
ports:
  - "3000:80"
labels:
  - "traefik.http.services.homepage.loadbalancer.server.port=3000"

# Also only works with local domain (no port mapping specified)
labels:
  - "traefik.http.services.homepage.loadbalancer.server.port=3000"

# Only works with public domain
ports:
  - "3000:3000"
labels:
  - "traefik.http.services.homepage.loadbalancer.server.port=3000"

# Also only works with public domain
ports:
  - "3000:3000"
labels:
  - "traefik.http.services.homepage.loadbalancer.server.port=80"

```

Does anyone have a clue why It does not work when I set it up like my `vaultwarden` service.  
(I am not running anything else on port 3000 and 8080)

Thanks in advance

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [February 2, 2023, 5:39pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/2 "2023-02-02T17:39:22Z")

</div>

Do you want both external and internal traffic go through Traefik? Why not just use both domains in the router? No need to expose the ports of the target containers.

```auto
.rule=Host(`internal`) || Host(`external`)

```

PS: You can use a single central [http-\>https redirect in http entrypoint](https://doc.traefik.io/traefik/routing/entrypoints/#redirection).

---

<div class="post-metadata">

**Author:** ![williamwoldum](https://avatars.discourse-cdn.com/v4/letter/w/f08c70/32.png) [@williamwoldum](https://community.traefik.io/u/williamwoldum)\
**Post date:** [February 2, 2023, 7:00pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/3 "2023-02-02T19:00:00Z")

</div>

Thanks for the response

I tried to apply your suggestions to the vaultwarden config

```auto
version: '3'

services:
  vaultwarden:
    image: vaultwarden/server
    container_name: vaultwarden
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - ./vw-data/:/data/
    environment:
      - ADMIN_TOKEN=REDACTED
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.entrypoints=http"
      - "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.local.example.dev`) || Host(`vaultwarden.example.dev`)"
      - "traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.vaultwarden.middlewares=vaultwarden-https-redirect"
      - "traefik.http.routers.vaultwarden-secure.entrypoints=https"
      - "traefik.http.routers.vaultwarden-secure.rule=Host(`vaultwarden.local.example.dev`) || Host(`vaultwarden.example.dev`)"
      - "traefik.http.routers.vaultwarden-secure.tls=true"
      - "traefik.http.routers.vaultwarden-secure.service=vaultwarden"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=8080"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

```

I now get a 502 error when trying to access both domains

```auto
10.0.0.5 - - [02/Feb/2023:18:51:48 +0000] "GET / HTTP/2.0" 502 11 "-" "-" 5659 "vaultwarden-secure@docker" "http://172.20.0.5:8080" 2ms
time="2023-02-02T19:51:48+01:00" level=debug msg="'502 Bad Gateway' caused by: dial tcp 172.20.0.5:8080: connect: connection refused"

```

I only made changes to the vaultwarden file. Should I make changes elsewhere?  
Thanks again.

---

<div class="post-metadata">

**Author:** ![williamwoldum](https://avatars.discourse-cdn.com/v4/letter/w/f08c70/32.png) [@williamwoldum](https://community.traefik.io/u/williamwoldum)\
**Post date:** [February 2, 2023, 7:12pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/4 "2023-02-02T19:12:25Z")

</div>

Just doing this (not exposing ports and sticking to the local domain only) is inaccessible locally (and publicly)

```auto
version: '3'

services:
  vaultwarden:
    image: vaultwarden/server
    container_name: vaultwarden
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - ./vw-data/:/data/
    environment:
      - ADMIN_TOKEN=REDACTED
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.entrypoints=http"
      - "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.local.example.dev`)"
      - "traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.vaultwarden.middlewares=vaultwarden-https-redirect"
      - "traefik.http.routers.vaultwarden-secure.entrypoints=https"
      - "traefik.http.routers.vaultwarden-secure.rule=Host(`vaultwarden.local.example.dev`)"
      - "traefik.http.routers.vaultwarden-secure.tls=true"
      - "traefik.http.routers.vaultwarden-secure.service=vaultwarden"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=8080"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

```

But portainer works fine when not exposing any ports (only locally ofc)?

```auto
version: '3'

services:
  portainer:
    image: portainer/portainer-ce
    container_name: portainer
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/pi/portainer/data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.rule=Host(`portainer.local.example.dev`)"
      - "traefik.http.middlewares.portainer-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.portainer.middlewares=portainer-https-redirect"
      - "traefik.http.routers.portainer-secure.entrypoints=https"
      - "traefik.http.routers.portainer-secure.rule=Host(`portainer.local.example.dev`)"
      - "traefik.http.routers.portainer-secure.tls=true"
      - "traefik.http.routers.portainer-secure.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

```

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [February 2, 2023, 7:40pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/5 "2023-02-02T19:40:50Z")

</div>

Is your local DNS pointing your local domain to the Traefik server IP?

---

<div class="post-metadata">

**Author:** ![williamwoldum](https://avatars.discourse-cdn.com/v4/letter/w/f08c70/32.png) [@williamwoldum](https://community.traefik.io/u/williamwoldum)\
**Post date:** [February 2, 2023, 7:52pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/6 "2023-02-02T19:52:03Z")

</div>

Yes my server which is running traefik has the ip `10.0.0.9`

Below image show my list of local DNS domains in pihole:

 ![image (1)](https://us1.discourse-cdn.com/flex020/uploads/containo/original/2X/3/367ac15ef9398929db219917954a50eb5dd58526.jpeg)

And as you can see portainer works fine with the local DNS:

 ![Nyt Projekt (1)](https://us1.discourse-cdn.com/flex020/uploads/containo/original/2X/b/b11660c3bda37476d61f766420139b1e2bc116df.jpeg)

And the config as showed before:

```auto
version: '3'

services:
  portainer:
    image: portainer/portainer-ce
    container_name: portainer
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/pi/portainer/data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.entrypoints=http"
      - "traefik.http.routers.portainer.rule=Host(`portainer.local.example.com`)"
      - "traefik.http.middlewares.portainer-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.portainer.middlewares=portainer-https-redirect"
      - "traefik.http.routers.portainer-secure.entrypoints=https"
      - "traefik.http.routers.portainer-secure.rule=Host(`portainer.local.example.com`)"
      - "traefik.http.routers.portainer-secure.tls=true"
      - "traefik.http.routers.portainer-secure.service=portainer"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

```

While vaultwarden now does not work:

 ![Nyt Projekt (2)](https://us1.discourse-cdn.com/flex020/uploads/containo/original/2X/7/7d4064d4c30f1def8cafc1c19bc5646ac3d65526.jpeg)

Also with the config showed before very similar to the portainer one:

```auto
version: '3'

services:
  vaultwarden:
    image: vaultwarden/server
    container_name: vaultwarden
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    volumes:
      - ./vw-data/:/data/
    environment:
      - ADMIN_TOKEN=REDACTED
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vaultwarden.entrypoints=http"
      - "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.local.example.com`)"
      - "traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.vaultwarden.middlewares=vaultwarden-https-redirect"
      - "traefik.http.routers.vaultwarden-secure.entrypoints=https"
      - "traefik.http.routers.vaultwarden-secure.rule=Host(`vaultwarden.local.example.com`)"
      - "traefik.http.routers.vaultwarden-secure.tls=true"
      - "traefik.http.routers.vaultwarden-secure.service=vaultwarden"
      - "traefik.http.services.vaultwarden.loadbalancer.server.port=8080"
      - "traefik.docker.network=proxy"

networks:
  proxy:
    external: true

```

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [February 2, 2023, 9:52pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/7 "2023-02-02T21:52:15Z")

</div>

Did you check the [vaultwarden proxy docs](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples)?

---

<div class="post-metadata">

**Author:** ![Lapotor](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/lapotor/32/7998_2.png) [@Lapotor](https://community.traefik.io/u/Lapotor)\
**Post date:** [December 18, 2023, 10:50pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/8 "2023-12-18T22:50:12Z")

</div>

@williamwoldum I'm looking to do exactly the same thing.  
Have you been able to solve your problems?  
If so, it would be great if you'd share your results.

---

<div class="post-metadata">

**Author:** ![nickc00per](https://avatars.discourse-cdn.com/v4/letter/n/5e9695/32.png) [@nickc00per](https://community.traefik.io/u/nickc00per)\
**Post date:** [April 4, 2025, 10:58pm UTC](https://community.traefik.io/t/expose-docker-service-locally-and-publicly/17398/9 "2025-04-04T22:58:21Z")

</div>

Necro'ing this thread for the sanity of future hobbyists like myself. The solution to separating local and external services is the config (./traefik/data/config.yml for docker). Add a secured middleware to local services. The result is "Forbidden" when attempting to access [app.local.example.net](http://app.local.example.net) from an external network.  
Below is an example.

```auto
http:
### ROUTER REGION FOR EXTERNAL SERVICE ###
  routers:
    jellyfin:
      entryPoints:
        - "https"
      rule: "Host(`jellyfin.example.net`)"
      middlewares:
        - default-headers
        - https-redirectscheme
      tls: {}
      service: request

### ROUTER REGION FOR LOCAL SERVICES ###
    jellyfin:
      entryPoints:
        - "https"
      rule: "Host(`jellyfin.local.example.net`)"
      middlewares:
        - secured
      tls: {}
      service: sonarr

### REGION SERVICES ###
  services:
    jellyfin:
      loadBalancer:
        servers:
          - url: "http://localhost:8096"
        passHostHeader: true

### ENDREGION ###
  middlewares:
    https-redirectscheme:
      redirectScheme:
        scheme: https
        permanent: true

    default-headers:
      headers:
        frameDeny: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 15552000
        customFrameOptionsValue: SAMEORIGIN
        customRequestHeaders:
          X-Forwarded-Proto: https

    default-whitelist:
      ipAllowList:
        sourceRange:
          - "192.168.1.0/24"

    secured:
      chain:
        middlewares:
          - default-whitelist
          - default-headers

```

I have no IT experience. This just gave me the desired effect.
