kylemanna / docker-openvpn

🔒 OpenVPN server in a Docker container complete with an EasyRSA PKI CA
https://hub.docker.com/r/kylemanna/openvpn/
MIT License
8.62k stars 2.37k forks source link

Port forwarding through VPN to a Client #443

Open Pixxelfragger opened 5 years ago

Pixxelfragger commented 5 years ago

I have the following scenarios:

So far everything works as expected. Client B can use services running on client A without problems as long as the vpn tunnel is up and running on both clients. For now both clients will use the VPN as Default Gateway and all traffic will be routed through the VPN.

The Problem:

But now it gets a little trickier. I want to use the services of client A even without an active VPN running on client B. I know that you would normally use a port release on the main router as well as a DynDNS service. But this is unfortunately not possible in my case…

Possible Solution:

The Idea was to use the VPN with port forwarding on the Dedicated Server as an alternative way. But my Problem is that I’m not sure what exact I must configure for this within the docker…

I’ve started with adding the port (as first example the port 5001/tcp) to my docker compose file. After that, I’ve added this rules to the iptables:

iptables -t nat -A PREROUTING -d 172.24.0.2 -p tcp --dport 5001 -j DNAT --to-dest 192.168.254.1:5001
iptables -t nat -A POSTROUTING -d 192.168.254.1 -p tcp --dport 5001 -j SNAT --to-source 192.168.254.2
iptables -t nat -L now shows:
bash-4.4# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DNAT       tcp  --  anywhere             a883b93cbe0a         tcp dpt:5001 to:192.168.254.1:5001

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER_OUTPUT  all  --  anywhere             127.0.0.11

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER_POSTROUTING  all  --  anywhere             127.0.0.11
MASQUERADE  all  --  192.168.255.0/24     anywhere
MASQUERADE  all  --  192.168.254.0/24     anywhere
SNAT       tcp  --  anywhere             192.168.254.1        tcp dpt:5001 to:192.168.254.2

Chain DOCKER_OUTPUT (1 references)
target     prot opt source               destination
DNAT       tcp  --  anywhere             127.0.0.11           tcp dpt:domain to:127.0.0.11:35413
DNAT       udp  --  anywhere             127.0.0.11           udp dpt:domain to:127.0.0.11:33452

Chain DOCKER_POSTROUTING (1 references)
target     prot opt source               destination
SNAT       tcp  --  127.0.0.11           anywhere             tcp spt:35413 to::53
SNAT       udp  --  127.0.0.11           anywhere             udp spt:33452 to::53

Where a883b93cbe0a is the Docker Container ID. And 192.168.255.1 is the IP Address of the Dockers “tun0”

So far, this setting only leads to timeouts when calling the subdomain URL "vpn.domain.com:5001". Is there a bug in the snat rule for the client's answers or do i miss something else here?

LukasWerfel commented 5 years ago

@Pixxelfragger did you find a way how to do it yet? I am wondering to.

Maybe you just have to set the iptables within docker and bind the ports to the host?

EDIT: In the end I switched to WireGuard, which makes these things very easy.

timvan commented 5 years ago

@Pixxelfragger - I am also interested in a solution to this. I want to forward a WebServer that is running locally on a Pi, that is the VPN Client, to a Cloud IP that is a VPN host.

Any luck on finding a solution?

webian commented 5 years ago

@Pixxelfragger, I'm interested to. I need to make my dev machine webserver reachable but my provider only gives me a non reachable private ip. I set up a vps with docker-openvpn and my dev machine can connect to it but I don't know how to forward ports 80/443. Any idea please?

jerometerrier commented 4 years ago

@Pixxelfragger, I'm interested to. I need to make my dev machine webserver reachable but my provider only gives me a non reachable private ip. I set up a vps with docker-openvpn and my dev machine can connect to it but I don't know how to forward ports 80/443. Any idea please?

Same needs, same problem :)

Derkades commented 4 years ago

I got it working, just in case it might help someone I've written a wiki page with the steps I took: https://github.com/kylemanna/docker-openvpn/wiki/Port-forwarding . It's not well written, but hopefully clear enough.

NanoCode012 commented 3 years ago

Hi @Derkades , may I ask a question? What would I do if the webserver is not working inside the container?

In my case, I have an apache server on my local machine. It is connected to the VPS via this repo OpenVPN. I followed your step in setting the static client ip, but could not wget successfully.

