Tumgik
amitabh-d · 1 year
Text
Docker Service Network Mode
When running a container using docker, one of the networking modes available is using the network of another service. Let's say we have the following invalid docker-compose.yml file:
version: '3' services: vpn: image: vpn:1.0 ports: - 51820:51820 app: image: app:1.0 ports: - 8080:8080 network_mode: service:vpn
We have two services, - vpn which exposes port 51820. - app which exposes ports 8080, but with network mode set to the vpn service.
Assuming the vpn allows local connections, and the network ip address of the host running the docker engine is 10.0.0.1, the vpn should be available via 10.0.0.1:51820, and the app at 10.0.0.1:8080.
But this does not work as intended.
The reason why this compose file is invalid is because when specifying network_mode the exposed ports are ignored for that service.
Knowing this we assume that this app service is now part of the vpn network namespace and move the expose ports declaration to the vpn dictionary to create a valid docker-compose.yml file,
version: '3' services: vpn: image: vpn:1.0 ports: - 51820:51820 - 8080:8080 app: image: app:1.0 network_mode: service:vpn
Now the port is exposed on the vpn service. If we access 10.0.0.1:8080 from the host, our app again will be not be available.
But if we get the vpn service's container id and assuming the following: - vpn container image has ping and curl installed, - the app is a http service, and run: docker exec -it $vpn_container_id ping app and, docker exec -it $vpn_container_id curl http://app:8080
We should get proper responses. ping should return pings, and curl should show our disruptive hello-world app.
But then why doesn't acessing 10.0.0.1:8080 from the host work? Well, it does work but not as we intended.
Docker exposes the vpn service's 8080 port to the host but there's nothing running on the 8080 port in the vpn service's container. The ports list exposes ports of the service it belongs to and does not concern itself with other services sharing the network. So the host accesses vpn's 8080 port and not app's 8080 port. But since app is part of vpn's network namespace, it is accessible from inside the vpn service's container.
So a way to access app from the host would be to add a reverse proxy which creates its own network and shares the default network. Then we add the proxy service to this new network. And we expose our app's port on the proxy as well. For example,
version: '3' networks: default: proxy: services: proxy: image: nginx:1.23.3 networks: - default - proxy volumes: - ./nginx:/etc/nginx/conf.d ports: - 8080:8080 vpn: image: vpn:1.0 ports: - 51820:51820 networks: - default - proxy app: image: app:1.0 network_mode: service:vpn
Next, proxy needs to know what to proxy and where it would be available.
Again assuming ping and curl is available in the nginx container, and try to access our app: docker exec -it $nginx_container_id ping app and, docker exec -it $nginx_container_id curl http://app:8080
It still does not work because app does not share the proxy network. But if we access our app on vpn:8080, docker exec -it $nginx_container_id ping vpn and, docker exec -it $nginx_container_id curl http://vpn:8080
It works!
Because the app is accessible from vpn's internal network, which is shared with the nginx container's proxy network. And even though we did not expose the 8080 port in app or vpn 's definition, the app is available on 8080 at vpn:8080 from within the nginx container as well.
So, we create a ./nginx/default.conf,
server { listen 8080; location / { proxy_pass http://vpn:8080; } }
And if we run docker compose up -d, and now our app should be accessible at 10.0.0.1:8080.
To summerize, to route traffic of a container via another container as well as access it from the host requires us to create a reverse proxy with a shared network.
This is could also be achieved by using any tunneling tool, like maybe with ssh or even ip. I've already written something similar in a previous post here. It uses iptables and ip to route traffic. Some might find it an interesting read.
0 notes
amitabh-d · 1 year
Text
Docker, Mullvad, Socks Proxy, and Automatic Networking Configuration
Mullvad runs their Socks proxy server on 10.64.0.1. But our wireguard is running in a container so the system does not know how to reach this IP address.
We need to tell our system how to reach this IP address via our container's IP.
To selectively route traffic via the proxy, we need to provide a .pac file to Firefox. A .pac file contains a function which decides which URL/host should be proxied. Under network settings Automatic proxy configuration URL it accepts a URL or we can specify a local file using file:////path/to/proxy.pac.
The linuxserver/wireguard image expects a wireguard configuration under /config/wg0.conf. Get your mullvad config from here https://mullvad.net/en/account/#/wireguard-config, and extract the downloaded zip into a wg folder. Rename the config you want to use to wg0.conf. If you don't have IPv6 then remove the IPv6 addresses from the wg0.conf file, otherwise the connection might fail.
Lets create the required files.
Copy the following into docker-compose.yml:
--- version: "3" services: wg: image: lscr.io/linuxserver/wireguard container_name: wg cap_add: - NET_ADMIN - SYS_MODULE environment: - PUID=1000 - PGID=1000 - TZ=Europe/London volumes: - ./wg:/config - /lib/modules:/lib/modules ports: - 51820:51820/udp - 1080:1080 #for socks proxy sysctls: - net.ipv4.conf.all.src_valid_mark=1 restart: unless-stopped
Copy the following into start.sh:
#!/bin/bash #start wg service docker-compose up -d docker exec wg curl --no-progress-meter https://am.i.mullvad.net/connected #enable nat inside the container docker exec wg iptables -t nat -A POSTROUTING -o wg+ -j MASQUERADE #get ip address of wg network wg_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' wg) echo "wg container ip is $wg_ip" #add route to mullvad socks ip sudo ip route add 10.64.0.1 via $wg_ip
And, make the script executable:
chmod 700 start.sh
Copy the following to `mullvad.pac':
const proxyList = new Set(); //add domain names below proxyList.add("mullvad.net"); //proxyList.add("anotherdomain.com"); function FindProxyForURL(url, host) { return proxyList.has(host) ? "SOCKS5 10.64.0.1:1080" : "DIRECT" }
Open Firefox's network settings and add the path to mullvad.pac file under Automatic proxy configuration URL.
file:////path/to/mullvad.pac
Now if you visit https://mullvad.net/en/check, it should be all green.
1 note · View note