|
| 1 | +version: "3" |
| 2 | + |
| 3 | +networks: |
| 4 | + # A non-default network is needed to control the IP address ranges (used in |
| 5 | + # some configs), and to avoid affecting other containers in the same Docker. |
| 6 | + vpn-network: |
| 7 | + driver: bridge |
| 8 | + ipam: |
| 9 | + driver: default |
| 10 | + config: |
| 11 | + - subnet: "172.30.172.0/24" |
| 12 | + enable_ipv6: false |
| 13 | + |
| 14 | +services: |
| 15 | + |
| 16 | + # A sample application that runs securely only through the VPN, not directly. |
| 17 | + # It will not actually start until the firewall rules are applied (either |
| 18 | + # for the first time on creation, or pre-existing block-rules on restarts). |
| 19 | + # There can any amount of apps configured in the same setup: 0, 1, 2, so on. |
| 20 | + # If stopped, nothing will happen - the VPN remains available for other apps. |
| 21 | + transmission: |
| 22 | + build: . |
| 23 | + entrypoint: [/app/wait-for-safety.sh] |
| 24 | + command: [/app/transmission.sh] |
| 25 | + environment: |
| 26 | + LOCAL_IPS: 172.30.172.* |
| 27 | + PEER_PORT: 46112 # as (and if) configured in the VPN provider |
| 28 | + volumes: |
| 29 | + - ./:/app |
| 30 | + - ./transmission-state:/var/lib/transmission |
| 31 | + - ./transmission-files:/mnt/files |
| 32 | + - ~/Downloads:/mnt/downloads |
| 33 | + - ~/Movies:/mnt/movies |
| 34 | + cap_add: [NET_ADMIN] # needed for the `wait-for-safety.sh` script |
| 35 | + restart: unless-stopped |
| 36 | + stop_signal: SIGTERM |
| 37 | + network_mode: service:network # CRITICALLY IMPORTANT! |
| 38 | + |
| 39 | + # A shared container that is used as a network. It does nothing but sleeps. |
| 40 | + # Native Docker's networks cannot share the iptables rules cross containers. |
| 41 | + # The ports of all containers are shared here, as the network-bound containers |
| 42 | + # cannot share their own ports (including the VPN-secured application). |
| 43 | + network: |
| 44 | + build: . |
| 45 | + command: sleep infinity |
| 46 | + cap_add: [NET_ADMIN] # needed only for debugging and README's simulations |
| 47 | + stop_signal: SIGKILL |
| 48 | + restart: always |
| 49 | + dns: [8.8.4.4] |
| 50 | + ports: |
| 51 | + - "127.0.0.1:9091:9091" # application's ports |
| 52 | + networks: |
| 53 | + - vpn-network |
| 54 | + |
| 55 | + # Evaluates the status of the setup, and prints a colorful message about that. |
| 56 | + # It also generates an HTML file that is later served by the web-view server. |
| 57 | + # If stopped, the status is not checked and not updated, the old one is shown. |
| 58 | + status: |
| 59 | + build: . |
| 60 | + command: |
| 61 | + - bash |
| 62 | + - -c |
| 63 | + - | |
| 64 | + while true; do |
| 65 | + /report-status.sh |
| 66 | + cat /status/index.ansi |
| 67 | + sleep 5 |
| 68 | + done |
| 69 | + environment: |
| 70 | + NS: 8.8.4.4 |
| 71 | + TZ: Europe/Berlin |
| 72 | + STATUS_DIR: /status |
| 73 | + env_file: |
| 74 | + - ipstack.env |
| 75 | + volumes: |
| 76 | + - ./report-status.sh:/report-status.sh:ro |
| 77 | + - html:/status:rw |
| 78 | + restart: unless-stopped |
| 79 | + stop_signal: SIGKILL |
| 80 | + network_mode: service:network # CRITICALLY IMPORTANT! |
| 81 | + |
| 82 | + # Connects and reconnects to the remote VPN server, creates the `tun` device, |
| 83 | + # configures the default traffic routing through VPN (only when connected). |
| 84 | + # If stopped, the `tun` device disappears for all other containers, |
| 85 | + # and the traffic is routed through the default `eth` device (if not blocked). |
| 86 | + openvpn: |
| 87 | + build: . |
| 88 | + command: ["openvpn", "--config", "client.conf"] |
| 89 | + volumes: |
| 90 | + - ./openvpn:/etc/openvpn:ro |
| 91 | + working_dir: /etc/openvpn/airvpn |
| 92 | + devices: [/dev/net/tun] |
| 93 | + cap_add: [NET_ADMIN] |
| 94 | + restart: unless-stopped |
| 95 | + stop_signal: SIGTERM |
| 96 | + network_mode: service:network # CRITICALLY IMPORTANT! |
| 97 | + |
| 98 | + # Applies the firewall rules to block the traffic from going around VPN. |
| 99 | + # If stopped, the iptables rules remain applied, but are not re-applied, |
| 100 | + # which allows their modification manually (incl. unblocking the traffic). |
| 101 | + firewall: |
| 102 | + build: . |
| 103 | + command: |
| 104 | + - bash |
| 105 | + - -c |
| 106 | + - | |
| 107 | + while true; do |
| 108 | + /apply-firewall.sh |
| 109 | + sleep 1s |
| 110 | + done |
| 111 | + environment: |
| 112 | + IPTABLES_FILE_V4: /iptables/iptables-v4.txt |
| 113 | + IPTABLES_FILE_V6: /iptables/iptables-v6.txt |
| 114 | + volumes: |
| 115 | + - ./apply-firewall.sh:/apply-firewall.sh:ro |
| 116 | + - iptables:/iptables |
| 117 | + cap_add: [NET_ADMIN] |
| 118 | + restart: unless-stopped |
| 119 | + stop_signal: SIGKILL |
| 120 | + network_mode: service:network # CRITICALLY IMPORTANT! |
| 121 | + |
| 122 | + # Generates the firewall rules to be atmomically applied in another container. |
| 123 | + # It also resolves the IP addresses of the VPN provider into an allow-list, |
| 124 | + # so that the firewall would not block it on the default `eth` interface. |
| 125 | + # See the notes in `generate-firewall.sh` on why this needs to be isolated. |
| 126 | + # If stopped, the dump files are not generated, so they will not be applied. |
| 127 | + rulemaker: |
| 128 | + build: . |
| 129 | + command: |
| 130 | + - bash |
| 131 | + - -c |
| 132 | + - | |
| 133 | + IPTABLES_FILE_V4=/tmp/null4 \ |
| 134 | + IPTABLES_FILE_V6=/tmp/null6 \ |
| 135 | + ALLOWED_IPS_FILE= ALLOWED_IPS_DIR= \ |
| 136 | + /generate-firewall.sh # silent insta-block! |
| 137 | +
|
| 138 | + while true; do |
| 139 | + /update-airvpn-ips.sh |
| 140 | + /generate-firewall.sh |
| 141 | + sleep 600 |
| 142 | + done |
| 143 | + environment: |
| 144 | + IPTABLES_FILE_V4: /iptables/iptables-v4.txt |
| 145 | + IPTABLES_FILE_V6: /iptables/iptables-v6.txt |
| 146 | + ALLOWED_IPS_FILE: /cache/all.txt |
| 147 | + ALLOWED_IPS_DIR: /cache |
| 148 | + LOCAL_IPS: 172.30.172.0/24 |
| 149 | + STATUS_IP: 139.130.4.5 |
| 150 | + NS: 8.8.4.4 |
| 151 | + volumes: |
| 152 | + - ./cache:/cache |
| 153 | + - ./update-airvpn-ips.sh:/update-airvpn-ips.sh:ro |
| 154 | + - ./generate-firewall.sh:/generate-firewall.sh:ro |
| 155 | + - iptables:/iptables |
| 156 | + dns: [8.8.4.4, 8.8.8.8] |
| 157 | + cap_add: [NET_ADMIN] |
| 158 | + restart: unless-stopped |
| 159 | + stop_signal: SIGKILL |
| 160 | + network_mode: bridge # NB! See the comment above, and generate-firewall.sh. |
| 161 | + |
| 162 | + # A supplimentary web server to publish the HTML status page. |
| 163 | + # If stopped, the status will not be served via HTTP, but will be shown |
| 164 | + # in the output anyway; the HTML page will also be generated anyway. |
| 165 | + # Note: it is not a part of the firewalled network, as there is no need |
| 166 | + # for utilities to be firewalled. And so, it can have its own ports exposed. |
| 167 | + # TODO: Is there a proper "Docker way" to run nginx in the "status" container? |
| 168 | + webview: |
| 169 | + image: nginx |
| 170 | + volumes: |
| 171 | + - ./nginx-no-access-log.conf:/etc/nginx/conf.d/nginx-no-access-log.conf:ro |
| 172 | + - html:/usr/share/nginx/html:ro |
| 173 | + restart: unless-stopped |
| 174 | + stop_signal: SIGTERM |
| 175 | + ports: |
| 176 | + - "127.0.0.1:9090:80" |
| 177 | + |
| 178 | +volumes: |
| 179 | + iptables: |
| 180 | + html: |
0 commit comments