# OpenTAKServer image for ZYRNTOPO.
#
# Built locally rather than pulled from a registry, deliberately: it means this
# stack has no dependency on an image whose tag someone else controls, and it
# works identically on a Raspberry Pi (arm64) and an x86 box without needing a
# multi-arch publish. The cost is build time — a few minutes on a desktop, and
# closer to twenty on a Pi 4, because several Python wheels have no prebuilt
# aarch64 artefact and are compiled from source.
# Python 3.12, NOT 3.13 — and this is the single most load-bearing line here.
#
# OTS runs on gevent, and gevent's fork hook opens with a hard
#   assert sys.version_info[:2] < (3, 13)
# On 3.13 that assertion fires on every fork. The web UI on 8081 still comes up
# and the health endpoint still answers 200, so the container reports healthy —
# but the forked TLS CoT listener never survives, 8089 is never bound, and every
# client gets "connection refused" against a server that looks fine in
# `docker compose ps`. The only visible symptom is AssertionError with an empty
# message, buried in migration output.
#
# Do not bump this to 3.13+ before gevent supports it.
FROM python:3.12-slim

# ffmpeg: pulled in by OTS's video-streaming paths even when MediaMTX is off.
# curl: the compose healthcheck. build-essential + the -dev packages: lxml and
# the crypto wheels need a compiler on ARM, where no prebuilt wheel exists.
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        ffmpeg curl git build-essential libxml2-dev libxslt1-dev libffi-dev libssl-dev \
    && rm -rf /var/lib/apt/lists/*

RUN addgroup --gid 1024 ots \
    && adduser --home /app --disabled-password --gecos "" --force-badname --gid 1024 ots

USER ots
WORKDIR /app

# Create the data directory in the IMAGE, owned by ots, before anything mounts
# over it. Docker seeds a fresh named volume from whatever is at the mountpoint
# in the image — ownership included — but when the path does not exist in the
# image it creates the volume as root:root instead. The container runs as ots,
# so OTS then dies on its first startup line with
#   PermissionError: [Errno 13] Permission denied: '/app/ots-data/uploads'
# which reads as an OTS bug rather than a volume-ownership one. Deleting this
# line brings it straight back, and only on a first run with a fresh volume.
RUN mkdir -p /app/ots-data

RUN python -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH"

# Pinned to the release this stack was written and tested against. Floating on
# the default branch means a rebuild months from now silently installs a
# different server than the one your certificates and clients were set up for.
#
# Upstream tags carry NO leading "v" — the tag is `1.7.11`, not `v1.7.11`. This
# was pinned to `v1.7.11` originally and every build died at `git checkout -q`
# with an error that names pip, not the tag, so it reads as a dependency problem.
# `git ls-remote --tags https://github.com/brian7704/OpenTAKServer.git` is the
# check before changing this. (6.0.0 is the newest tag, but the env-var names in
# docker-compose.yml are 1.7.x's — moving up is a config review, not a bump.)
ARG OTS_VERSION=1.7.11
RUN pip install --no-cache-dir "git+https://github.com/brian7704/OpenTAKServer.git@${OTS_VERSION}"

# OTS imports psycopg at module load, before it has looked at any configuration,
# so it needs a libpq wrapper even on a default install that will only ever touch
# SQLite. The plain `psycopg` it depends on is the pure-Python variant, which
# finds no libpq in a -slim image and aborts startup with
#   ImportError: no pq wrapper available.
# The [binary] extra carries its own libpq, which keeps this independent of what
# Debian happens to package. Installed after OTS so it overrides the bare
# dependency rather than being overwritten by it.
RUN pip install --no-cache-dir "psycopg[binary]"

# The CA is NOT created here. Upstream's Dockerfile runs create-ca at build
# time, which bakes a certificate authority into the image layer — every rebuild
# would mint a new CA and invalidate every client certificate already enrolled,
# and anyone with the image would hold the CA key. The setup script creates it
# once, after first start, into the persistent volume where it belongs.

EXPOSE 8081 8089 8443
STOPSIGNAL SIGINT
ENTRYPOINT ["opentakserver"]
