2025-06-13 02:01:38 +02:00
|
|
|
# =================================================================
|
|
|
|
|
#
|
2025-12-15 17:54:19 +01:00
|
|
|
# Dockerfile for local build (nativ, without Cross-Compilation)
|
2025-06-13 02:01:38 +02:00
|
|
|
#
|
|
|
|
|
# =================================================================
|
|
|
|
|
|
2026-02-12 15:06:57 +01:00
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# Stage 0: Fetch static FFmpeg binaries
|
|
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# We use a static build to ensure it works in the scratch image without libraries
|
|
|
|
|
FROM mwader/static-ffmpeg:7.1 AS ffmpeg-static
|
|
|
|
|
|
2026-08-27 18:36:23 +05:00
|
|
|
# Workspace skeleton shared by the backend and frontend dependency builds.
|
|
|
|
|
FROM rust:1.95 AS workspace-skeleton
|
|
|
|
|
|
|
|
|
|
WORKDIR /src
|
|
|
|
|
COPY Cargo.toml Cargo.lock ./
|
|
|
|
|
COPY shared ./shared/
|
|
|
|
|
COPY frontend/Cargo.toml frontend/Trunk.toml ./frontend/
|
|
|
|
|
COPY backend/app/Cargo.toml backend/app/build.rs ./backend/app/
|
|
|
|
|
COPY backend/auth/Cargo.toml ./backend/auth/
|
|
|
|
|
COPY backend/btree/Cargo.toml ./backend/btree/
|
|
|
|
|
COPY backend/config-loader/Cargo.toml ./backend/config-loader/
|
|
|
|
|
COPY backend/core/Cargo.toml ./backend/core/
|
2026-09-11 08:07:10 +02:00
|
|
|
COPY backend/curation/Cargo.toml ./backend/curation/
|
2026-08-27 18:36:23 +05:00
|
|
|
COPY backend/dvr/Cargo.toml ./backend/dvr/
|
|
|
|
|
COPY backend/hls/Cargo.toml ./backend/hls/
|
|
|
|
|
COPY backend/iptv/Cargo.toml ./backend/iptv/
|
|
|
|
|
COPY backend/library/Cargo.toml ./backend/library/
|
|
|
|
|
COPY backend/media-server/Cargo.toml ./backend/media-server/
|
|
|
|
|
COPY backend/metadata/Cargo.toml ./backend/metadata/
|
|
|
|
|
COPY backend/messaging/Cargo.toml ./backend/messaging/
|
|
|
|
|
COPY backend/mpegts/Cargo.toml ./backend/mpegts/
|
|
|
|
|
COPY backend/parser/Cargo.toml ./backend/parser/
|
|
|
|
|
COPY backend/processing/Cargo.toml ./backend/processing/
|
|
|
|
|
COPY backend/repository/Cargo.toml ./backend/repository/
|
|
|
|
|
COPY backend/session/Cargo.toml ./backend/session/
|
|
|
|
|
|
|
|
|
|
RUN mkdir -p frontend/src backend/app/src/tools && \
|
|
|
|
|
printf 'fn main() {}\n' > frontend/src/main.rs && \
|
|
|
|
|
printf 'fn main() {}\n' > backend/app/src/main.rs && \
|
|
|
|
|
printf 'fn main() {}\n' > backend/app/src/tools/flags_builder.rs && \
|
2026-09-11 08:07:10 +02:00
|
|
|
for crate in auth btree config-loader core curation dvr hls iptv library media-server metadata messaging mpegts parser processing repository session; do \
|
2026-08-27 18:36:23 +05:00
|
|
|
mkdir -p "backend/${crate}/src"; \
|
|
|
|
|
printf '\n' > "backend/${crate}/src/lib.rs"; \
|
|
|
|
|
done
|
|
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# Stage 1: Build the Rust binary for production
|
|
|
|
|
# -----------------------------------------------------------------
|
2026-08-27 18:36:23 +05:00
|
|
|
FROM workspace-skeleton AS rust-build
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Get target architecture from build argument
|
|
|
|
|
ARG RUST_TARGET=x86_64-unknown-linux-musl
|
2023-10-17 10:27:37 +02:00
|
|
|
|
2026-04-10 14:56:57 +02:00
|
|
|
# Install build dependencies for Debian (trixie)
|
2025-10-26 21:46:04 +01:00
|
|
|
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
2026-05-04 19:07:41 +02:00
|
|
|
pkg-config musl-tools && \
|
2025-10-26 21:46:04 +01:00
|
|
|
apt-get clean && \
|
|
|
|
|
rm -rf /var/lib/apt/lists/*
|
2025-03-14 16:09:07 +01:00
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Set Rust compiler flags for static linking against musl
|
|
|
|
|
ENV RUSTFLAGS='-C target-feature=+crt-static'
|
2024-03-27 12:04:54 -05:00
|
|
|
|
2026-08-27 18:36:23 +05:00
|
|
|
# Build dependencies (this layer is cached until a manifest or shared code changes)
|
2025-10-26 21:46:04 +01:00
|
|
|
RUN rustup target add ${RUST_TARGET}
|
2026-08-27 18:36:23 +05:00
|
|
|
RUN cargo build -p tuliprox --target ${RUST_TARGET} --release
|
2025-07-25 12:50:10 +02:00
|
|
|
|
2026-08-27 18:36:23 +05:00
|
|
|
# Copy the backend source only after its dependency layer is complete.
|
2025-10-26 21:46:04 +01:00
|
|
|
COPY backend ./backend/
|
2026-08-27 18:36:23 +05:00
|
|
|
RUN find backend -type f -name '*.rs' -exec touch {} + && \
|
|
|
|
|
cargo build -p tuliprox --target ${RUST_TARGET} --release
|
2024-03-27 12:04:54 -05:00
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
2025-07-25 12:50:10 +02:00
|
|
|
# Stage 2: Build the rust frontend
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
2026-08-27 18:36:23 +05:00
|
|
|
FROM workspace-skeleton AS trunk-build
|
2025-07-25 12:50:10 +02:00
|
|
|
|
|
|
|
|
# Install dependencies for Trunk and WebAssembly
|
2025-10-26 21:46:04 +01:00
|
|
|
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
|
|
|
pkg-config libssl-dev curl binaryen && \
|
|
|
|
|
apt-get clean && \
|
|
|
|
|
rm -rf /var/lib/apt/lists/*
|
2024-03-28 11:58:00 +01:00
|
|
|
|
2025-07-25 12:50:10 +02:00
|
|
|
# Add wasm target & install trunk
|
|
|
|
|
RUN rustup target add wasm32-unknown-unknown
|
|
|
|
|
RUN cargo install --locked trunk wasm-bindgen-cli
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-08-17 18:04:37 +02:00
|
|
|
# Pre-build dependencies
|
|
|
|
|
WORKDIR /src/frontend
|
2026-08-27 18:36:23 +05:00
|
|
|
RUN cargo build --target wasm32-unknown-unknown --release
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Now copy the rest of the source code and build the project
|
2025-08-17 18:04:37 +02:00
|
|
|
WORKDIR /src
|
2025-10-26 21:46:04 +01:00
|
|
|
COPY frontend ./frontend/
|
2025-07-25 12:50:10 +02:00
|
|
|
|
2025-08-07 19:46:49 +02:00
|
|
|
WORKDIR /src/frontend
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-07-25 12:50:10 +02:00
|
|
|
# Run Trunk build
|
2026-08-27 18:36:23 +05:00
|
|
|
RUN find src -type f -name '*.rs' -exec touch {} + && trunk build --release
|
2024-03-27 12:04:54 -05:00
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
2026-02-12 15:06:57 +01:00
|
|
|
# Stage 3: Build video resources with ffmpeg (from linuxserver used for build time only)
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
2025-04-22 19:43:23 +02:00
|
|
|
FROM linuxserver/ffmpeg:latest AS resource-build
|
2025-05-22 18:49:47 +02:00
|
|
|
|
2025-02-23 13:04:36 +01:00
|
|
|
WORKDIR /src
|
|
|
|
|
COPY resources ./resources
|
2025-04-22 19:43:23 +02:00
|
|
|
|
|
|
|
|
# Combine ffmpeg commands into a single layer to reduce image size
|
2026-03-13 16:12:43 +01:00
|
|
|
# Convert every .jpg file in resources into a matching .ts file.
|
|
|
|
|
RUN set -eu; \
|
|
|
|
|
find ./resources -maxdepth 1 -type f -name '*.jpg' | sort | while IFS= read -r image; do \
|
|
|
|
|
output="${image%.jpg}.ts"; \
|
2026-07-08 11:52:22 +02:00
|
|
|
resource_name="$(basename "${image%.jpg}")"; \
|
2026-03-13 16:12:43 +01:00
|
|
|
ffmpeg -y -nostdin -loop 1 -framerate 30 -i "${image}" \
|
|
|
|
|
-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000 \
|
|
|
|
|
-t 10 -shortest \
|
|
|
|
|
-c:v libx264 -pix_fmt yuv420p -preset veryfast -crf 23 \
|
|
|
|
|
-x264-params "keyint=30:min-keyint=30:scenecut=0:bframes=0:open_gop=0" \
|
|
|
|
|
-c:a aac -b:a 128k -ac 2 -ar 48000 \
|
|
|
|
|
-mpegts_flags +resend_headers \
|
|
|
|
|
-muxdelay 0 -muxpreload 0 \
|
|
|
|
|
-f mpegts "${output}" || exit 1; \
|
2026-07-08 11:52:22 +02:00
|
|
|
if [ "${resource_name}" = "panel_api_provisioning" ]; then \
|
|
|
|
|
rm -f ./resources/panel_api_provisioning_hls_*.ts ./resources/panel_api_provisioning_hls.m3u8; \
|
|
|
|
|
ffmpeg -y -nostdin -loop 1 -framerate 30 -i "${image}" \
|
|
|
|
|
-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000 \
|
|
|
|
|
-t 12 -shortest \
|
|
|
|
|
-c:v libx264 -pix_fmt yuv420p -preset veryfast -crf 23 \
|
|
|
|
|
-g 60 -keyint_min 60 \
|
|
|
|
|
-force_key_frames "expr:gte(t,n_forced*2)" \
|
|
|
|
|
-x264-params "scenecut=0:bframes=0:open_gop=0" \
|
|
|
|
|
-c:a aac -b:a 128k -ac 2 -ar 48000 \
|
|
|
|
|
-mpegts_flags +resend_headers \
|
|
|
|
|
-muxdelay 0 -muxpreload 0 \
|
|
|
|
|
-f hls \
|
|
|
|
|
-hls_time 2 \
|
|
|
|
|
-hls_list_size 0 \
|
|
|
|
|
-hls_segment_type mpegts \
|
|
|
|
|
-hls_segment_filename "./resources/panel_api_provisioning_hls_%03d.ts" \
|
|
|
|
|
./resources/panel_api_provisioning_hls.m3u8 || exit 1; \
|
|
|
|
|
rm -f ./resources/panel_api_provisioning_hls.m3u8; \
|
|
|
|
|
fi; \
|
2026-01-27 00:16:40 +01:00
|
|
|
done
|
2025-05-22 17:39:06 +02:00
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# Stage 4: Prepare timezone data
|
|
|
|
|
# -----------------------------------------------------------------
|
2025-05-22 17:39:06 +02:00
|
|
|
FROM alpine:latest AS tz-prep
|
2025-05-22 18:49:47 +02:00
|
|
|
|
2025-05-22 17:39:06 +02:00
|
|
|
ARG TZ=UTC
|
2025-05-22 18:49:47 +02:00
|
|
|
ENV TZ=${TZ}
|
|
|
|
|
|
2025-05-22 17:39:06 +02:00
|
|
|
RUN apk add --no-cache tzdata \
|
|
|
|
|
&& mkdir -p /output/etc \
|
|
|
|
|
&& mkdir -p /output/usr/share \
|
|
|
|
|
&& cp -r /usr/share/zoneinfo /output/usr/share/zoneinfo \
|
2025-05-22 18:49:47 +02:00
|
|
|
&& ln -sf /usr/share/zoneinfo/${TZ} /output/etc/localtime
|
|
|
|
|
|
2025-05-22 17:39:06 +02:00
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# =================================================================
|
|
|
|
|
#
|
|
|
|
|
# Part 2: Final Image Stages
|
|
|
|
|
#
|
|
|
|
|
# =================================================================
|
|
|
|
|
|
|
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# Final Image #1: Debugging Environment (Alpine-based)
|
|
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
FROM rust:alpine AS debug
|
|
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Make the build-time argument available as a run-time environment variable
|
2025-06-13 02:01:38 +02:00
|
|
|
ARG RUST_TARGET=x86_64-unknown-linux-musl
|
|
|
|
|
ARG TZ=UTC
|
|
|
|
|
|
|
|
|
|
# Make the build-time argument available as a run-time environment variable
|
|
|
|
|
ENV RUST_TARGET=${RUST_TARGET}
|
|
|
|
|
ENV TZ=${TZ}
|
|
|
|
|
|
2026-02-12 15:06:57 +01:00
|
|
|
# Install build dependencies, debugger and ffmpeg for Alpine.
|
2025-10-26 21:46:04 +01:00
|
|
|
# 'build-base' contains gcc, make, etc.
|
|
|
|
|
# 'gdb' is required for the debugger (lldb is often more complicated in Alpine repos)
|
2026-02-12 15:06:57 +01:00
|
|
|
# 'ffmpeg' is required for the probe feature
|
2026-05-04 19:07:41 +02:00
|
|
|
RUN apk add --no-cache bash build-base perl lldb gdb ffmpeg
|
2025-06-13 02:01:38 +02:00
|
|
|
|
|
|
|
|
# Update Rust toolchain and add the necessary target
|
|
|
|
|
RUN rustup update && rustup target add $RUST_TARGET
|
|
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Create the app layout to simulate the production environment
|
2025-06-13 02:01:38 +02:00
|
|
|
WORKDIR /app
|
2025-08-07 19:46:49 +02:00
|
|
|
COPY --from=trunk-build /src/frontend/dist ./web
|
2025-06-20 13:44:54 +02:00
|
|
|
COPY --from=resource-build /src/resources ./resources
|
2025-06-13 02:01:38 +02:00
|
|
|
|
|
|
|
|
# Create a separate directory for the source code
|
|
|
|
|
WORKDIR /usr/src/tuliprox
|
|
|
|
|
COPY . .
|
|
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Copy the entrypoint script and set it as the entry point for the container
|
2025-06-13 02:01:38 +02:00
|
|
|
COPY ./docker/debug/debug-entrypoint.sh /usr/local/bin/entrypoint.sh
|
2025-10-26 21:46:04 +01:00
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# Ensure the script is executable
|
|
|
|
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
|
|
|
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
|
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# The CMD is passed as an argument to the Entrypoint script.
|
|
|
|
|
# This keeps the container running indefinitely for interactive debugging.
|
2025-06-13 02:01:38 +02:00
|
|
|
CMD ["tail", "-f", "/dev/null"]
|
|
|
|
|
|
|
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# Final Image #2: Production image based on scratch
|
|
|
|
|
# -----------------------------------------------------------------
|
2025-04-18 16:12:38 +02:00
|
|
|
FROM scratch AS scratch-final
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
ARG RUST_TARGET=x86_64-unknown-linux-musl
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-05-22 17:39:06 +02:00
|
|
|
# Copy timezone data and localtime from tz-prep
|
|
|
|
|
COPY --from=tz-prep /output/usr/share/zoneinfo /usr/share/zoneinfo
|
|
|
|
|
COPY --from=tz-prep /output/etc/localtime /etc/localtime
|
|
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Copy SSL certificates from a builder stage that has them
|
2024-03-27 12:04:54 -05:00
|
|
|
COPY --from=rust-build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
2025-05-22 17:39:06 +02:00
|
|
|
|
2026-02-12 15:06:57 +01:00
|
|
|
# Copy static ffmpeg/ffprobe binaries
|
|
|
|
|
COPY --from=ffmpeg-static /ffmpeg /usr/local/bin/
|
|
|
|
|
COPY --from=ffmpeg-static /ffprobe /usr/local/bin/
|
|
|
|
|
|
2025-05-22 17:39:06 +02:00
|
|
|
# App
|
|
|
|
|
WORKDIR /app
|
2025-06-20 13:44:54 +02:00
|
|
|
COPY --from=rust-build /src/target/${RUST_TARGET}/release/tuliprox ./tuliprox
|
2025-08-07 19:46:49 +02:00
|
|
|
COPY --from=trunk-build /src/frontend/dist ./web
|
2025-06-20 13:44:54 +02:00
|
|
|
COPY --from=resource-build /src/resources ./resources
|
2025-05-22 17:39:06 +02:00
|
|
|
|
2025-05-10 17:59:50 +02:00
|
|
|
ENTRYPOINT ["/app/tuliprox"]
|
2025-04-14 15:51:16 +02:00
|
|
|
CMD ["-s", "-p", "/app/config"]
|
2024-10-21 19:41:17 +02:00
|
|
|
|
2025-06-13 02:01:38 +02:00
|
|
|
# -----------------------------------------------------------------
|
|
|
|
|
# Final Image #3: Production image based on Alpine
|
|
|
|
|
# -----------------------------------------------------------------
|
2025-04-18 16:12:38 +02:00
|
|
|
FROM alpine:latest AS alpine-final
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
ARG RUST_TARGET=x86_64-unknown-linux-musl
|
2025-05-22 18:49:47 +02:00
|
|
|
ARG TZ=UTC
|
|
|
|
|
ENV TZ=${TZ}
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2026-02-12 15:06:57 +01:00
|
|
|
# Install dependencies including ffmpeg
|
|
|
|
|
RUN apk add --no-cache bash curl ca-certificates tini ffmpeg
|
2025-04-22 19:43:23 +02:00
|
|
|
|
2025-10-26 21:46:04 +01:00
|
|
|
# Copy timezone data and localtime from tz-prep
|
|
|
|
|
COPY --from=tz-prep /output/usr/share/zoneinfo /usr/share/zoneinfo
|
|
|
|
|
COPY --from=tz-prep /output/etc/localtime /etc/localtime
|
|
|
|
|
|
|
|
|
|
# Copy SSL certificates `ca-certificates` from Alpine-based Stage (tz-prep ist Alpine)
|
|
|
|
|
COPY --from=tz-prep /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
2025-05-22 17:39:06 +02:00
|
|
|
|
|
|
|
|
# Default timezone fallback
|
|
|
|
|
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime
|
|
|
|
|
|
2024-10-21 19:41:17 +02:00
|
|
|
WORKDIR /app
|
2025-06-20 13:44:54 +02:00
|
|
|
COPY --from=rust-build /src/target/${RUST_TARGET}/release/tuliprox ./tuliprox
|
2025-08-07 19:46:49 +02:00
|
|
|
COPY --from=trunk-build /src/frontend/dist ./web
|
2025-06-20 13:44:54 +02:00
|
|
|
COPY --from=resource-build /src/resources ./resources
|
2025-06-13 02:01:38 +02:00
|
|
|
|
2025-05-10 17:59:50 +02:00
|
|
|
ENTRYPOINT ["/sbin/tini", "--", "/app/tuliprox"]
|
2026-03-13 16:12:43 +01:00
|
|
|
CMD ["-s", "-p", "/app/config"]
|