# Multi-stage build for the didbot-dev binary, which — see its module doc at # crates/didbot-serve/src/bin/didbot-dev.rs — is the same binary for a laptop # and for this image: it refuses to start against a real zone unless it is # handed a real secret, and picks its DNS backend from the zone rather than # hardcoding the development one. # # Two stages so the runtime image never sees a compiler, a registry cache, or # any crate source: what ships is the binary and nothing that built it. FROM rust:1.90-slim-bookworm AS builder WORKDIR /build RUN apt-get update \ && apt-get install -y --no-install-recommends pkg-config libssl-dev \ && rm -rf /var/lib/apt/lists/* # Dependencies first, so an edit to application code does not re-fetch or # re-build the workspace's crates.io dependencies on every image build. COPY Cargo.toml Cargo.lock ./ COPY crates crates COPY lexicons lexicons # `--features route53` links the Route53-backed DNS provider and IMDS # credential fetch that `--tls acme` needs; see # crates/didbot-serve/src/bin/didbot-dev.rs and crates/didbot-dns/src/ # route53.rs. Left off a build that only ever targets `.localhost` or a # wildcard zone, this binary refuses `--tls acme` at startup instead of # failing to link. RUN cargo build --release -p didbot-serve --bin didbot-dev --locked --features route53 \ && strip target/release/didbot-dev # --------------------------------------------------------------------------- FROM debian:bookworm-slim AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates libcap2-bin \ && rm -rf /var/lib/apt/lists/* \ && useradd --system --uid 10001 --create-home --home-dir /home/didbot \ --shell /usr/sbin/nologin didbot COPY --from=builder /build/target/release/didbot-dev /usr/local/bin/didbot-dev # 443 is a privileged port and this image runs as an unprivileged user. With # `--network host` there is no network namespace of its own to relax # `net.ipv4.ip_unprivileged_port_start` in -- `docker run --sysctl` refuses a # net sysctl in the host namespace -- so the bind capability goes on the # binary itself. `+ep` is the whole grant: bind a low port, nothing else. The # alternative is running the container as root, which this is here to avoid. RUN setcap cap_net_bind_service=+ep /usr/local/bin/didbot-dev # The data directory is a volume mount in every deployment that matters — the # attached EBS volume in `infra/`, or a developer's own bind mount — so it is # declared here rather than baked in. A bind mount replaces this directory # entirely, so the ownership set here governs nothing at run time: what # matters is that the mounted directory on the host is owned by uid 10001, # which is why the uid above is pinned rather than left to `useradd` and why # `infra/templates/user_data.sh.tftpl` chowns the mount to that number. # # `didbot-dev`'s `create_dir` tightens whatever mode it finds to `0700` on # every open, so the *mode* of a handed directory is never trusted. Ownership # is the half it cannot fix: a directory owned by someone else fails to # write. See `crates/didbot-pds/src/wal/mod.rs`. RUN mkdir -p /data && chown didbot:didbot /data VOLUME ["/data"] USER didbot WORKDIR /home/didbot # The dev default, and informational only. Nothing terminates TLS in front of # this image, so the deployment that serves traffic runs it with `--network # host` and `--tls acme --port 443` -- see infra/templates/user_data.sh.tftpl # -- and binds no published port at all. EXPOSE 3000 ENTRYPOINT ["/usr/local/bin/didbot-dev"] CMD ["--help"]