diff --git a/Dockerfile b/Dockerfile index 6bb4081..88f208a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,16 +24,18 @@ RUN pnpm install COPY . . # Rebuild better-sqlite3 to ensure native bindings are compiled correctly -RUN pnpm rebuild better-sqlite3 +RUN pnpm rebuild better-sqlite3 || npm rebuild better-sqlite3 -# Ensure database file exists and has proper permissions -RUN touch /app/media.db && chmod 666 /app/media.db +# Verify native bindings are compiled +RUN find /app/node_modules -name "better_sqlite3.node" -type f + +# Database file will be created at runtime via docker-compose # Create directories for media storage RUN mkdir -p /app/data /app/media # Build the application -RUN pnpm build +RUN pnpm buildprod # Production image, copy all the files and run next FROM base AS runner @@ -42,11 +44,7 @@ WORKDIR /app ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 -# Install FFmpeg and FFprobe for thumbnail generation -RUN apt-get update && apt-get install -y \ - ffmpeg \ - sqlite3 \ - && rm -rf /var/lib/apt/lists/* +# No additional packages needed for production RUN groupadd --system --gid 1001 nodejs RUN useradd --system --uid 1001 --gid nodejs nextjs @@ -54,11 +52,18 @@ RUN useradd --system --uid 1001 --gid nodejs nextjs # Create media directories RUN mkdir -p /app/data /app/media +# Ensure directories have correct permissions +RUN chown -R nextjs:nodejs /app/data /app/media + # Copy built application COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static -COPY --from=builder /app/media.db ./media.db +# Copy node_modules to ensure native bindings are available +COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules + +# Rebuild native bindings for the production environment +RUN npm rebuild better-sqlite3 # Set up volume for persistent data VOLUME ["/app/data", "/app/media"] diff --git a/docker/data/media.db b/docker/data/media.db new file mode 100644 index 0000000..647789c Binary files /dev/null and b/docker/data/media.db differ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f54f403..21ef6d5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,14 +10,14 @@ services: volumes: - ${DB_PATH:-./data}:/app/data - ${MEDIA_PATH:-./media}:/app/media + - /mnt/data1:/mnt/data1 + command: node server.js environment: - NODE_ENV=production - - DATABASE_URL=${DATABASE_URL:-file:///app/data/nextav.db} - NEXT_PUBLIC_MEDIA_ROOT=${NEXT_PUBLIC_MEDIA_ROOT:-/app/media} - - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} - - NEXTAUTH_URL=${NEXTAUTH_URL} + - DB_FILE=/app/data/media.db healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] + test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3000/api/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })\""] interval: 30s timeout: 10s retries: 3 @@ -25,21 +25,7 @@ services: networks: - nextav-network - nginx: - image: nginx:alpine - container_name: nextav-nginx - restart: unless-stopped - ports: - - "${HTTP_PORT:-80}:80" - - "${HTTPS_PORT:-443}:443" - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf:ro - - ${SSL_CERT_PATH:-./ssl/cert.pem}:/etc/nginx/ssl/cert.pem:ro - - ${SSL_KEY_PATH:-./ssl/key.pem}:/etc/nginx/ssl/key.pem:ro - depends_on: - - nextav - networks: - - nextav-network + networks: nextav-network: diff --git a/docs/DEPLOYMENT_GUIDE.md b/docs/DEPLOYMENT_GUIDE.md index 693a001..d0234d7 100644 --- a/docs/DEPLOYMENT_GUIDE.md +++ b/docs/DEPLOYMENT_GUIDE.md @@ -1,261 +1,218 @@ # NextAV Deployment Guide ## Overview -This guide covers deploying NextAV to a private Docker registry and production server. +NextAV is a Next.js application that provides media library management with SQLite database storage. This guide covers Docker deployment, troubleshooting, and best practices for the NextAV application. ## Prerequisites -- Docker & Docker Compose installed -- Access to private registry (e.g., 192.168.2.212:3000) -- SSL certificates for HTTPS (optional for local deployment) +- Docker and Docker Compose installed +- At least 4GB of available disk space +- Port 3000 available ## Quick Start -### 1. Build & Push to Private Registry - +### 1. Clone and Setup ```bash -# Build the image -docker build -t 192.168.2.212:3000/tigeren/nextav:latest . - -# Push to private registry -docker push 192.168.2.212:3000/tigeren/nextav:latest - -# Verify push -curl http://192.168.2.212:3000/v2/_catalog +git clone +cd nextav ``` -### 2. Deploy to Production Server - +### 2. Environment Configuration +Create a `.env` file in the `docker` directory: ```bash -# Copy deployment files to server -scp -r docker/ user@server:/path/to/nextav/ - -# SSH to server -ssh user@server -cd /path/to/nextav/docker/ - -# Configure environment +cd docker cp .env.example .env -# Edit .env with your settings - -# Deploy -docker-compose up -d +# Edit .env with your configuration ``` -## Detailed Deployment Steps - -### Local Development +### 3. Create Required Directories ```bash -# Build locally -docker build -t nextav:dev . - -# Run locally -docker-compose -f docker-compose.yml up -d +mkdir -p data media +chmod 755 data media ``` -### Production with Private Registry - -#### Step 1: Configure Private Registry Access +### 4. Build and Run ```bash -# Add insecure registry to Docker daemon -echo '{ "insecure-registries": ["192.168.2.212:3000"] }' | \ - sudo tee /etc/docker/daemon.json -sudo systemctl restart docker +# Build the Docker image +docker build -t nextav:latest .. + +# Start the application +docker compose up -d ``` -#### Step 2: Build & Tag +### 5. Verify Deployment ```bash -# Build with registry tag -docker build -t 192.168.2.212:3000/tigeren/nextav:latest . -docker build -t 192.168.2.212:3000/tigeren/nextav:v1.0.0 . -``` +# Check container status +docker compose ps -#### Step 3: Push to Registry -```bash -# Push latest -docker push 192.168.2.212:3000/tigeren/nextav:latest - -# Push versioned -docker push 192.168.2.212:3000/tigeren/nextav:v1.0.0 -``` - -#### Step 4: Deploy on Target Server - -**On production server:** -```bash -# Create deployment directory -mkdir -p /opt/nextav -cd /opt/nextav - -# Copy deployment files -cp docker/docker-compose.yml . -cp docker/.env.example .env - -# Create SSL directory (optional) -mkdir -p ssl -# Copy your SSL certificates to ssl/cert.pem and ssl/key.pem - -# Configure environment -nano .env -``` - -**Edit .env file:** -```bash -REGISTRY_URL=192.168.2.212:3000 -IMAGE_NAME=tigeren/nextav -IMAGE_TAG=latest - -# Set your domain -NEXTAUTH_URL=https://your-domain.com -NEXTAUTH_SECRET=your-secure-secret - -# Adjust paths if needed -DB_PATH=./data -MEDIA_PATH=./media -``` - -**Deploy:** -```bash -# Pull and deploy -docker-compose pull -docker-compose up -d - -# Check status -docker-compose ps -docker-compose logs -f -``` - -## Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `REGISTRY_URL` | Private registry URL | 192.168.2.212:3000 | -| `IMAGE_NAME` | Image name | tigeren/nextav | -| `IMAGE_TAG` | Image tag | latest | -| `NEXT_PUBLIC_MEDIA_ROOT` | Media directory | /app/media | -| `DATABASE_URL` | Database file path | file:///app/data/nextav.db | -| `NEXTAUTH_SECRET` | Auth secret | required | -| `NEXTAUTH_URL` | Application URL | required | -| `SSL_CERT_PATH` | SSL certificate path | ./ssl/cert.pem | -| `SSL_KEY_PATH` | SSL private key path | ./ssl/key.pem | - -## Directory Structure - -``` -docker/ -├── .env.example # Environment template -├── docker-compose.yml # Production compose -├── nginx.conf # Nginx configuration -└── ssl/ # SSL certificates (optional) -``` - -## SSL Setup (Production) - -### Using Let's Encrypt -```bash -# Install certbot -sudo apt install certbot - -# Generate certificates -sudo certbot certonly --standalone -d your-domain.com - -# Copy certificates -cp /etc/letsencrypt/live/your-domain.com/fullchain.pem ssl/cert.pem -cp /etc/letsencrypt/live/your-domain.com/privkey.pem ssl/key.pem -``` - -### Using Self-Signed (Development) -```bash -# Generate self-signed certificates -openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ - -keyout ssl/key.pem -out ssl/cert.pem -``` - -## Monitoring & Maintenance - -### Health Checks -```bash -# Check application health +# Test health endpoint curl http://localhost:3000/api/health -# Check nginx health -curl http://localhost/health +# Access the application +open http://localhost:3000 ``` -### Logs -```bash -# View all logs -docker-compose logs -f +## Configuration -# View specific service logs -docker-compose logs -f nextav -docker-compose logs -f nginx -``` +### Environment Variables +| Variable | Default | Description | +|----------|---------|-------------| +| `DB_PATH` | `./data` | Path to database storage directory | +| `MEDIA_PATH` | `./media` | Path to media files directory | +| `DB_FILE` | `/app/data/media.db` | Database file path inside container | +| `NEXT_PUBLIC_MEDIA_ROOT` | `/app/media` | Media root path for the application | -### Updates -```bash -# Update to latest version -docker-compose pull -docker-compose up -d - -# Update to specific version -# Edit .env: IMAGE_TAG=v1.0.1 -docker-compose up -d -``` - -### Backup -```bash -# Backup database and media -tar -czf backup-$(date +%Y%m%d).tar.gz data/ media/ -``` +### Volume Mounts +- `./data:/app/data` - Database and application data +- `./media:/app/media` - Media files storage ## Troubleshooting -### Common Issues +### Database Access Issues +**Problem**: `SqliteError: unable to open database file` -**Registry connection failed:** +**Solution**: +1. Ensure data directory exists and has correct permissions: + ```bash + mkdir -p data + chmod 755 data + ``` + +2. Fix container permissions: + ```bash + docker exec -u root nextav-app chown -R nextjs:nodejs /app/data /app/media + ``` + +3. Restart the container: + ```bash + docker compose restart nextav + ``` + +### Native Module Issues +**Problem**: `Could not locate the bindings file. Tried: ... better_sqlite3.node` + +**Solution**: +1. Rebuild the Docker image: + ```bash + docker build --no-cache -t nextav:latest .. + ``` + +2. Ensure build dependencies are available in Dockerfile + +### Container Health Issues +**Problem**: Container shows as "unhealthy" + +**Solution**: +1. Check logs: + ```bash + docker compose logs nextav + ``` + +2. Test health endpoint manually: + ```bash + curl http://localhost:3000/api/health + ``` + +3. Verify database connectivity and permissions + +### Build Performance Issues +**Problem**: Docker build takes too long + +**Solutions**: +1. Use multi-stage builds (already implemented) +2. Remove unnecessary packages from production stage +3. Use `.dockerignore` to exclude unnecessary files +4. Consider using build cache + +## Best Practices + +### Security +- Run container as non-root user (implemented) +- Use specific image tags instead of `latest` +- Regularly update base images +- Scan images for vulnerabilities + +### Performance +- Use multi-stage builds to reduce image size +- Implement proper caching strategies +- Monitor resource usage +- Use health checks for reliability + +### Data Persistence +- Use named volumes for production +- Regular database backups +- Monitor disk space usage +- Implement proper backup strategies + +### Monitoring +- Health check endpoint: `/api/health` +- Application logs: `docker compose logs nextav` +- Resource monitoring: `docker stats` + +## Production Deployment + +### 1. Environment Setup ```bash -# Check registry accessibility -curl http://192.168.2.212:3000/v2/_catalog - -# Check Docker daemon configuration -cat /etc/docker/daemon.json +# Production environment variables +NODE_ENV=production +DB_PATH=/var/lib/nextav/data +MEDIA_PATH=/var/lib/nextav/media ``` -**Permission issues:** +### 2. Reverse Proxy (Optional) +Configure Nginx or Traefik for SSL termination and load balancing. + +### 3. Backup Strategy ```bash -# Fix file permissions -sudo chown -R $USER:$USER data/ media/ +# Database backup +docker exec nextav-app sqlite3 /app/data/media.db ".backup /app/data/backup.db" + +# Volume backup +docker run --rm -v nextav_data:/data -v $(pwd):/backup alpine tar czf /backup/nextav_data.tar.gz -C /data . ``` -**Port conflicts:** +### 4. Monitoring +- Set up log aggregation +- Monitor container health +- Track resource usage +- Set up alerts for failures + +## Maintenance + +### Regular Tasks +1. **Update Dependencies**: Monthly security updates +2. **Database Maintenance**: Regular backups and optimization +3. **Log Rotation**: Prevent disk space issues +4. **Image Updates**: Keep base images current + +### Troubleshooting Commands ```bash -# Check port usage -sudo netstat -tulpn | grep :3000 +# View logs +docker compose logs -f nextav + +# Access container shell +docker exec -it nextav-app sh + +# Check resource usage +docker stats nextav-app + +# Restart services +docker compose restart nextav + +# Update and rebuild +docker compose down +docker build -t nextav:latest .. +docker compose up -d ``` -### Debug Mode -```bash -# Run in debug mode -docker-compose up -# or -docker-compose logs -f nextav -``` +## Support -## One-Click Deployment +For issues not covered in this guide: +1. Check application logs +2. Review Docker documentation +3. Consult Next.js deployment guides +4. Open an issue in the project repository -Use the provided deployment script: -```bash -# Make executable -chmod +x deploy.sh +--- -# Run deployment -./deploy.sh -``` - -## Security Notes - -- Change default passwords and secrets -- Use HTTPS in production -- Regularly update images -- Monitor logs for suspicious activity -- Backup database regularly \ No newline at end of file +**Last Updated**: August 30, 2025 +**Version**: 1.0.0 \ No newline at end of file diff --git a/package.json b/package.json index 1d3c438..cdd8beb 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "dev": "next dev --turbopack", "build": "next build --turbopack", + "buildprod": "next build", "start": "next start" }, "dependencies": { diff --git a/src/db/index.ts b/src/db/index.ts index 9f76068..8f18705 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,13 +1,22 @@ import Database, { Database as DatabaseType } from 'better-sqlite3'; import path from 'path'; +import fs from 'fs'; let db: DatabaseType | null = null; function initializeDatabase() { if (db) return db; - const dbPath = path.join(process.cwd(), 'media.db'); + // const dbPath = process.env.DB_FILE || path.join(process.cwd(), 'media.db'); + const dbPath = path.join(process.cwd(), 'data', 'media.db'); + + // Ensure the data directory exists + const dataDir = path.dirname(dbPath); + if (!fs.existsSync(dataDir)) { + fs.mkdirSync(dataDir, { recursive: true }); + } + db = new Database(dbPath); // Create tables