forked from cloud/ovgate
Add container build, compose example and deployment docs
Multi-stage Dockerfile on debian:trixie-slim. openvpn3 and lwIP are cloned at pinned refs and handed to CMake through OVG_OPENVPN3_DIR/OVG_LWIP_DIR rather than left to FetchContent, whose GIT_TAG master would make the same Dockerfile build a different VPN client each week. The unit suite runs in the builder stage. docker/openvpngate.conf overrides only the keys whose host default is wrong inside a container -- loopback listen addresses, which make a published port reach nothing, and relative state paths, which put the node failure history on a layer that gets thrown away. Everything else stays absent and takes the compiled-in default so the file cannot drift from the code. The compose example drops every capability, runs read-only as uid 10001 and publishes both ports to host loopback: the admin endpoint has no auth and includes POST /switch. That configuration is the design constraint of this project (no root, no tun device) turned into something testable. docs/DOCKER.md 8 records what was checked against the source and what was not: this sandbox has no docker daemon, so neither the image build nor the compose file has actually been run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5782207744
commit
f37cd0a125
@@ -0,0 +1,71 @@
|
||||
# openvpngate -- configuration baked into the container image.
|
||||
#
|
||||
# This file sets ONLY the keys whose host default is wrong inside a container.
|
||||
# Everything else is left absent and takes the compiled-in default, so this
|
||||
# file cannot drift from the code the way a copied-and-edited full config does.
|
||||
#
|
||||
# etc/openvpngate.conf in the source tree is the annotated reference: every key,
|
||||
# its default, and why that is the default. Read that one to change behaviour,
|
||||
# then add the key here.
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
[socks5]
|
||||
# ---------------------------------------------------------------------------
|
||||
# The default is 127.0.0.1, which inside a container means "reachable from this
|
||||
# container only" -- a published port would connect to nothing. Bind everywhere
|
||||
# and let the container runtime decide who gets to reach it: docker-compose.yml
|
||||
# publishes this to host loopback, not to the LAN.
|
||||
listen_address = 0.0.0.0
|
||||
listen_port = 1080
|
||||
|
||||
require_auth = true
|
||||
|
||||
# Credentials stay out of the image. Mount a file here (docker-compose.yml
|
||||
# does) -- SIGHUP re-reads it without dropping a live session:
|
||||
#
|
||||
# docker compose kill -s HUP openvpngate
|
||||
#
|
||||
# If this path is missing the process exits at startup with
|
||||
# "config: cannot open auth file"; if it is a *directory* -- which is what
|
||||
# Docker silently creates for a bind mount whose source does not exist -- the
|
||||
# file parses as empty and startup warns "every login will be refused". The
|
||||
# compose file uses create_host_path: false so that case fails loudly instead.
|
||||
auth_file = /etc/openvpngate/socks5.auth
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
[vpngate]
|
||||
# ---------------------------------------------------------------------------
|
||||
# Absolute. The default is relative (var/vpngate_cache.csv) and would resolve
|
||||
# against the working directory; inside the image that is /var/lib/openvpngate,
|
||||
# which happens to be right, but only by accident. Say it explicitly, because
|
||||
# this is also the one path that survives a container replacement and the one
|
||||
# directory a read-only rootfs still permits writing to.
|
||||
cache_path = /var/lib/openvpngate/vpngate_cache.csv
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
[selector]
|
||||
# ---------------------------------------------------------------------------
|
||||
# Same reasoning. Worth persisting for a different reason though: this is the
|
||||
# record of which nodes have failed on you, and losing it on every `up` means
|
||||
# walking back into the same broken node with a flattering API score.
|
||||
history_path = /var/lib/openvpngate/node_history.tsv
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
[admin]
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bound everywhere for the same reason as socks5 above -- but this endpoint has
|
||||
# NO authentication and includes POST /switch, so whoever can reach it can force
|
||||
# your gateway onto another node. It is protected here by *publishing* rules,
|
||||
# not by the bind address: keep it on 127.0.0.1 on the host side, or set
|
||||
# enabled = false and drop the HEALTHCHECK from the Dockerfile, which probes it.
|
||||
enabled = true
|
||||
listen_address = 0.0.0.0
|
||||
listen_port = 9080
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
[log]
|
||||
# ---------------------------------------------------------------------------
|
||||
# stderr, so that `docker logs` and the compose log driver see it. Logging to a
|
||||
# file inside a container puts the record on the layer that gets thrown away.
|
||||
level = info
|
||||
file = -
|
||||
@@ -0,0 +1,32 @@
|
||||
# SOCKS5 credentials, one per line: <user>:<secret>
|
||||
#
|
||||
# cp docker/socks5.auth.example docker/socks5.auth
|
||||
# $EDITOR docker/socks5.auth
|
||||
#
|
||||
# docker-compose.yml mounts docker/socks5.auth read-only into the container.
|
||||
# Reloaded on SIGHUP without dropping a live session:
|
||||
#
|
||||
# docker compose kill -s HUP openvpngate
|
||||
#
|
||||
# Two accepted forms.
|
||||
#
|
||||
# 1. Plaintext. Hashed with a random salt when the file is read, so it is never
|
||||
# held in memory in the clear -- but it is sitting in the clear right here,
|
||||
# which is the part that matters on a shared host.
|
||||
#
|
||||
# alice:changeme
|
||||
#
|
||||
# 2. Pre-hashed: sha256$<salt_hex>$<sha256_hex(salt_hex + password)>. Note the
|
||||
# salt is concatenated as its *hex text*, not as raw bytes. Generate one:
|
||||
#
|
||||
# salt=$(openssl rand -hex 16)
|
||||
# printf 'alice:sha256$%s$%s\n' "$salt" \
|
||||
# "$(printf '%s' "${salt}${PASSWORD}" | sha256sum | cut -d' ' -f1)"
|
||||
#
|
||||
# Lines starting with '#' and blank lines are ignored. A malformed line is a
|
||||
# hard startup error, not a skipped entry: half-loaded credentials are worse
|
||||
# than none.
|
||||
#
|
||||
# The entry below is an example and will be rejected by anyone paying
|
||||
# attention. Replace it.
|
||||
alice:changeme
|
||||
Reference in New Issue
Block a user