diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ce8f9a8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +.git +.gitignore + +Dockerfile +docker-compose*.yml + +code/ +doc/ +asset/ + +*.log +*.tmp +tmp/ + +olcrtc +build/ +dist/ +coverage.out diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..029764f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# syntax=docker/dockerfile:1.7 + +ARG GO_VERSION=1.25 +ARG ALPINE_VERSION=3.22 + +FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS build + +WORKDIR /src + +RUN apk add --no-cache ca-certificates git + +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY . . + +ARG TARGETOS=linux +ARG TARGETARCH=amd64 + +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ + go build -trimpath -ldflags="-s -w" -o /out/olcrtc ./cmd/olcrtc + +FROM alpine:${ALPINE_VERSION} AS runtime + +RUN apk add --no-cache ca-certificates tzdata && \ + addgroup -S olcrtc && \ + mkdir -p /usr/share/olcrtc /var/lib/olcrtc && \ + adduser -S -D -h /var/lib/olcrtc -s /sbin/nologin -G olcrtc olcrtc && \ + chown -R olcrtc:olcrtc /var/lib/olcrtc + +COPY --from=build /out/olcrtc /usr/local/bin/olcrtc +COPY internal/names/data/names internal/names/data/surnames /usr/share/olcrtc/ +COPY docker/olcrtc-entrypoint.sh /usr/local/bin/olcrtc-entrypoint +COPY docker/olcrtc-healthcheck.sh /usr/local/bin/olcrtc-healthcheck + +RUN chmod 0755 /usr/local/bin/olcrtc /usr/local/bin/olcrtc-entrypoint /usr/local/bin/olcrtc-healthcheck + +USER olcrtc:olcrtc +WORKDIR /var/lib/olcrtc + +ENV OLCRTC_MODE=srv \ + OLCRTC_PROVIDER=telemost \ + OLCRTC_DATA_DIR=/usr/share/olcrtc \ + OLCRTC_DNS=1.1.1.1:53 \ + OLCRTC_KEY_FILE=/var/lib/olcrtc/key.hex + +VOLUME ["/var/lib/olcrtc"] + +HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \ + CMD ["/usr/local/bin/olcrtc-healthcheck"] + +ENTRYPOINT ["/usr/local/bin/olcrtc-entrypoint"] diff --git a/docker-compose.server.yml b/docker-compose.server.yml new file mode 100644 index 0000000..522de34 --- /dev/null +++ b/docker-compose.server.yml @@ -0,0 +1,19 @@ +services: + olcrtc-server: + build: + context: . + image: olcrtc/server:local + container_name: olcrtc-server + restart: unless-stopped + environment: + OLCRTC_ROOM_ID: "${OLCRTC_ROOM_ID:?set OLCRTC_ROOM_ID}" + OLCRTC_KEY: "${OLCRTC_KEY:-}" + OLCRTC_DNS: "${OLCRTC_DNS:-1.1.1.1:53}" + OLCRTC_DUO: "${OLCRTC_DUO:-false}" + OLCRTC_DEBUG: "${OLCRTC_DEBUG:-false}" + volumes: + - olcrtc-state:/var/lib/olcrtc + init: true + +volumes: + olcrtc-state: diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..eb87fd4 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,60 @@ +# OlcRTC server Docker image + +This image runs `olcrtc` in server mode. The server does not expose an inbound +TCP port; it keeps outbound WebSocket/WebRTC connections to Telemost and relays +client traffic through the room. + +## Build + +```bash +docker build -t olcrtc/server:local . +``` + +For Podman: + +```bash +podman build -t olcrtc/server:local . +``` + +## Run + +```bash +docker run -d \ + --name olcrtc-server \ + --restart unless-stopped \ + -e OLCRTC_ROOM_ID="your-room-id" \ + -e OLCRTC_KEY="64-hex-character-shared-key" \ + -v olcrtc-state:/var/lib/olcrtc \ + olcrtc/server:local +``` + +If `OLCRTC_KEY` is omitted, the entrypoint generates a 32-byte key, stores it +in `/var/lib/olcrtc/key.hex`, and prints it once to the logs: + +```bash +docker logs olcrtc-server +``` + +Use the same key on clients. + +## Compose + +```bash +export OLCRTC_ROOM_ID="your-room-id" +export OLCRTC_KEY="64-hex-character-shared-key" +docker compose -f docker-compose.server.yml up -d --build +``` + +Optional environment variables: + +- `OLCRTC_DNS`: DNS resolver for outbound TCP dials, default `1.1.1.1:53` +- `OLCRTC_DUO`: set to `true` for two parallel WebRTC channels +- `OLCRTC_DEBUG`: set to `true` for verbose logs +- `OLCRTC_KEY_FILE`: persistent key path, default `/var/lib/olcrtc/key.hex` + +## Operational notes + +- The container runs as a non-root `olcrtc` user. +- The runtime image includes CA certificates for Telemost HTTPS/WSS. +- The healthcheck verifies that the container's PID 1 is the `olcrtc` process. +- No `EXPOSE` is declared because server mode does not accept inbound traffic. diff --git a/docker/olcrtc-entrypoint.sh b/docker/olcrtc-entrypoint.sh new file mode 100755 index 0000000..bce7aa5 --- /dev/null +++ b/docker/olcrtc-entrypoint.sh @@ -0,0 +1,79 @@ +#!/bin/sh +set -eu + +die() { + echo "olcrtc-entrypoint: $*" >&2 + exit 1 +} + +bool_flag() { + case "${1:-}" in + 1|true|TRUE|yes|YES|on|ON) return 0 ;; + *) return 1 ;; + esac +} + +make_key() { + if command -v od >/dev/null 2>&1; then + od -An -N32 -tx1 /dev/urandom | tr -d ' \n' + else + hexdump -n 32 -e '32/1 "%02x"' /dev/urandom + fi +} + +if [ "${1:-}" = "olcrtc" ]; then + shift +fi + +if [ "$#" -gt 0 ]; then + exec /usr/local/bin/olcrtc "$@" +fi + +mode="${OLCRTC_MODE:-srv}" +room_id="${OLCRTC_ROOM_ID:-${ROOM_ID:-}}" +provider="${OLCRTC_PROVIDER:-telemost}" +data_dir="${OLCRTC_DATA_DIR:-/usr/share/olcrtc}" +dns_server="${OLCRTC_DNS:-1.1.1.1:53}" +key="${OLCRTC_KEY:-${KEY:-}}" +key_file="${OLCRTC_KEY_FILE:-/var/lib/olcrtc/key.hex}" + +[ "$mode" = "srv" ] || die "server image defaults to OLCRTC_MODE=srv; got '$mode'" +[ -n "$room_id" ] || die "set OLCRTC_ROOM_ID to the Telemost room id" + +if [ -z "$key" ]; then + if [ -s "$key_file" ]; then + key="$(tr -d '[:space:]' < "$key_file")" + else + key="$(make_key)" + umask 077 + printf '%s\n' "$key" > "$key_file" + echo "olcrtc-entrypoint: generated encryption key and saved it to $key_file" >&2 + echo "olcrtc-entrypoint: OLCRTC_KEY=$key" >&2 + fi +fi + +case "$key" in + *[!0-9a-fA-F]*) + die "OLCRTC_KEY must be a 64-character hex string" + ;; +esac + +[ "${#key}" -eq 64 ] || die "OLCRTC_KEY must be 64 hex characters" + +set -- /usr/local/bin/olcrtc \ + -mode "$mode" \ + -provider "$provider" \ + -id "$room_id" \ + -key "$key" \ + -data "$data_dir" \ + -dns "$dns_server" + +if bool_flag "${OLCRTC_DUO:-}"; then + set -- "$@" -duo +fi + +if bool_flag "${OLCRTC_DEBUG:-}"; then + set -- "$@" -debug +fi + +exec "$@" diff --git a/docker/olcrtc-healthcheck.sh b/docker/olcrtc-healthcheck.sh new file mode 100755 index 0000000..e21e47e --- /dev/null +++ b/docker/olcrtc-healthcheck.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu + +exe="$(readlink /proc/1/exe 2>/dev/null || true)" +case "$exe" in + */olcrtc) exit 0 ;; + *) exit 1 ;; +esac