# syntax=docker/dockerfile:1 ############################################################################### # awg_profiler — container image # # AmneziaWG is NOT packaged in Alpine's repos, and a container cannot load the # kernel module. So the data plane is the userspace implementation # `amneziawg-go`: `awg-quick` automatically falls back to it (via /dev/net/tun) # when /sys/module/amneziawg is absent — exactly the container case. # # Three builder stages compile everything statically, then a tiny Alpine # runtime carries only the finished binaries + a handful of CLI helpers the # tool shells out to (awg / awg-quick / amneziawg-go / nft / qrencode). ############################################################################### # Pin the versions of the AmneziaWG userspace components for reproducible builds. ARG AWG_TOOLS_REF=master ARG AWG_GO_REF=master # ─── Stage 1: build the profiler binary (static, CGO off → runs on musl) ────── FROM golang:1.26-alpine AS app-builder WORKDIR /src # Assets in webui/ are compiled into the binary via //go:embed, so the whole # module source is needed but nothing has to be shipped alongside the binary. COPY go.mod ./ COPY *.go ./ COPY webui/ ./webui/ COPY webui_glass/ ./webui_glass/ ENV CGO_ENABLED=0 RUN go build -trimpath -ldflags="-s -w" -o /out/awg_profiler . # ─── Stage 2: build amneziawg-go (userspace WireGuard/AmneziaWG data plane) ─── FROM golang:1.26-alpine AS awggo-builder ARG AWG_GO_REF RUN apk add --no-cache git make WORKDIR /src RUN git clone --depth=1 --branch "${AWG_GO_REF}" \ https://github.com/amnezia-vpn/amneziawg-go . \ && CGO_ENABLED=0 make \ && install -Dm0755 amneziawg-go /out/amneziawg-go # ─── Stage 3: build amneziawg-tools (the `awg` + `awg-quick` C tools) ───────── FROM alpine:3.20 AS tools-builder ARG AWG_TOOLS_REF RUN apk add --no-cache git build-base linux-headers bash WORKDIR /src RUN git clone --depth=1 --branch "${AWG_TOOLS_REF}" \ https://github.com/amnezia-vpn/amneziawg-tools . \ && make -C src \ && make -C src install \ WITH_WGQUICK=yes WITH_BASHCOMPLETION=no WITH_SYSTEMDUNITS=no \ DESTDIR=/out PREFIX=/usr # ─── Stage 4: runtime ───────────────────────────────────────────────────────── FROM alpine:3.20 # awg-quick is a bash script and drives `ip` (iproute2); the profiler shells out # to nft (firewall/NAT rules) and qrencode (client QR codes). ca-certificates is # needed for the public-IP HTTPS lookup. Everything else it needs (sysctl, grep, # mktemp, …) is already provided by busybox. RUN apk add --no-cache \ bash \ iproute2 \ nftables \ libqrencode-tools \ ca-certificates # AmneziaWG userspace stack + the profiler itself. COPY --from=tools-builder /out/usr/ /usr/ COPY --from=awggo-builder /out/amneziawg-go /usr/bin/amneziawg-go COPY --from=app-builder /out/awg_profiler /usr/local/bin/awg_profiler COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh # All mutable profiler state (config, client registry, generated profiles, the # deps-installed flag) lives here; the interface .conf + nft ruleset live in # /etc/amnezia/amneziawg. Mount volumes on both to persist across restarts. ENV AWG_PROFILER_DIR=/data VOLUME ["/data", "/etc/amnezia/amneziawg"] # WireGuard/AmneziaWG listen port (UDP) and the management web UI (TCP). EXPOSE 51820/udp EXPOSE 8080/tcp ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] # Default to the web UI on all interfaces; override with any profiler subcommand. CMD ["web", "--addr", "0.0.0.0:8080"]