Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 62 additions & 54 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,79 +1,87 @@
# Use Node.js LTS (Long Term Support) as base image
FROM node:20-bullseye

# Create app user and group with configurable UID/GID
# Use Node 22 LTS as base image
FROM node:22-alpine3.23 AS base

###############
# BUILD STAGE #
###############
FROM base AS builder

# Build deps
RUN apk add --no-cache \
python3-dev \
py3-pip \
py3-virtualenv \
gcc \
g++ \
make \
musl-dev \
shadow

# Install ffsubsync and autosubsync into custom venvs since pipx doesn't work properly over build stages
RUN python3 -m venv /opt/venv/ffsubsync && \
python3 -m venv /opt/venv/autosubsync && \
/opt/venv/ffsubsync/bin/pip install --no-cache-dir --no-compile ffsubsync "setuptools<70" && \
/opt/venv/autosubsync/bin/pip install --no-cache-dir --no-compile autosubsync "setuptools<70"

# Set group and user id to 1000 in case node ever decides to change it
ENV PUID=1000
ENV PGID=1000

RUN mkdir -p /app
RUN chown node:node /app

# Modify existing node user instead of creating new one
RUN groupmod -g ${PGID} node && \
usermod -u ${PUID} -g ${PGID} node && \
chown -R node:node /home/node
RUN apt-get clean

# Install system dependencies including ffmpeg, Python, cron, and build tools
RUN apt-get update && apt-get install -y \
ffmpeg \
python3 \
python3-pip \
python3-venv \
cron \
build-essential \
&& rm -rf /var/lib/apt/lists/*

USER node
# Set working directory
WORKDIR /app

# Copy package.json and package-lock.json (if available)
# Node deps
COPY --chown=node:node package*.json ./

# Install Node.js dependencies while skipping husky installation
ENV HUSKY=0
RUN npm install --ignore-scripts

# Rebuild native modules for the container's platform
# Native rebuild
RUN npm rebuild better-sqlite3

# Copy the rest of your application
# Build app and cleanup
COPY --chown=node:node . .
RUN mkdir -p /home/node/.local/bin/
RUN cp bin/* /home/node/.local/bin/

# Build TypeScript
RUN npm run build
RUN npm run build && \
npm prune --omit=dev --production && \
npm cache clean --force

# Create data directory for SQLite database
RUN mkdir -p /app/data && chown node:node /app/data
####################
# PRODUCTION STAGE #
####################
FROM base AS final

# Create startup script
# Set default cron schedule (if not provided by environment variable)
ENV CRON_SCHEDULE="0 0 * * *"
# Runtime deps
RUN apk add --no-cache \
ffmpeg \
python3 \
shadow

# Install pipx
RUN python3 -m pip install --user pipx \
&& python3 -m pipx ensurepath
# Same user as build stage
ENV PUID=1000
ENV PGID=1000
RUN groupmod -g ${PGID} node && \
usermod -u ${PUID} -g ${PGID} node && \
chown -R node:node /home/node

# Add pipx to PATH
ENV PATH="/home/node/.local/bin:$PATH"
USER node
WORKDIR /app

# Install ffsubsync and autosubsync using pipx
# Clean caches after installation to reduce memory footprint
RUN pipx install ffsubsync \
&& pipx install autosubsync \
&& python3 -m pip cache purge \
&& find /home/node/.local/share/pipx -type f -name "*.pyc" -delete 2>/dev/null || true \
&& find /home/node/.local/share/pipx -type d -name "__pycache__" -delete 2>/dev/null || true
# Copy app, python venv installs and bin
COPY --from=builder --chown=node:node /app /app
COPY --from=builder --chown=node:node /opt/venv /opt/venv
COPY --chown=node:node bin/* /home/node/.local/bin/

# Expose web UI port
EXPOSE 3000
# Create volume for persistent storage of database
RUN mkdir -p /app/data
VOLUME "/app/data"

# Default memory limit for Node.js
# Runtime Env variables
ENV CRON_SCHEDULE="0 0 * * *"
ENV NODE_OPTIONS="--max-old-space-size=512"
ENV PATH="/opt/venv/ffsubsync/bin:/opt/venv/autosubsync/bin:/home/node/.local/bin/:$PATH"

EXPOSE 3000

# Use server as entrypoint (which includes cron scheduling)
# Memory optimization flags: uses NODE_OPTIONS to prevent OOM
CMD ["node", "--optimize-for-size", "dist/index-server.js"]
CMD ["node", "--optimize-for-size", "dist/index-server.js"]
9 changes: 6 additions & 3 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
subsyncarr-plus:
image: tomtomw123/subsyncarr-plus:latest
container_name: subsyncarr-plus
user: "1000:10"
user: "1000:1000"
ports:
- '3000:3000' # Web UI
volumes:
Expand All @@ -14,7 +14,7 @@ services:
- /path/to/movies:/movies
- /path/to/tv:/tv
- /path/to/anime:/anime
- ./data:/app/data # Persist database across restarts
- db-data:/app/data # Persist database across restarts
restart: unless-stopped
deploy:
resources:
Expand All @@ -25,7 +25,7 @@ services:
environment:
- TZ=Etc/UTC # Replace with your own timezone
- PUID=1000
- PGID=10
- PGID=1000
- CRON_SCHEDULE=0 0 * * * # Runs every day at midnight by default
- SCAN_PATHS=/movies,/tv # Remember to mount these as volumes. Must begin with /. Default valus is `/scan_dir`
- EXCLUDE_PATHS=/movies/temp,/tv/downloads # Exclude certain sub-directories from the scan
Expand All @@ -41,3 +41,6 @@ services:
# - WEB_PORT=3000 # Port for web UI (default: 3000)
# - WEB_HOST=127.0.0.1 # Host to bind to (default: 127.0.0.1, use 0.0.0.0 for all interfaces)
# - DB_PATH=/app/data/subsyncarr-plus.db # SQLite database location (default: /app/data/subsyncarr-plus.db)

volumes:
db-data: