# syntax=docker/dockerfile:1.7 # # Packages nostr-vpn (github.com/mmalmi/nostr-vpn) as the paid-exit seller # daemon + its web control panel. Both apps/nostr-vpn and apps/nostr-vpn-web # build from this one image (same binaries, different entrypoint/command), # mirroring upstream's own umbrel/docker-compose.yml, which runs `daemon` # and `web` as two containers sharing one /data volume with no network link # between them — reviewed directly, not assumed. # # This is upstream's own umbrel/Dockerfile, unchanged except for how the # source arrives (a pinned commit tarball here, instead of a local checkout # in their build context) — see docs/nostr-vpn-integration-plan.md for why # the pin exists and what was verified against this exact commit. ARG NVPN_COMMIT=87f19447741998ab5a06aadc701abc7ae021004b FROM debian:bookworm-slim AS source ARG NVPN_COMMIT # git clone, not a codeload.github.com/archive/.tar.gz tarball: the # latter 404s from this environment even for refs/heads/main HEAD (network # policy on that specific endpoint, not a real upstream 404 — plain # `git clone https://github.com/...` works fine). RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates git \ && rm -rf /var/lib/apt/lists/* WORKDIR /src # GitHub's anonymous smart-HTTP upload-pack refuses to fetch an arbitrary # SHA directly (only advertised refs) — fetch main by name and verify the # pinned commit is actually what we land on, so a force-push to main can't # silently swap out the reviewed code. RUN git init -q . \ && git remote add origin https://github.com/mmalmi/nostr-vpn.git \ && git fetch -q --depth 1 origin master \ && git checkout -q FETCH_HEAD \ && test "$(git rev-parse HEAD)" = "${NVPN_COMMIT}" \ && rm -rf .git FROM node:24-bookworm AS web-builder WORKDIR /work/web/control-panel COPY --from=source /src/web/control-panel/package.json /src/web/control-panel/pnpm-lock.yaml ./ RUN --mount=type=cache,id=nostr-vpn-pnpm-store,target=/pnpm/store \ corepack enable \ && corepack prepare pnpm@10.28.2 --activate \ && pnpm install --frozen-lockfile --store-dir /pnpm/store COPY --from=source /src/web/control-panel ./ RUN pnpm run build FROM rust:1.94-bookworm AS rust-builder ARG TARGETPLATFORM WORKDIR /work RUN apt-get update \ && apt-get install -y --no-install-recommends \ clang \ libclang-dev \ libdbus-1-dev \ pkg-config \ && rm -rf /var/lib/apt/lists/* COPY --from=source /src/Cargo.toml /src/Cargo.lock ./ COPY --from=source /src/crates ./crates COPY --from=source /src/vendor ./vendor RUN --mount=type=cache,id=nostr-vpn-cargo-registry-${TARGETPLATFORM},target=/usr/local/cargo/registry \ --mount=type=cache,id=nostr-vpn-cargo-git-${TARGETPLATFORM},target=/usr/local/cargo/git \ --mount=type=cache,id=nostr-vpn-cargo-target-${TARGETPLATFORM},target=/work/target \ cargo build --release -p nvpn -p nostr-vpn-web \ && mkdir -p /out \ && cp /work/target/release/nvpn /out/nvpn \ && cp /work/target/release/nostr-vpn-web /out/nvpn-web FROM debian:bookworm-slim AS runtime LABEL org.opencontainers.image.source="https://github.com/mmalmi/nostr-vpn" \ org.opencontainers.image.description="nostr-vpn, packaged as an Archipelago paid-exit seller app" \ org.opencontainers.image.licenses="MIT" RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ iproute2 \ iptables \ iputils-ping \ libdbus-1-3 \ procps \ wireguard-tools \ && rm -rf /var/lib/apt/lists/* COPY --from=rust-builder /out/nvpn /usr/local/bin/nvpn COPY --from=rust-builder /out/nvpn-web /usr/local/bin/nvpn-web COPY --from=web-builder /work/web/control-panel/dist /usr/share/nostr-vpn/web COPY docker-entrypoint.sh /usr/local/bin/archy-nvpn-entrypoint.sh RUN chmod +x /usr/local/bin/archy-nvpn-entrypoint.sh ENV HOME=/data/home \ XDG_CONFIG_HOME=/data/config \ NVPN_CLI_PATH=/usr/local/bin/nvpn \ RUST_LOG=info EXPOSE 38080 VOLUME ["/data"] # No image-level ENTRYPOINT/CMD: apps/nostr-vpn and apps/nostr-vpn-web set # their own entrypoint/custom_args in their manifests (daemon vs. web), # both pointing at archy-nvpn-entrypoint.sh — see that script for why the # seed-config step has to run before either binary starts.