streamflow/Dockerfile

174 lines
5.4 KiB
Text
Raw Normal View History

# 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"]