feat: add Unraid single-container deployment with docker-compose and comprehensive setup guide

This commit is contained in:
Michael committed 2026-04-16 10:13:08 +02:00
1 parent 9bb61cc8a7
commit 73585213ba
6 files changed
+753 -1

No files matched your search

+4 -1
View File
@@ -2,7 +2,10 @@
"permissions": {
"allow": [
"Bash(rtk git:*)",
"Bash(rtk npm:*)"
"Bash(rtk npm:*)",
"Bash(git remote:*)",
"Bash(git branch:*)",
"Bash(git push:*)"
]
}
}
Submodule .claude/worktrees/upbeat-easley added at 9bb61cc8a7.
+55
View File
@@ -0,0 +1,55 @@
# ==========================================
# Podcastic - Unraid Configuration
# ==========================================
# All services in single container on port 3579
# Application Environment
NODE_ENV=production
# ==========================================
# DATABASE & CACHE (Internal - Don't change)
# ==========================================
MONGODB_URI=mongodb://127.0.0.1:27017/podcastic
REDIS_URL=redis://127.0.0.1:6379
# ==========================================
# SECURITY - CHANGE THESE!
# ==========================================
# JWT Secret - Use strong random string
# Generate: openssl rand -base64 32
JWT_SECRET=change-this-to-random-secret-key-in-production
JWT_EXPIRES_IN=7d
JWT_REFRESH_EXPIRES_IN=30d
# ==========================================
# OPTIONAL: PodcastIndex API (Podcast Search)
# ==========================================
# Leave empty to disable (manual RSS subscription still works)
# Get free keys: https://podcastindex-api.com/
PODCAST_INDEX_API_KEY=
PODCAST_INDEX_API_SECRET=
# ==========================================
# PORTS (Single container)
# ==========================================
# Frontend: http://your-unraid-ip:3579
# API: http://your-unraid-ip:3579/api
# Health: http://your-unraid-ip:3579/health
PORT=5000 # Internal backend port (don't change)
# ==========================================
# Frontend Configuration
# ==========================================
VITE_API_URL=http://your-unraid-ip:3579/api
# Or use relative path:
# VITE_API_URL=/api
# ==========================================
# NOTES FOR UNRAID
# ==========================================
# 1. Change JWT_SECRET to a random string
# 2. If accessing from WAN, update VITE_API_URL to your domain
# 3. Optionally add PodcastIndex API keys for search feature
# 4. All data stored in /mnt/user/appdata/podcastic/
# 5. Logs in /mnt/user/appdata/podcastic/logs/
+154
View File
@@ -0,0 +1,154 @@
# Multi-stage build for Podcastic All-in-One Container
# Combines: Backend (Node.js), Frontend (React), Web Server (Nginx), Database (MongoDB), Cache (Redis)
# ==================== STAGE 1: Build Backend ====================
FROM node:20-alpine AS backend-builder
WORKDIR /build/backend
COPY backend/package*.json ./
RUN npm ci
COPY backend/tsconfig.json ./
COPY backend/src ./src
RUN npm run build
# ==================== STAGE 2: Build Frontend ====================
FROM node:20-alpine AS frontend-builder
WORKDIR /build/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/tsconfig*.json ./
COPY frontend/vite.config.ts ./
COPY frontend/postcss.config.js ./
COPY frontend/tailwind.config.js ./
COPY frontend/index.html ./
COPY frontend/src ./src
RUN npm run build
# ==================== STAGE 3: Final Image ====================
FROM node:20-alpine
# Install supervisor to manage multiple processes, mongodb, redis, nginx
RUN apk add --no-cache supervisor nginx mongodb redis bash curl
WORKDIR /app
# ==================== Setup Backend ====================
COPY --from=backend-builder /build/backend/dist ./backend/dist
COPY --from=backend-builder /build/backend/package*.json ./backend/
RUN cd backend && npm ci --only=production
# ==================== Setup Frontend ====================
RUN mkdir -p /usr/share/nginx/html
COPY --from=frontend-builder /build/frontend/dist/* /usr/share/nginx/html/
# ==================== Setup Nginx ====================
RUN mkdir -p /etc/nginx/conf.d
COPY <<'EOF' /etc/nginx/conf.d/default.conf
server {
listen 3579;
server_name _;
client_max_body_size 100M;
# Frontend - Static files
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
expires 1d;
add_header Cache-Control "public, immutable";
}
# Static assets with long cache
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
root /usr/share/nginx/html;
expires 1y;
add_header Cache-Control "public, immutable";
}
# API - Proxy to backend
location /api {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Health check endpoint
location /health {
proxy_pass http://127.0.0.1:5000;
}
}
EOF
# ==================== Setup Supervisor ====================
RUN mkdir -p /var/log/supervisor
COPY <<'EOF' /etc/supervisor/conf.d/supervisord.conf
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:mongodb]
command=/usr/bin/mongod --dbpath /data/db --bind_ip 127.0.0.1
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/mongodb.err.log
stdout_logfile=/var/log/supervisor/mongodb.out.log
[program:redis]
command=/usr/bin/redis-server --bind 127.0.0.1
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/redis.err.log
stdout_logfile=/var/log/supervisor/redis.out.log
[program:backend]
command=/bin/bash -c "cd /app/backend && node dist/index.js"
environment=NODE_ENV=production,MONGODB_URI=mongodb://127.0.0.1:27017/podcastic,REDIS_URL=redis://127.0.0.1:6379
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/backend.err.log
stdout_logfile=/var/log/supervisor/backend.out.log
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/nginx.err.log
stdout_logfile=/var/log/supervisor/nginx.out.log
EOF
# ==================== Create Data Directories ====================
RUN mkdir -p /data/db /data/redis
# ==================== Environment ====================
ENV NODE_ENV=production
ENV MONGODB_URI=mongodb://127.0.0.1:27017/podcastic
ENV REDIS_URL=redis://127.0.0.1:6379
ENV PORT=5000
# ==================== Health Check ====================
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://127.0.0.1:3579/health || exit 1
# ==================== Expose Port ====================
EXPOSE 3579
# ==================== Entrypoint ====================
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+458
View File
@@ -0,0 +1,458 @@
# 🐳 Podcastic - Unraid Installation Guide
Complete guide to install Podcastic on Unraid as a **single all-in-one container**.
## 📋 What's Included
This single Docker container includes:
- ✅ **Backend**: Node.js + Express.js API
- ✅ **Frontend**: React web interface
- ✅ **Database**: MongoDB (embedded)
- ✅ **Cache**: Redis (embedded)
- ✅ **Web Server**: Nginx reverse proxy
- ✅ **Process Manager**: Supervisor (manages all 5 services)
All in **ONE container** on port **3579**
## Prerequisites
- Unraid server with Docker support
- ~2GB RAM available
- ~20GB storage for database/media
- Internet connection
## Installation Steps
### Step 1: Clone Repository
```bash
# Via terminal on Unraid
cd /mnt/user/appdata # or your preferred path
git clone https://github.com/R0m1k3/podcastic.git
cd podcastic
```
Or download as ZIP from GitHub and extract.
### Step 2: Configure Environment
```bash
# Copy template
cp .env.example .env
# Edit with your settings
nano .env
```
**Key settings**:
```env
NODE_ENV=production
# JWT Secret - CHANGE THIS!
JWT_SECRET=your-super-secret-key-change-me-in-production
# Optional: PodcastIndex API for podcast search
PODCAST_INDEX_API_KEY=
PODCAST_INDEX_API_SECRET=
```
### Step 3: Build Docker Image
Option A: Build locally (takes ~5-10 minutes)
```bash
docker-compose -f docker-compose.unraid.yml build --no-cache
```
Option B: Use pre-built image (faster)
```bash
# Will be available after first push to Docker Hub
# docker pull r0m1k3/podcastic:latest
```
### Step 4: Start Container
```bash
# Start
docker-compose -f docker-compose.unraid.yml up -d
# View logs
docker-compose -f docker-compose.unraid.yml logs -f podcastic
# Check status
docker ps | grep podcastic
```
### Step 5: Access Application
Open browser:
```
http://your-unraid-ip:3579
```
**First Time Setup**:
1. Click "Create Account"
2. Register with email/password
3. Log in
4. Go to "Discover" to search podcasts
5. Subscribe and listen!
---
## 📊 Container Architecture
```
Single Container (podcastic)
├── Nginx (port 3579)
│ ├── Serves static frontend
│ └── Proxies /api to backend
├── Node.js Backend (internal port 5000)
│ ├── API routes
│ ├── Authentication
│ └── Database management
├── MongoDB (internal port 27017)
│ └── Podcast data storage
└── Redis (internal port 6379)
└── Cache & sessions
```
All services communicate **internally** - only port 3579 exposed.
---
## 🛠️ Unraid Integration
### Add to Unraid via WebUI
1. **Settings → Docker** → Enable Docker
2. **Docker** tab
3. Add custom template:
```xml
<?xml version="1.0" encoding="utf-8"?>
<Container version="2">
<Name>podcastic</Name>
<Repository>r0m1k3/podcastic:latest</Repository>
<Registry>https://hub.docker.com/</Registry>
<Network>bridge</Network>
<MyIP/>
<Shell>sh</Shell>
<Privileged>false</Privileged>
<Support/>
<Project/>
<Overview/>
<Category/>
<WebUI>http://[IP]:[PORT:3579]</WebUI>
<TemplateURL/>
<Icon/>
<ExtraParams/>
<PostArgs/>
<StaticNetwork>false</StaticNetwork>
<DonateText/>
<DonateLink/>
<Description>Podcastic - Multi-user podcast streaming application</Description>
<Networking>
<Mode>bridge</Mode>
<Publish>
<Port>
<HostPort>3579</HostPort>
<ContainerPort>3579</ContainerPort>
<Protocol>tcp</Protocol>
</Port>
</Publish>
</Networking>
<Data>
<Volume>
<HostDir>/mnt/user/appdata/podcastic/db</HostDir>
<ContainerDir>/data/db</ContainerDir>
<Mode>rw</Mode>
</Volume>
<Volume>
<HostDir>/mnt/user/appdata/podcastic/redis</HostDir>
<ContainerDir>/data/redis</ContainerDir>
<Mode>rw</Mode>
</Volume>
<Volume>
<HostDir>/mnt/user/appdata/podcastic/logs</HostDir>
<ContainerDir>/var/log/supervisor</ContainerDir>
<Mode>rw</Mode>
</Volume>
</Data>
<Environment>
<Variable>
<Name>JWT_SECRET</Name>
<Value>change-me-in-production</Value>
</Variable>
<Variable>
<Name>PODCAST_INDEX_API_KEY</Name>
<Value/>
</Variable>
<Variable>
<Name>PODCAST_INDEX_API_SECRET</Name>
<Value/>
</Variable>
</Environment>
</Container>
```
Or use Docker Compose tab with `docker-compose.unraid.yml`
---
## 📂 Data Persistence
Data is saved to Unraid shares:
```
/mnt/user/appdata/podcastic/
├── db/ # MongoDB data (podcasts, users, episodes)
├── redis/ # Redis cache data
└── logs/ # Application logs
```
### Backup
```bash
# Backup database
docker exec podcastic mongodump --out /backup/mongodb
# Copy to safe location
cp -r /mnt/user/appdata/podcastic /mnt/backup/podcastic-backup
```
### Restore
```bash
docker exec podcastic mongorestore /backup/mongodb
```
---
## 🔧 Management Commands
### View Logs
```bash
# All logs
docker logs -f podcastic
# Specific service
docker exec podcastic tail -f /var/log/supervisor/backend.out.log
docker exec podcastic tail -f /var/log/supervisor/mongodb.out.log
docker exec podcastic tail -f /var/log/supervisor/redis.out.log
docker exec podcastic tail -f /var/log/supervisor/nginx.out.log
```
### Restart Container
```bash
docker-compose -f docker-compose.unraid.yml restart podcastic
```
### Stop Container
```bash
docker-compose -f docker-compose.unraid.yml down
# Keep volumes (data persists)
# Data in /mnt/user/appdata/podcastic/ is preserved
```
### Update to Latest
```bash
# Pull latest code
cd /path/to/podcastic
git pull
# Rebuild and restart
docker-compose -f docker-compose.unraid.yml build --no-cache
docker-compose -f docker-compose.unraid.yml up -d
```
---
## 🐛 Troubleshooting
### Container won't start
```bash
# Check logs
docker logs podcastic
# Common issues:
# - Port 3579 in use: Change in docker-compose.unraid.yml
# - Insufficient RAM: Free up memory
# - Permission issues: Check volume permissions
```
### MongoDB not starting
```bash
# Check mongo logs
docker exec podcastic tail -f /var/log/supervisor/mongodb.out.log
# Repair database
docker exec podcastic mongod --repair --dbpath /data/db
```
### Can't access on port 3579
```bash
# Check if container is running
docker ps | grep podcastic
# Check if port is open
netstat -tulpn | grep 3579
# Test connection
curl http://localhost:3579/health
```
### Out of disk space
MongoDB can grow large. Check:
```bash
docker exec podcastic du -sh /data/db
# Clean old data (backup first!)
```
---
## 📈 Performance Optimization
### For Limited Resources
Edit `docker-compose.unraid.yml`:
```yaml
# Limit memory usage
mem_limit: 1g
cpus: '0.5'
```
### For High Performance
Increase limits:
```yaml
mem_limit: 4g
cpus: '2'
```
### Disable Unneeded Features
If only streaming (no search):
```env
PODCAST_INDEX_API_KEY= # Leave empty
```
---
## 🔒 Security Notes
### Change Default Secrets
```env
# MUST change in production!
JWT_SECRET=your-unique-secret-key-here
# Use strong password for first admin account
```
### Firewall Rules
Allow only trusted IPs:
```bash
# On Unraid, set firewall rules in UI
# Or use nginx config to restrict access
```
### SSL/HTTPS Setup
If exposing to internet, use reverse proxy with SSL:
- Nginx Proxy Manager (separate container)
- Traefik (with Let's Encrypt)
- Unraid built-in reverse proxy
---
## 📊 Monitoring
### Check Container Health
```bash
# Real-time stats
docker stats podcastic
# Service status
docker exec podcastic supervisorctl status
# Expected output:
# mongodb RUNNING pid 123, uptime 0:00:45
# redis RUNNING pid 124, uptime 0:00:45
# backend RUNNING pid 125, uptime 0:00:45
# nginx RUNNING pid 126, uptime 0:00:45
```
### Resource Usage
```bash
# Disk usage
du -sh /mnt/user/appdata/podcastic/
# Memory usage
docker exec podcastic free -h
# CPU usage
docker stats --no-stream podcastic
```
---
## 🆘 Support
If issues occur:
1. **Check logs**:
```bash
docker logs podcastic
```
2. **Check service status**:
```bash
docker exec podcastic supervisorctl status
```
3. **Rebuild container**:
```bash
docker-compose -f docker-compose.unraid.yml build --no-cache
docker-compose -f docker-compose.unraid.yml up -d
```
4. **Factory reset** (loses all data!):
```bash
docker-compose -f docker-compose.unraid.yml down -v
rm -rf /mnt/user/appdata/podcastic
# Start fresh
```
---
## 🎯 Next Steps
1. **First Run**: Create account, set JWT_SECRET properly
2. **Configure PodcastIndex**: Optional, enables podcast search
3. **Add Podcasts**: Via Discover or RSS URLs
4. **Enjoy**: Start listening!
---
## 📚 Additional Resources
- **Main README**: See README.md
- **Getting Started**: See GETTING_STARTED.md
- **PodcastIndex Setup**: See PODCAST_INDEX_SETUP.md
- **GitHub**: https://github.com/R0m1k3/podcastic
---
**Last Updated**: 2026-04-16
**Tested on**: Unraid 6.12+
+81
View File
@@ -0,0 +1,81 @@
version: '3.8'
services:
podcastic:
build:
context: .
dockerfile: Dockerfile.unraid
container_name: podcastic
restart: unless-stopped
ports:
- "3579:3579" # Web Interface (Frontend + API)
environment:
# Backend Config
NODE_ENV: production
PORT: 5000
# Database
MONGODB_URI: mongodb://127.0.0.1:27017/podcastic
REDIS_URL: redis://127.0.0.1:6379
# JWT Config
JWT_SECRET: ${JWT_SECRET:-change_me_in_production}
JWT_EXPIRES_IN: 7d
JWT_REFRESH_EXPIRES_IN: 30d
# PodcastIndex API (Optional - for podcast search)
PODCAST_INDEX_API_KEY: ${PODCAST_INDEX_API_KEY:-}
PODCAST_INDEX_API_SECRET: ${PODCAST_INDEX_API_SECRET:-}
volumes:
# MongoDB data persistence
- podcastic_db:/data/db
# Redis data persistence (optional)
- podcastic_redis:/data/redis
# Application logs
- podcastic_logs:/var/log/supervisor
networks:
- podcastic-network
# Resource limits (adjust based on your server)
# Uncomment to set limits:
# mem_limit: 2g
# cpus: '1'
volumes:
podcastic_db:
driver: local
podcastic_redis:
driver: local
podcastic_logs:
driver: local
networks:
podcastic-network:
driver: bridge
# ============================================
# USAGE:
# ============================================
#
# 1. Copy .env.example to .env and configure:
# cp .env.example .env
#
# 2. Build and start:
# docker-compose -f docker-compose.unraid.yml up -d
#
# 3. Access:
# http://your-server-ip:3579
#
# 4. View logs:
# docker-compose -f docker-compose.unraid.yml logs -f podcastic
#
# 5. Stop:
# docker-compose -f docker-compose.unraid.yml down
#
# 6. Backup data:
# docker run --rm -v podcastic_db:/data/db -v $(pwd):/backup \
# alpine tar czf /backup/podcastic-db.tar.gz -C /data db
#
# ============================================