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