subnets add
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
OUTLINE_TRANSPORT=ss://secret@IP:PORT/?outline=1&prefix=POST%20
|
||||||
|
SERVERURL=PUBLIC_IP
|
||||||
|
PEERS=3
|
||||||
|
INTERNAL_SUBNET=10.13.13.0
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
* text=auto
|
||||||
|
*.sh text eol=lf
|
||||||
|
Dockerfile text eol=lf
|
||||||
|
docker-compose.yml text eol=lf
|
||||||
|
root/etc/** text eol=lf
|
||||||
|
root/defaults/** text eol=lf
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.env
|
||||||
|
wireguard-config
|
||||||
|
wireguard-config/peer*
|
||||||
|
wireguard-config/wg0.conf
|
||||||
|
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
FROM golang:1.24-bookworm AS builder
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y git
|
||||||
|
|
||||||
|
# Клонируем репозиторий и собираем приложение
|
||||||
|
WORKDIR /outline-sdk
|
||||||
|
RUN git clone https://github.com/OutlineFoundation/outline-sdk.git .
|
||||||
|
WORKDIR /outline-sdk/x/examples/outline-cli
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=1 go build -o /outline-cli -ldflags="-extldflags=-static" .
|
||||||
|
|
||||||
|
FROM debian:bookworm
|
||||||
|
RUN apt-get update && apt-get install -y curl wget
|
||||||
|
# Устанавливаем необходимые утилиты для работы сети и создаем пустой resolv.conf.head
|
||||||
|
RUN apt-get update && apt-get install -y iproute2 iptables && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
touch /etc/resolv.conf.head
|
||||||
|
|
||||||
|
# Копируем собранный бинарный файл из этапа сборки
|
||||||
|
COPY --from=builder /outline-cli /usr/local/bin/outline-cli
|
||||||
|
|
||||||
|
# Обертка-энтрипоинт: готовит DNS и запускает outline-cli
|
||||||
|
COPY entrypoint.sh /usr/local/bin/outline-entrypoint.sh
|
||||||
|
|
||||||
|
# Делаем бинарный файл исполняемым
|
||||||
|
RUN chmod +x /usr/local/bin/outline-cli /usr/local/bin/outline-entrypoint.sh
|
||||||
|
|
||||||
|
# Точка входа
|
||||||
|
ENTRYPOINT ["/usr/local/bin/outline-entrypoint.sh"]
|
||||||
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
services:
|
||||||
|
outline-client:
|
||||||
|
build: .
|
||||||
|
container_name: outline-client
|
||||||
|
privileged: true
|
||||||
|
# WireGuard UDP port is published from this service because
|
||||||
|
# the wireguard container shares this network namespace.
|
||||||
|
ports:
|
||||||
|
- "51821:51820/udp"
|
||||||
|
environment:
|
||||||
|
# Replace with your Outline access key.
|
||||||
|
OUTLINE_TRANSPORT: "${OUTLINE_TRANSPORT}"
|
||||||
|
INTERNAL_SUBNET: "${INTERNAL_SUBNET}"
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_ADMIN
|
||||||
|
devices:
|
||||||
|
- /dev/net/tun:/dev/net/tun
|
||||||
|
security_opt:
|
||||||
|
- apparmor:unconfined
|
||||||
|
sysctls:
|
||||||
|
- net.ipv4.ip_forward=1
|
||||||
|
- net.ipv4.conf.all.src_valid_mark=1
|
||||||
|
- net.ipv4.conf.all.rp_filter=0
|
||||||
|
- net.ipv4.conf.default.rp_filter=0
|
||||||
|
- net.ipv6.conf.all.forwarding=0
|
||||||
|
- net.ipv6.conf.all.disable_ipv6=1
|
||||||
|
- net.ipv6.conf.default.disable_ipv6=1
|
||||||
|
restart: unless-stopped
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "50m"
|
||||||
|
max-file: "5"
|
||||||
|
|
||||||
|
wireguard:
|
||||||
|
image: lscr.io/linuxserver/wireguard:latest
|
||||||
|
container_name: wg2outline
|
||||||
|
depends_on:
|
||||||
|
- outline-client
|
||||||
|
# Important: share network stack with outline-client so all
|
||||||
|
# traffic from WG peers leaves through Outline routing/policy.
|
||||||
|
network_mode: "service:outline-client"
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_MODULE
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=Etc/UTC
|
||||||
|
# Public IP or domain of this server for peers.
|
||||||
|
- SERVERURL=${SERVERURL}
|
||||||
|
- SERVERPORT=51821
|
||||||
|
- PEERS=${PEERS:-1}
|
||||||
|
- PEERDNS=1.1.1.1
|
||||||
|
- INTERNAL_SUBNET=${INTERNAL_SUBNET}
|
||||||
|
# Keepalive helps on NAT/mobile networks.
|
||||||
|
- PERSISTENTKEEPALIVE_PEERS=25
|
||||||
|
# Optional for enterprise networks that block MTU/fragmentation.
|
||||||
|
- MTU=1280
|
||||||
|
# Firewall/NAT is handled by the host/namespace setup.
|
||||||
|
- LOG_CONFS=true
|
||||||
|
volumes:
|
||||||
|
- ./wireguard-config:/config
|
||||||
|
- /lib/modules:/lib/modules:ro
|
||||||
|
sysctls:
|
||||||
|
- net.ipv4.conf.all.src_valid_mark=1
|
||||||
|
restart: unless-stopped
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "50m"
|
||||||
|
max-file: "5"
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ -z "${OUTLINE_TRANSPORT:-}" ]; then
|
||||||
|
echo "ERROR: OUTLINE_TRANSPORT is required (ss://...)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Some distros mount /etc/resolv.conf as a file from the host.
|
||||||
|
# We want to ensure DNS works reliably inside the VPN network namespace.
|
||||||
|
umount /etc/resolv.conf 2>/dev/null || true
|
||||||
|
[ -f /etc/resolv.conf ] || printf 'nameserver 1.1.1.1\n' > /etc/resolv.conf
|
||||||
|
|
||||||
|
/usr/local/bin/outline-cli -transport "${OUTLINE_TRANSPORT}" &
|
||||||
|
OUTLINE_PID=$!
|
||||||
|
|
||||||
|
# Allow local Docker and WireGuard subnets to bypass Outline policy routing.
|
||||||
|
# Without this, reply packets to WG peers can be forced into table 233.
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
if ip rule show | grep -q "table 233"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
WG_SUBNET="${INTERNAL_SUBNET}/24"
|
||||||
|
ip rule add pref 100 to "${WG_SUBNET}" lookup main 2>/dev/null || true
|
||||||
|
|
||||||
|
# Docker/custom bridge subnets differ per host (e.g. 172.17.0.0/16, 10.200.0.0/16).
|
||||||
|
pref=101
|
||||||
|
for cidr in $(ip -4 route show proto kernel scope link 2>/dev/null | awk '$2 == "dev" { print $1 }'); do
|
||||||
|
ip rule add pref "${pref}" to "${cidr}" lookup main 2>/dev/null || true
|
||||||
|
pref=$((pref + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ensure exactly one NAT rule for traffic leaving via Outline interface.
|
||||||
|
if iptables -t nat -C POSTROUTING -o outline+ -j MASQUERADE 2>/dev/null; then
|
||||||
|
while iptables -t nat -C POSTROUTING -o outline+ -j MASQUERADE 2>/dev/null; do
|
||||||
|
iptables -t nat -D POSTROUTING -o outline+ -j MASQUERADE || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
iptables -t nat -A POSTROUTING -o outline+ -j MASQUERADE
|
||||||
|
|
||||||
|
wait "$OUTLINE_PID"
|
||||||
|
|
||||||
Executable
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# ./test-wg-client.sh [path-to-peer-conf]
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# ./test-wg-client.sh ./wireguard-config/peer1/peer1.conf
|
||||||
|
|
||||||
|
PEER_CONF="${1:-./wireguard-config/peer2/peer2.conf}"
|
||||||
|
CLIENT_NAME="${WG_TEST_CONTAINER_NAME:-wg-test-client}"
|
||||||
|
WAIT_SECONDS="${WG_TEST_WAIT_SECONDS:-15}"
|
||||||
|
|
||||||
|
if [[ ! -f "${PEER_CONF}" ]]; then
|
||||||
|
echo "ERROR: peer config not found: ${PEER_CONF}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
docker rm -f "${CLIENT_NAME}" >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
echo "==> Preparing clean test container: ${CLIENT_NAME}"
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
echo "==> Starting temporary WireGuard client"
|
||||||
|
docker run -d \
|
||||||
|
--name "${CLIENT_NAME}" \
|
||||||
|
--privileged \
|
||||||
|
--cap-add NET_ADMIN \
|
||||||
|
--cap-add SYS_MODULE \
|
||||||
|
--device /dev/net/tun:/dev/net/tun \
|
||||||
|
-v "$(realpath "${PEER_CONF}"):/etc/wireguard/wg0.conf:ro" \
|
||||||
|
--entrypoint sh \
|
||||||
|
alpine:3.20 \
|
||||||
|
-c "apk add --no-cache wireguard-tools iproute2 iptables ip6tables openresolv curl >/dev/null && wg-quick up wg0 && tail -f /dev/null" \
|
||||||
|
>/dev/null
|
||||||
|
|
||||||
|
echo "==> Waiting ${WAIT_SECONDS}s for tunnel to initialize"
|
||||||
|
sleep "${WAIT_SECONDS}"
|
||||||
|
|
||||||
|
if [[ "$(docker inspect -f '{{.State.Running}}' "${CLIENT_NAME}")" != "true" ]]; then
|
||||||
|
echo "ERROR: test client container exited before tunnel check" >&2
|
||||||
|
echo "==> Last container logs:" >&2
|
||||||
|
docker logs "${CLIENT_NAME}" >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> WireGuard status inside client"
|
||||||
|
docker exec "${CLIENT_NAME}" wg show || true
|
||||||
|
|
||||||
|
echo "==> Test request through client namespace: https://web.telegram.org/"
|
||||||
|
docker run --rm \
|
||||||
|
--network=container:"${CLIENT_NAME}" \
|
||||||
|
curlimages/curl:8.7.1 \
|
||||||
|
-sS -I --max-time 20 https://web.telegram.org/
|
||||||
|
|
||||||
|
echo "==> External IP seen via WG client namespace"
|
||||||
|
docker run --rm \
|
||||||
|
--network=container:"${CLIENT_NAME}" \
|
||||||
|
curlimages/curl:8.7.1 \
|
||||||
|
-sS --max-time 20 https://ifconfig.me
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "==> Test completed successfully"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = ${CLIENT_IP}
|
||||||
|
PrivateKey = $(cat /config/${PEER_ID}/privatekey-${PEER_ID})
|
||||||
|
ListenPort = 51820
|
||||||
|
DNS = ${PEERDNS}
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = $(cat /config/server/publickey-server)
|
||||||
|
PresharedKey = $(cat /config/${PEER_ID}/presharedkey-${PEER_ID})
|
||||||
|
Endpoint = ${SERVERURL}:${SERVERPORT}
|
||||||
|
AllowedIPs = ${ALLOWEDIPS}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = ${INTERFACE}.1
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = $(cat /config/server/privatekey-server)
|
||||||
|
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
|
||||||
|
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
|
||||||
Reference in New Issue
Block a user