jordanpotter / docker-wireguard

Simple image for running a WireGuard client with a kill switch
MIT License
143 stars 37 forks source link

Unable to access WebUIs of containers routed through this container #10

Closed rafajrichard closed 3 years ago

rafajrichard commented 3 years ago

When I route a container via --net=container: through docker-wireguard and open according ports on docker-wireguard I still cannot access them. I'm guessing this is due to the kill-switch. Is there a way to open the ports to LAN, or am I doing something wrong?

jordanpotter commented 3 years ago

Hey @rafajrichard, reposting from a discussion in https://github.com/jordanpotter/docker-wireguard/issues/7#issuecomment-695169500. Let me know if this works for you!


Suppose you have two containers: app and wireguard. If you want container app to use Wireguard, you'd run something like:

docker run --net=container:wireguard app

However once you do that, all traffic for app is routed through the wireguard container. So if app serves a webpage on port 80, you wouldn't be able to access that page locally.

To get around this, you can use another container to proxy traffic to app! I've been using the dperson/nginx image, which has worked wonderfully for me.

So my setup is:

Run the Wireguard container: docker run --name wireguard --cap-add NET_ADMIN --cap-add SYS_MODULE --sysctl net.ipv4.conf.all.src_valid_mark=1 -v /path/to/conf/mullvad.conf:/etc/wireguard/mullvad.conf jordanpotter/wireguard
Run the App container: docker run --name app --net=container:wireguard app
Run the Proxy container: docker run --name proxy --link app dperson/nginx -w 'http://app:80/;/'

I think this uses some older features in Docker, but this is what I do for my own use cases.

boratanrikulu commented 3 years ago

I'm using same container for serving http server and using wireguard. Also, I can access to the container from remote. I hope these files will be useful to someone.

dockerfile

FROM golang:1.15-alpine
WORKDIR /src

COPY go.sum go.mod ./
RUN go mod download
COPY . .

RUN CGO_ENABLED=0 go build -o /bin/app .

FROM alpine
WORKDIR /src

COPY --from=0 /bin/app /bin/app
COPY --from=0 /src/run.sh /src/run.sh
RUN apk add --no-cache wireguard-tools

CMD ["/src/run.sh"]

run.sh

#!/bin/bash
set -e

wg-quick up wg0
addr="$(ip -o addr show dev eth0 | awk '$3 == "inet" {print $4}')"
ip rule add from ${addr} table main

shutdown () {
    wg-quick down wg0
    ip rule del from ${addr} table main
    exit 0
}
trap shutdown SIGTERM SIGINT SIGQUIT

/bin/app &
wait $!

start like this

docker run --rm -i -t \
    --privileged \
    -e PORT=80 \
    -p 8080:80 \
    --sysctl net.ipv6.conf.all.disable_ipv6=0 \
    -v `pwd`/wg0.conf:/etc/wireguard/wg0.conf \
    image-name
jordanpotter commented 3 years ago

Hey @boratanrikulu , it looks like your solution does not have a kill switch enabled. Have you experimented with a version of your solution that still has a kill switch?

If you have something working, I'd very much welcome a PR!

Yrlish commented 3 years ago

As this docker's iptables only blocks outgoing traffic. This means setting up a reverse proxy into this container will work fine. I have a few containers running behind this wireguard all configured with a docker-compose file.

Here is an example:

---
version: "2.1"
services:
  swag:
    image: ghcr.io/linuxserver/swag
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - ...
    volumes:
      - ./data/swag:/config
    ports:
      - 443:443
      - 80:80
    restart: unless-stopped

  wireguard:
    image: jordanpotter/wireguard:2.0.1
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    volumes:
      - ./data/vpn.conf:/etc/wireguard/wg0.conf
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

  whatever: # e.g. runs a service on port 8123
    image: ...
    container_name: whatever
    depends_on:
      - "wireguard"
    network_mode: "service:wireguard"
    environment:
      - ...
    restart: unless-stopped

