# OP25 Core Container # Pinned to a Python major version deliberately. The bare `slim-trixie` tag # carries no version at all, so a rebuild could move the interpreter across a # major release -- which this repo has already been bitten by once, when # app/models.py only ran because trixie happened to ship 3.14 and PEP 649 # defers annotation evaluation. Matches drb-edge-node, which is already 3.14. FROM python:3.14-slim # Set environment variables ENV DEBIAN_FRONTEND=noninteractive # Install system dependencies RUN apt-get update && \ apt-get upgrade -y && \ apt-get install git pulseaudio pulseaudio-utils liquidsoap usbutils -y # Install custom PulseAudio system config (enables anonymous access for edge-node) COPY system.pa /etc/pulse/system.pa # Clone the boatbod op25 repository, PINNED (node-26#29, #46). An unpinned # clone plus CI's layer cache meant the image held whatever gr310 HEAD was at # the last cache miss. 5b58335 (gr310, 2026-08-23) is the commit tk_drb_conv # was verified against for node-26#29 and the first gr310 merge that carries # the 2026-08-03 NBFM noise/voice squelch (PR #296, op25_nbfm.py # nbfm_squelch_mode). Bump deliberately, re-checking tk_drb_conv against # tk_p25.py at the new commit. ARG OP25_COMMIT=5b583357240e0172bfae905f0c966474e0d0f094 RUN git clone -b gr310 https://github.com/boatbod/op25 /op25 && \ git -C /op25 checkout --detach "${OP25_COMMIT}" # Set the working directory WORKDIR /op25 # Run the install script to set up op25 RUN sed -i 's/sudo //g' install.sh RUN ./install.sh -f # Install Python dependencies COPY requirements.txt /tmp/requirements.txt RUN pip3 install --no-cache-dir -r /tmp/requirements.txt # DRB's trunking module for P25 conventional channels (node-26#24): reports # encryption + NAC and applies the NAC filter, which stock tk_p25 does not. COPY op25_addons/tk_drb_conv.py /op25/op25/gr-op25_repeater/apps/tk_drb_conv.py # Create the run_multi-rx_service.sh script COPY run_multi-rx_service.sh /op25/op25/gr-op25_repeater/apps/run_multi-rx_service.sh RUN chmod +x /op25/op25/gr-op25_repeater/apps/run_multi-rx_service.sh # Expose ports for HTTP control as needed, for example: EXPOSE 8001 8081 # Create and set up the configuration directory VOLUME ["/configs"] # Set the working directory in the container WORKDIR /app # Copy the rest of the directory contents into the container at /app COPY ./app /app # 1. Copy the wrapper script and make it executable COPY docker-entrypoint.sh /usr/local/bin/ RUN sed -i 's/\r$//' /usr/local/bin/docker-entrypoint.sh && \ chmod +x /usr/local/bin/docker-entrypoint.sh # 2. Update ENTRYPOINT to use the wrapper script ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] # 3. Use CMD to pass the launch command as arguments to the ENTRYPOINT script. # main.py starts uvicorn itself (see `if __name__ == "__main__"`) so the bind # address can be driven by OP25_DEBUG_EXPOSE at runtime instead of being baked # into this image at build time. CMD ["python", "main.py"]