# apache is on localhost:81
wget -O - 192.168.254.1:81

I'm just using apache server to test port forwarding on VPN first. Do you have any ideas on where I made a mistake?

Derkades commented 3 years ago

Make sure the webserver is listening on the correct interface (the VPN). How do you connect to the VPN on the client? I am using this: https://hub.docker.com/r/derkades/ovpn-client

NanoCode012 commented 3 years ago

Hi @Derkades . Thank you for your reply. I finally got it working. I'm using Windows openvpn client on local.

Your guide was great! The issue lied within the static client ip. When I checked it out, even after following the other guide you mentioned, my client machine still has another ip 192.168.255.X. I already tried reconnecting the openvpn, but nothing changed. I will see if it changes later, but in the meantime, I'm using the ip above and the port forwarding works great!

plachta11b commented 3 years ago

I was able to configure this by setting up routes and iptables.

On the server: Setup port forwarding for incoming connections:

iptables -t nat -A PREROUTING -d ${SERVER_PUB_IP}/32 -p tcp -m tcp --dport 5001 -m comment --comment "traffic will be routed through the VPN" -j DNAT --to-destination 192.168.254.1:5001

Route forwarded trafic into openvpn server container

ip route add 192.168.254.0/24 via 172.24.0.2 dev br-<your docker bridge name/hash>

In the container: Setup post routing to modify source ip. Otherwise client would not be able to respond.

iptables -t nat -A POSTROUTING -d 192.168.254.0/24 -o tun0 -j MASQUERADE

Persistent route: Route will be removed after container stops. This behaviour can be prevented by using external network.

docker network create openvpn-docker-bridge --opt com.docker.network.bridge.name=openvpn-docker --attachable --subnet 172.84.0.0/30

ip route add 192.168.254.0/24 via 172.84.0.2 dev openvpn-docker

Debug tools recomended: Watch trafic: tcpdump dst 192.168.254.1 Spin up http server: python3 -m http.server --bind 192.168.254.1 8000 Bind tcp trafic from other in home pc on the client: rinetd

I do not like iptables with specific port in the openvpn container as i need too many unique ports forwarded.

joesturge commented 4 months ago

I acheived automatic configuration of IP tables using a second docker container like so

version: '3'
services:
  openvpn:
    cap_add:
      - NET_ADMIN
    image: kylemanna/openvpn
    container_name: openvpn
    healthcheck: # healthcheck to allow sidecar container to run after vpn server is ready
      test: ["CMD", "pgrep", "openvpn"]
      interval: 10s
      timeout: 60s
      retries: 6
    ports:
      - "1194:1194/udp"
      - "8211:8211/udp" # also decare port to be forwarded
    restart: unless-stopped
    volumes:
      - ./openvpn-data/conf:/etc/openvpn

  iptables_sidecar:
    cap_add:
      - NET_ADMIN
    build: .
    container_name: iptables_sidecar
    depends_on:
      openvpn:
        condition: service_healthy
    network_mode: "service:openvpn"

then in the dockerfile run a script which can run iptables

FROM alpine:latest

# Install iptables
RUN apk add --no-cache iptables

# Create the script file within the container
RUN echo '#!/bin/sh' >> /apply.sh \
    && echo 'iptables -A PREROUTING -t nat -i eth0 -p udp --dport 8211 -j DNAT --to 192.168.254.1:8211' >> /apply.sh \
    && echo 'iptables -A FORWARD -p udp -d 192.168.254.1 --dport 8211 -j ACCEPT' >> /apply.sh \
    && chmod +x /apply.sh

# Set the script as the entrypoint
ENTRYPOINT ["/apply.sh"]
sibosend commented 3 months ago

I got it working, just in case it might help someone I've written a wiki page with the steps I took: https://github.com/kylemanna/docker-openvpn/wiki/Port-forwarding . It's not well written, but hopefully clear enough.

another way to persist firewall rules:

since an isoleted volume has been created, it is feasible to append iptables rules to ovpn_env.sh

docker run -it --rm --privileged --pid=host justincormack/nsenter1

cd /var/lib/docker/volumes/$OVPN_DATA/_data/

echo 'iptables -t nat -A POSTROUTING -d a.b.c.d/e -o eth1 -j SNAT --to-source x.x.x.x' >> ovpn_env.sh