# One image: the Rust binary with the web UI compiled into it. # # Named Containerfile, so podman finds it without -f. The just recipes pass -f # anyway, because the docker CLI only looks for Dockerfile. # # `rust-embed` pulls web/dist into the binary in release mode, so the runtime # stage carries no assets and no web server — just the one executable. FROM oven/bun:1.4 AS web WORKDIR /web COPY web/package.json web/bun.lock ./ RUN bun install --frozen-lockfile COPY web/ ./ RUN bun run build FROM rust:1-slim-trixie AS server WORKDIR /src # libsqlite3-sys is vendored, so the build needs a C toolchain but no dev headers. RUN apt-get update && apt-get install -y --no-install-recommends gcc libc6-dev && rm -rf /var/lib/apt/lists/* COPY Cargo.toml Cargo.lock ./ COPY crates/ crates/ COPY --from=web /web/dist/ web/dist/ RUN cargo build --release -p otserver FROM debian:trixie-slim # ca-certificates is not optional: the tile proxy fetches over HTTPS. RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && useradd --system --uid 10001 --home /data opentracker \ && mkdir -p /data && chown opentracker /data COPY --from=server /src/target/release/otserver /usr/local/bin/otserver USER opentracker WORKDIR /data ENV OT_HTTP_ADDR=0.0.0.0:7372 \ OT_UDP_ADDR=0.0.0.0:7373 \ OT_DB_PATH=/data/opentracker.db \ OT_CACHE_DIR=/data/cache VOLUME /data # THE TRAP: 7373 is UDP and HTTP reverse proxies do not forward it. It needs its # own published port and its own firewall rule, or every phone silently falls # back to TLS-over-TCP and the whole point of the protocol is lost. EXPOSE 7372/tcp 7373/udp ENTRYPOINT ["otserver"]