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
78 changes: 78 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Docker ignore file for Subarr
# Node modules
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Build outputs
client/build/
.env.local
.env.development.local
.env.test.local
.env.production.local

# Database files (should be handled by volumes)
server/*.db
server/*.db-journal
*.db
*.db-journal

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# IDE files
.vscode/
.idea/
*.swp
*.swo

# Git
.git/
.gitignore

# Logs
logs/
*.log

# Runtime data
pids/
*.pid
*.seed
*.pid.lock

# Coverage directory used by tools like istanbul
coverage/

# Dependency directories
node_modules/
jspm_packages/

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# Docker files (to avoid recursion)
Dockerfile
docker-compose.yml
.dockerignore

# Documentation
README.md
71 changes: 71 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Multi-stage Dockerfile for Subarr
FROM node:alpine3.22 AS base

# Install system dependencies required for better-sqlite3
RUN apk add --no-cache \
python3 \
make \
g++ \
sqlite-dev \
linux-headers

WORKDIR /app

# Copy package files
COPY package*.json ./
COPY client/package*.json ./client/
COPY server/package*.json ./server/

# Install dependencies (including dev dependencies for building native modules)
RUN npm ci

# Rebuild better-sqlite3 for the current architecture
RUN npm rebuild better-sqlite3

FROM base AS builder

# Copy source code
COPY client/ ./client/
COPY server/ ./server/

# Build the client
RUN npm --workspace client run build

FROM node:alpine3.22 AS production

# Install only runtime dependencies
RUN apk add --no-cache sqlite

# Create non-root user for security
RUN addgroup -g 1001 -S subarr && \
adduser -S subarr -u 1001

WORKDIR /app

# Copy built application from builder stage
COPY --from=builder --chown=subarr:subarr /app/node_modules ./node_modules
COPY --from=builder --chown=subarr:subarr /app/client/build ./client/build
COPY --from=builder --chown=subarr:subarr /app/server ./server
COPY --from=builder --chown=subarr:subarr /app/package.json ./

# Rebuild native module for runtime architecture (avoids Exec format error)
RUN apk add --no-cache python3 make g++ sqlite-dev linux-headers \
&& npm rebuild better-sqlite3 --build-from-source \
&& apk del python3 make g++ sqlite-dev linux-headers \
&& rm -rf /root/.npm /root/.cache

# Create data directory for database persistence
RUN mkdir -p /app/data && chown subarr:subarr /app/data

# Switch to non-root user
USER subarr

# Expose port
EXPOSE 3001

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/api/playlists || exit 1

# Start the server
CMD ["node", "server/index.js"]
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,37 @@ Subarr is NOT intended to do the following:

### Installation

#### Docker (Recommended)

```bash
git clone https://github.com/derekantrican/subarr.git
cd subarr
docker-compose up -d
```

The app will be available at `http://localhost:3001`

#### Helpful Docker Scripts

From the project root you can use the following npm scripts (they just wrap common docker-compose commands):

```
npm run docker:run # Start (build if needed) in background
npm run docker:logs # Follow logs
npm run docker:stop # Stop and remove container
npm run update:docker # git pull then rebuild using latest base images and recreate
npm run docker:restart # Restart container (down + up -d)
```

Typical update workflow if you deployed via git clone:

```
cd subarr
npm run update:docker
```

#### Manual Installation

Make sure you have Node >= 18 installed, then run the following:

```
Expand Down
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Please run `git pull` before running this compose
services:
subarr:
build: .
container_name: subarr
ports:
- "3001:3001"
volumes:
- subarr_data:/app/data
environment:
- NODE_ENV=production
- PORT=3001
- DB_PATH=/app/data/subarr.db
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

volumes:
subarr_data:
driver: local
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
"scripts": {
"start-server": "npm --workspace client run build && NODE_ENV=production node server/index.js",
"start-server-win": "npm --workspace client run build && SET NODE_ENV=production && node server/index.js",
"update": "git pull && npm install && npm run start-server"
"docker:run": "docker-compose up -d",
"update": "git pull && npm install",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was npm run start-server removed from the update script?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I attempted to make npm run update script universal for docker, and a base install.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So is the recommendation that "manual installs" run npm run update:manual and docker installs run npm run update:docker? I don't see how npm run update would work for both installs (unless I don't understand something about how scripts work)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the ideal flow would go like this
Manual user: npm run update:manual
Docker user: npm run update:docker

This would've allowed each user update and start the application the way they would like. Typically the docker image for an app would exist in a place like dockerhub and that would allowed for docker users to not need to use node scripts. but since this is the first iteration of docker, I thought it would be okay for now.

ps. Sorry I should have included this in my pull from the beginning.

Copy link
Copy Markdown
Owner

@derekantrican derekantrican Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understandable. I'm quite new to docker, so I'm not very familiar. But I know it's a big request for people interested in this app.

Let's keep update:docker as you have it (or change it to docker:update since the other docker scripts have that naming convention), but let's remove update:manual and just go back to the regular update script the way it was.

"update:manual": "npm run update && npm run start-server",
"update:docker": "git pull && docker-compose build --pull && docker-compose up -d",
"docker:build": "docker build -t subarr .",
"docker:stop": "docker-compose down",
"docker:logs": "docker-compose logs -f"
}
}