Simple sidecar to connect a container to an external network with another container as the gateway.
The goal is to be able to connect to a Gluetun container from multiple stacks without using network_mode: container:<gluetun>
since the container
network mode introduces some problems like it not being a direct dependency which can cause stacks to fail to start and if the Gluetun container updates and restarts then the attached container won't regain network access until it is taken down and started again.
I tried to keep the container itself as lightweight (I got it to like 4.1MB
!) and simple as possible with enough functionality and configurability that it solves lots of problems.
You'll need an external network with a known subnet which you can create like this:
docker network create -subnet=172.21.0.0/24 --ip-range=172.21.0.128/25 --gateway=172.21.0.1 vpn_net
You'll use IPs in this subnet and this network name for the containers you want to hook up. If you don't specify an IP it will assing one from 172.21.0.128-172.21.0.255 but if you do specify then you can use 172.21.0.0-172.21.0.255 but it's better to keep manual and auto assigned IPs separate so if you want a manual IP it would be better to select from 172.21.0.3-172.21.0.127.
Here's a simple setup for a gluetun stack which you could have at /opt/stacks/glutun/docker-compose.yml
. You'll just need to set up your credentials for your provider as you can see in the gluetun-wiki repo
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
cap_add:
- NET_ADMIN
environment:
- VPN_SERVICE_PROVIDER=${VPN_PROVIDER}
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
- WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
- SERVER_CITIES=${SERVER_CITIES}
volumes:
- /opt/stacks/gluetun/iptables:/iptables
- /etc/localtime:/etc/localtime:ro
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
networks:
vpn_net:
ipv4_address: 172.21.0.2
restart: always
logging:
driver: json-file
options:
max-size: 100m
max-file: "5"
networks:
vpn_net:
external: true
And then create a file at /opt/stacks/gluetun/iptables/post-rules.txt
with the following content (edit the subnets if your network uses a different one):
iptables -A FORWARD -s 172.21.0.0/24 -o tun0 -j ACCEPT
iptables -A FORWARD -d 172.21.0.0/24 -i tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -s 172.21.0.0/24 -o tun0 -j MASQUERADE
Make sure the gluetun stack is up and running correctly before moving on. If you have trouble please check the gluetun-wiki repo for help
Once you have the gateway container set up and configured correctly you have these options for the environment of this connector:
Variable | Description | Status | Default | Example |
---|---|---|---|---|
GATEWAY_IP |
IP of the gateway container (on the Docker network) that traffic will be routed through | Required | N/A | 172.21.0.2 |
BYPASS_IP |
IP of the Docker host in the Docker network, normally 172.x.0.1 | Optional unless BYPASS_SUBNETS is defined then required |
N/A | 172.21.0.1 |
BYPASS_SUBNETS |
Comma separated list of subnets that should be routed through the bypass IP | Optional | Empty | 192.168.88.0/24,100.64.0.0/10 |
HEALTH_REMOTE_IP |
External IP to ping for health check | Optional unless HEALTH_REMOTE_CHECK is on |
N/A | 1.1.1.1 |
HEALTH_REMOTE_CHECK |
Whether to ping the HEALTH_REMOTE_IP from inside the container to log health | Optional with default off | off | on |
HEALTH_LOCAL_IP |
Local IP to ping for health check | Optional unless HEALTH_LOCAL_CHECK is on then required |
N/A | 192.168.88.1 |
HEALTH_LOCAL_CHECK |
Whether to ping the HEALTH_LOCAL_IP from inside the container to log health |
Optional with default off | off | on |
IP_API_URL |
Endpoint to wget from to print IP | Optional with default ifconfig.me/ip | ifconfig.me/ip | ifconfig.me/ip |
IP_API_CHECK |
Whether to check the public IP on boot using IP_API_URL | Optional with default on | on | on |
TRACE_ON_START |
Run traceroutes when starting using HEALTH_REMOTE_IP and HEALTH_LOCAL_IP to confirm routing table |
Optional with default off | off | off |
Create a new stack for the things you want to include in what this connector routes and then add it as you see in the example docker-compose.yml.
Here is a simplified version:
services:
# this apline container represents your apps
app_one:
image: alpine:latest
network_mode: service:connectorr # connect it to the connectorr container
command: sh -c "apk add curl && curl ifconfig.me/ip"
app_two:
image: alpine:latest
network_mode: service:connectorr # connect it to the connectorr container
command: sh -c "apk add curl && curl ifconfig.me/ip"
connectorr:
image: ghcr.io/wolffshots/connectorr:latest
container_name: app_connectorr
## specific port for the app/s you have connected (in this case the ports you access alpine on)
## note that they must be unique ports on the actual app side
ports:
- 8085:8085 # an example port for app one. to access app one in the docker network it would be 172.21.0.50:8085 or app_connectorr:8085
- 8086:8086 # an example port for app two. vice versa for app two
cap_add:
- NET_ADMIN
environment:
- GATEWAY_IP=172.21.0.2 # gluetun
- BYPASS_IP=172.21.0.1 # docker host
- BYPASS_SUBNETS=192.168.88.0/24 # local network
restart: always
networks:
- vpn_net # the network you created which will assign an ip in 172.21.0.128-172.21.0.255 based on the ip pool of the network
networks:
vpn_net: # the network you created
external: true
Once this stack is up your apps should be using connectorr
as their network and it should be routing all traffic through gluetun
except for traffic between the bypassed subnets