Lets say the service whatever have something running on port 8123 inside it. As whatever is configured with network_mode: "service:wireguard" we need to access it through the service wireguard, as in http://wireguard:8123/ (internal docker dns only). Either you map the port on the wireguard service with 8123:8123 to able to use http://host:8123 or you use a separate service for reverse proxying (http://whatever.fqdn or http://services.fqdn/whatever), in which do not need to map the port (you may need to expose the port though, if the image doesn't already do that).

I am using linuxserver/docker-swag for reverse proxying, it has a bunch of nice stuff in it out of the box. Swag has a bunch of reverse proxy configurations bundled with it sourced from linuxserver/reverse-proxy-confs. What you need to remember to do, is to set the nginx site configuration from whatever hostname is in it to wireguard, e.g. set $upstream_app whatever; to set $upstream_app wireguard; for the templates. In easier terms, basically change proxy_pass http://whatever:8123; to proxy_pass http://wireguard:8123;.

jordanpotter commented 3 years ago

I've added instructions to the README for exposing ports on the Wireguard container, which allows the local network to contact linked services such as web UIs. I tested this myself using Nginx and included the example in the README.

@rafajrichard let me know if this works for you! You can also use the proxy solution (which a few people here have written about).

rafajrichard commented 3 years ago

I have since moved to a different container (linuxserver/wireguard) and added a killswitch into the config file of it, but if I have to set up a new server, I will try your solution. Thanks!

jordanpotter commented 3 years ago

Sounds good! Would appreciate your thoughts if/when you try it 👍

justmytwospence commented 3 years ago

This worked fine for me using nginx-proxy-manager, but I'm trying to switch to traefik and finding that the kill switch isn't compatible. I'm still trying to figure out the details of how traefik works. So far all I can tell is that traefik sets up a server at an IP address 192.168.96.X for reverse-proxying the container and that's what isn't making it through I guess. Any obvious ideas?

jordanpotter commented 3 years ago

Hey @justmytwospence, I'm not too familiar with Traefik. Did you end up figuring this out? I'm curious whether the features described in the "Local Network" section of the README were helpful.

justmytwospence commented 3 years ago

No I haven't yet. I have had my local subnet set up since before the transition (192.168.1.0/24). I tried adding a second bit of code to do the same thing to the 192.168.96.0/24 subnet but that didn't work. I don't know enough about CIDR and subnetting to know if that's the right subnet mask though - maybe you could enlighten me? This is the traefik documentation for the mandatory load balancer that sets up this new subnet: https://doc.traefik.io/traefik/routing/services/

jordanpotter commented 3 years ago

This will take me a bit of time to investigate -- life has been pretty busy. In the meantime, could you share your configuration so I can replicate locally?

prov3it commented 3 years ago
version: "3"
services:
    wireguard:
    container_name: wireguard
    image: jordanpotter/wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      net.ipv4.conf.all.src_valid_mark: 1
    volumes:
      - /X/mullvad.conf:/etc/wireguard/mullvad.conf
    restart: unless-stopped
    networks:
      - web

  curl:
    image: appropriate/curl
    container_name: wireguard-curl
    command: http://httpbin.org/ip
    network_mode: "service:wireguard"
    depends_on:
      - wireguard

  Y:
    container_name: Y
    environment:
      - PGID=1000
      - PUID=1000
      - WEBUI_PORT=1234
      - TZ="Europe/Z"
    image: ghcr.io/linuxserver/Y
    restart: "no"
    volumes:
      - /mnt/usb/docker/config/Y/config/:/config/Y
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.qbit.entrypoints=websecure"
      - "traefik.http.services.qbit.loadbalancer.server.port=1234"
      - "traefik.http.routers.qbit.rule=Host(`YX`)"
      - "traefik.http.routers.qbit.tls=true"
      - "traefik.http.routers.qbit.tls.domains[0].main=YX"
    depends_on:
      - wireguard
    network_mode: "service:wireguard"

networks:
  web:
    external: true

i've got this working for me with traefik 2.3. The only thing im not sure of is how to see that the killswitch is working.