# Multi-stage build for security and optimization FROM node:20-slim AS backend-builder # Install build dependencies for native modules (sqlite3, bcrypt) RUN apt-get update && apt-get install -y \ python3 \ make \ g++ \ gcc \ && rm -rf /var/lib/apt/lists/* WORKDIR /app # Copy backend dependencies FIRST (better layer caching) COPY backend/package*.json ./backend/ RUN cd backend && npm ci --only=production # Copy ONLY necessary backend source files COPY backend/server.js backend/healthcheck.js ./backend/ COPY backend/database ./backend/database COPY backend/middleware ./backend/middleware COPY backend/routes ./backend/routes COPY backend/utils ./backend/utils COPY backend/jobs ./backend/jobs # Build frontend FROM node:20-slim AS frontend-builder WORKDIR /app # Copy frontend dependencies FIRST (better layer caching) COPY frontend/package*.json ./frontend/ RUN cd frontend && npm ci # Copy ONLY necessary frontend source files COPY frontend/index.html frontend/vite.config.js ./frontend/ COPY frontend/public ./frontend/public COPY frontend/src ./frontend/src # Build frontend application RUN cd frontend && npm run build # Final production image FROM node:20-slim # Combine apt-get operations and use --no-install-recommends to reduce size and time RUN apt-get update && apt-get install -y --no-install-recommends \ ffmpeg \ python3 \ python3-pip \ openvpn \ wireguard-tools \ openresolv \ curl \ ca-certificates \ iptables \ iproute2 \ imagemagick \ procps \ && pip3 install --no-cache-dir --break-system-packages streamlink yt-dlp \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Create VPN script as a separate file instead of echo commands COPY <<'EOF' /etc/openvpn/update-resolv-conf #!/bin/bash # Update DNS when VPN connects/disconnects case $script_type in up) echo "[VPN] Setting up DNS..." echo "# VPN DNS - DO NOT MODIFY" > /etc/resolv.conf for opt in ${!foreign_option_*}; do if echo ${!opt} | grep -q "DNS"; then DNS_IP=$(echo ${!opt} | awk '{print $3}') echo "nameserver $DNS_IP" >> /etc/resolv.conf echo "[VPN] Added DNS: $DNS_IP" fi done if ! grep -q "nameserver" /etc/resolv.conf; then echo "nameserver 1.1.1.1" >> /etc/resolv.conf echo "[VPN] Using fallback DNS" fi ;; down) echo "[VPN] Restoring default DNS..." echo "nameserver 8.8.8.8" > /etc/resolv.conf echo "nameserver 1.1.1.1" >> /etc/resolv.conf ;; esac EOF RUN chmod +x /etc/openvpn/update-resolv-conf # Create app user for security (non-root) RUN groupadd -g 1001 appgroup && \ useradd -u 1001 -g appgroup -m -s /bin/bash appuser WORKDIR /app # Create necessary directories with proper permissions RUN mkdir -p /app/data/playlists \ /app/data/recordings \ /app/data/logos \ /app/data/uploads \ /app/data/m3u-files \ /app/uploads/logos \ /app/logs \ /app/pwa-assets \ /app/android-assets && \ chown -R appuser:appgroup /app # Copy backend from builder COPY --from=backend-builder --chown=appuser:appgroup /app/backend ./backend # Copy built frontend from builder COPY --from=frontend-builder --chown=appuser:appgroup /app/frontend/dist ./frontend/dist # Copy desktop app update files COPY --chown=appuser:appgroup desktop-app/dist ./updates # Copy PWA assets and platform-specific resources COPY --chown=appuser:appgroup frontend/public/manifest.json ./pwa-assets/manifest.json COPY --chown=appuser:appgroup frontend/public/service-worker.js ./pwa-assets/service-worker.js COPY --chown=appuser:appgroup frontend/public/icons ./pwa-assets/icons # Create VPN directories with proper permissions RUN mkdir -p /etc/wireguard /etc/openvpn/configs && \ chmod 755 /etc/wireguard /etc/openvpn/configs # Create startup script using heredoc (much faster than echo) COPY <<'EOF' /app/start.sh #!/bin/sh echo "Initializing application..." # Fix data directory permissions for root access chown -R root:root /app/data 2>/dev/null || true # Ensure database files are writable by root chmod 644 /app/data/streamflow.db* 2>/dev/null || true chown root:root /app/data/streamflow.db* 2>/dev/null || true # Ensure VPN directories are accessible chmod 755 /etc/wireguard /etc/openvpn/configs 2>/dev/null || true # Create all data subdirectories (including log-archives for CWE-53) mkdir -p /app/data/backups /app/data/logos /app/data/logo-cache /app/data/m3u-files /app/data/playlists /app/data/recordings /app/data/uploads /app/data/log-archives # Ensure restrictive permissions on log directories (CWE-53) chmod 700 /app/logs 2>/dev/null || true chmod 700 /app/data/log-archives 2>/dev/null || true # Set ownership chown -R appuser:appgroup /app/data 2>/dev/null || true # Start update server in background python3 -m http.server 9000 --directory /app/updates > /tmp/update-server.log 2>&1 & UPDATE_SERVER_PID=$! sleep 1 if kill -0 $UPDATE_SERVER_PID 2>/dev/null; then echo "Update server started successfully (PID: $UPDATE_SERVER_PID) on port 9000" else echo "Warning: Update server failed to start" fi echo "Starting Node.js application..." # Run as root to allow VPN operations (wg-quick, openvpn require root) cd /app && exec node backend/server.js EOF RUN chmod +x /app/start.sh USER root # Expose ports EXPOSE 12345 9000 # Health check - disabled due to segfault issues # HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ # CMD node backend/healthcheck.js || exit 1 # Start application CMD ["/app/start.sh"]