# Docker Deployment quicprochat includes a multi-stage Dockerfile and a Docker Compose configuration for building and running the server in containers. --- ## Quick start ```bash docker compose up ``` This builds the server image (if not already built) and starts a single `server` service listening on port `7000`. The server will generate a self-signed TLS certificate on first launch and begin accepting QUIC connections. To rebuild after code changes: ```bash docker compose up --build ``` To run in the background: ```bash docker compose up -d ``` --- ## Docker Compose configuration The `docker-compose.yml` at the repository root defines a single service: ```yaml services: server: build: context: . dockerfile: docker/Dockerfile ports: - "7000:7000/udp" environment: RUST_LOG: "info" QPC_LISTEN: "0.0.0.0:7000" QPC_DATA_DIR: "/var/lib/quicprochat" QPC_PRODUCTION: "true" volumes: - server-data:/var/lib/quicprochat restart: unless-stopped volumes: server-data: ``` ### Port mapping The container exposes port `7000` (QUIC/UDP). Note that QUIC uses UDP, so ensure your firewall allows UDP traffic on this port. ### Restart policy `restart: unless-stopped` ensures the server restarts automatically after crashes but stays stopped if you explicitly `docker compose stop` or `docker compose down`. --- ## Multi-stage Docker build The Dockerfile at `docker/Dockerfile` uses a two-stage build to produce a minimal runtime image. ### Stage 1: Builder (`rust:bookworm`) ```dockerfile FROM rust:bookworm AS builder WORKDIR /build # Copy manifests first so dependency layers are cached independently of source. COPY Cargo.toml Cargo.lock ./ COPY crates/quicprochat-core/Cargo.toml crates/quicprochat-core/Cargo.toml # ... (all 9 crate manifests) # Create dummy source files for dependency caching. RUN mkdir -p ... && echo 'fn main() {}' > ... # Schemas must exist before the proto crate's build.rs runs. COPY schemas/ schemas/ # Build dependencies only (cache layer). RUN cargo build --release --bin qpc-server 2>/dev/null || true # Copy real source and build for real. COPY crates/ crates/ RUN cargo build --release --bin qpc-server ``` Key steps: 1. **Base image**: `rust:bookworm` (Debian Bookworm with the Rust toolchain pre-installed). 2. **No system compiler required**: Unlike v1, the builder stage does not install `capnproto`. The v2 Protobuf compiler is vendored by `protobuf-src` and compiled automatically as part of `cargo build`. 3. **Copy manifests first**: `Cargo.toml` and `Cargo.lock` are copied before source code with dummy stubs so that dependency compilation is cached in a separate Docker layer. 4. **Copy schemas**: The `schemas/` directory is copied before the dependency build because `quicprochat-proto/build.rs` references it. 5. **Copy real source and build**: After the dependency cache layer, real source files are copied in and `cargo build --release` produces the final binary. ### Stage 2: Runtime (`debian:bookworm-slim`) ```dockerfile FROM debian:bookworm-slim AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /build/target/release/qpc-server /usr/local/bin/qpc-server RUN groupadd --system qpc \ && useradd --system --gid qpc --no-create-home --shell /usr/sbin/nologin qpc \ && mkdir -p /var/lib/quicprochat \ && chown qpc:qpc /var/lib/quicprochat EXPOSE 7000 VOLUME ["/var/lib/quicprochat"] ENV RUST_LOG=info \ QPC_LISTEN=0.0.0.0:7000 \ QPC_DATA_DIR=/var/lib/quicprochat \ QPC_TLS_CERT=/var/lib/quicprochat/server-cert.der \ QPC_TLS_KEY=/var/lib/quicprochat/server-key.der \ QPC_PRODUCTION=true HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD test -f /var/lib/quicprochat/server-cert.der || exit 1 USER qpc CMD ["qpc-server"] ``` Key characteristics: - **Minimal image**: No Rust toolchain, no build tools, no `protoc` binary. - **`ca-certificates`**: Included for future HTTPS calls (e.g., ACME certificate provisioning). - **Dedicated user**: The container runs as the `qpc` system user (not `root`) for defense in depth. - **Named volume**: `/var/lib/quicprochat` is declared as a `VOLUME` for data persistence. - **`QPC_PRODUCTION=true`**: The runtime image defaults to production mode, requiring pre-existing TLS certificates and a strong auth token. --- ## Volume persistence The server stores its state (TLS certificates, KeyPackages, delivery queues, OPAQUE setup, KT log) in the data directory. Mount a volume to persist this data across container restarts: ```yaml services: server: # ... existing config ... volumes: - server-data:/var/lib/quicprochat volumes: server-data: ``` Or use a bind mount for easier inspection: ```bash mkdir -p ./server-data docker run -d \ --name quicprochat \ -p 7000:7000/udp \ -v "$(pwd)/server-data:/var/lib/quicprochat" \ -e QPC_ALLOW_INSECURE_AUTH=true \ -e QPC_PRODUCTION=false \ -e RUST_LOG=info \ qpc-server ``` Without a volume, all server state (including TLS certificates and message queues) is lost when the container is removed. The server will generate a new self-signed certificate on each fresh start, which means clients will need the new certificate to connect. --- ## Building just the image To build the Docker image without starting a container: ```bash docker build -t qpc-server -f docker/Dockerfile . ``` To run it in development mode (without production validation): ```bash docker run -d \ --name quicprochat \ -p 7000:7000/udp \ -e QPC_ALLOW_INSECURE_AUTH=true \ -e QPC_PRODUCTION=false \ -e RUST_LOG=info \ qpc-server ``` --- ## Connecting the client to a containerised server When the server runs in Docker with `docker compose up`, the client can connect from the host: ```bash # Extract the server's TLS cert from the container volume docker compose cp server:/var/lib/quicprochat/server-cert.der ./data/server-cert.der # Connect cargo run -p quicprochat-client -- ping \ --ca-cert ./data/server-cert.der \ --server-name localhost ``` If you mounted a bind volume (e.g., `./server-data:/var/lib/quicprochat`), the certificate is directly accessible at `./server-data/server-cert.der`. --- ## Next steps - [Running the Server](running-the-server.md) -- server configuration without Docker - [Running the Client](running-the-client.md) -- CLI subcommands - [Demo Walkthrough](demo-walkthrough.md) -- step-by-step messaging scenario