Files
vps/docs/deployment-summary.md
service 1e1a528a5e Initial commit: VPS setup documentation
Add comprehensive documentation for VPS setup and configuration including:
- Project instructions
- VPS1 starting point configuration
- VPS1 current state documentation
- VPS1 todo list

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 07:43:24 +01:00

12 KiB

VPS1 Deployment Summary

Date Completed: 2026-01-25 Host: vps1.phiiiil.de (152.53.119.222) Status: Production Ready

Completed Work

0. Immich Photo Backup (2026-01-25)

Location: /home/phil/docker/backup/

Script: /home/phil/docker/backup/backup-immich-photos.sh

What Gets Backed Up:

  • Immich photo library (34,694 files, 39.34GB)
  • All photos, videos, thumbnails, and encoded videos
  • Incremental backup using rsync with hardlinking

Backup Location: /mnt/backup/immich-photos/

Schedule: Daily at 04:00 German time (CET/CEST)

Retention: 30 days

Latest Backup: /mnt/backup/immich-photos/latest (symlink)

Log: /var/log/immich-photo-backup.log

Performance:

  • First backup: ~4 minutes (164 MB/s)
  • Subsequent backups: Incremental (only changed/new files)
  • Space efficient: Uses hardlinks for unchanged files

Restore:

# Restore all photos
rsync -av /mnt/backup/immich-photos/latest/ /home/phil/docker/immich-app/library/

Status: Active and automated

1. Security Hardening

UFW Firewall

  • Status: Active and enabled
  • Default Policy: Deny incoming, Allow outgoing
  • Allowed Ports:
    • 22/tcp (SSH)
    • 80/tcp (HTTP - Caddy)
    • 443/tcp (HTTPS - Caddy)
    • 443/udp (HTTP3/QUIC - Caddy)
    • 2283/tcp (Immich)
    • 2222/tcp (Gitea SSH)
    • Existing game server ports preserved

Fail2ban

  • Status: Active and protecting SSH
  • Configuration:
    • Ban time: 1 hour (3600s)
    • Find time: 10 minutes
    • Max retries: 3
    • Backend: systemd journal
  • Currently Banned: 5 IPs (SSH brute force attempts)

2. Gitea Deployment

Location: /home/phil/docker/gitea/

Services:

  • gitea - Git hosting application (Gitea latest)
  • gitea-db - PostgreSQL 16 database

Configuration:

  • Domain: git.phiiiil.de DNS configured
  • Database: PostgreSQL with strong password
  • SSH Port: 2222
  • Network: netbird_netbird (shared)
  • Registration: Disabled (private instance)
  • OIDC: Enabled for Netbird integration
  • Admin: User phil created with secure password

Status: Running and healthy

Access:

Volumes:

  • gitea_gitea_db_data - PostgreSQL data
  • gitea_gitea_data - Gitea application data

3. Caddy Reverse Proxy

Configuration:

Routes:

  • nb.phiiiil.de → Netbird Dashboard & API
  • git.phiiiil.de → Gitea (port 3000)
  • immich.phiiiil.de → Immich (port 2283)

Network Configuration:

  • Caddy connected to both netbird_netbird and immich_default networks
  • Can proxy to all services

Security Headers Applied:

  • HSTS (3600s, includeSubDomains, preload)
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin

SSL Certificates:

  • nb.phiiiil.de - Let's Encrypt
  • git.phiiiil.de - Let's Encrypt
  • immich.phiiiil.de - Let's Encrypt

4. Backup System

Location: /home/phil/docker/backup/

Scripts:

  • /home/phil/docker/backup/backup.sh - Databases and volumes (02:00)
  • /home/phil/docker/backup/backup-immich-photos.sh - Photo library (04:00)

What Gets Backed Up:

Database Backup (02:00):

  1. Immich PostgreSQL database (52MB)
  2. Immich library manifest (file count, size)
  3. Netbird management data (31MB)
  4. Netbird Zitadel database (77KB)
  5. Gitea PostgreSQL database (24KB)
  6. Gitea data volume (9.4KB)

Photo Backup (04:00): 7. Immich photo library (34,694 files, 39.34GB) 8. Incremental backup with hardlinking 9. 30-day retention

Backup Location: /mnt/backup/

Schedule: Daily at 02:00 and 04:00 German time (cron)

Retention: 30 days

Latest Backups:

  • Databases: /mnt/backup/latest (symlink)
  • Photos: /mnt/backup/immich-photos/latest (symlink)

Logs:

  • Databases: /var/log/vps-backup.log
  • Photos: /var/log/immich-photo-backup.log

Remote Storage:

  • ⚠️ Currently backing up to local disk only
  • Remote storage should be mounted to /mnt/backup for off-site backups

5. Network Configuration

Docker Networks:

  • bridge (default)
  • netbird_netbird - Netbird, Gitea, Immich, Caddy
  • immich_default - Immich services, Caddy
  • host (for Coturn)

Firewall Rules:

  • All services properly accessible
  • Only necessary ports exposed
  • Default deny incoming policy

System Status

Running Containers

Service Status Health Ports URL
Netbird (8 containers) Running 1 healthy 80, 443 https://nb.phiiiil.de
Immich (4 containers) Running 3 healthy 2283 https://immich.phiiiil.de
Gitea (2 containers) Running 2 healthy 2222, 3000 https://git.phiiiil.de

Resource Usage

  • Disk: 55GB used of 1TB (6%) - 900GB free
  • RAM: ~2GB used of 15GB - 13GB free
  • Containers: 12 total

File Structure

/home/phil/docker/
├── netbird/              # Netbird VPN + Caddy
│   ├── docker-compose.yml
│   ├── Caddyfile
│   └── *.env files
├── immich-app/           # Immich Photo Management
│   ├── docker-compose.yml
│   ├── .env
│   ├── library/          # 37GB of photos ⚠️
│   └── postgres/
├── gitea/                # Git Hosting
│   ├── docker-compose.yml
│   └── .env
└── backup/               # Backup Scripts
    └── backup.sh         # Main backup script

/mnt/backup/              # Backup storage (mount remote storage here)
└── latest/               # Symlink to latest backup

Security Checklist

  • UFW firewall configured and active
  • Fail2ban protecting SSH (5 IPs blocked)
  • Only necessary ports exposed
  • Docker containers running as non-root user
  • Environment files have restricted permissions (600)
  • SSL/TLS via Caddy (Let's Encrypt) for all domains
  • Security headers configured in Caddy
  • Gitea registration disabled (private instance)
  • Automated daily backups (30-day retention)
  • OIDC SSO integration ready to configure
  • Remote backup storage needs to be mounted

Monitoring

Docker Health Checks

All services have health checks configured:

# Check all container health
docker ps --format "table {{.Names}}\t{{.Status}}"

# Check specific container
docker inspect <container> | grep -A 5 Health

Current Health Status:

  • gitea (healthy)
  • gitea-db (healthy)
  • immich_server (healthy)
  • immich_postgres (healthy)
  • immich_redis (healthy)
  • immich_machine_learning (healthy)
  • netbird-zdb-1 (healthy)

Backup Monitoring

Check latest backup:

ls -lah /mnt/backup/latest/
cat /mnt/backup/latest/backup-info.txt

Check backup log:

tail -f /var/log/vps-backup.log

System Monitoring

Basic health:

# Disk usage
df -h

# Memory usage
free -h

# Container resource usage
docker stats

# Firewall status
sudo ufw status numbered

# Fail2ban status
sudo fail2ban-client status sshd

Maintenance Tasks

Daily

  • Automated backups run at 2:00 AM
  • Check backup completion

Weekly

  • Check backup logs
  • Verify backup completion
  • Review fail2ban bans
  • Check disk space

Monthly

  • Review and update container images
cd /home/phil/docker/gitea && docker compose pull
cd /home/phil/docker/netbird && docker compose pull
cd /home/phil/docker/immich-app && docker compose pull
  • Check for security updates
sudo apt update && sudo apt upgrade

Quarterly

  • Test backup restoration procedures
  • Review and rotate SSH keys if needed
  • Audit firewall rules
  • Review and clean old backups (auto-cleanup after 30 days)

Emergency Procedures

Restore from Backup

  1. Identify backup to restore:
ls -lah /mnt/backup/
  1. Restore Immich database:
gunzip < /mnt/backup/latest/immich-db.sql.gz | docker exec -i immich_postgres psql -U postgres immich
  1. Restore Gitea database:
gunzip < /mnt/backup/latest/gitea-db.sql.gz | docker exec -i gitea-db psql -U gitea gitea
  1. Restore Gitea data volume:
docker run --rm -v gitea_gitea_data:/data -v /mnt/backup/latest:/backup alpine tar xzf /backup/gitea-data.tar.gz -C /data
  1. Restore Netbird management data:
docker run --rm -v netbird_netbird_management:/data -v /mnt/backup/latest:/backup alpine tar xzf /backup/netbird-management.tar.gz -C /data

Restart Services

# Netbird (includes Caddy)
cd /home/phil/docker/netbird && docker compose restart

# Gitea
cd /home/phil/docker/gitea && docker compose restart

# Immich
cd /home/phil/docker/immich-app && docker compose restart

# Specific container
docker restart <container_name>

Documentation

  • vps1-state-25012026.md - Current system state and operational guide
  • vps1-startpoint.md - System analysis and architecture
  • docs/oidc-integration-guide.md - SSO setup with Netbird Zitadel

Support

Logs

  • Caddy: docker logs netbird-caddy-1
  • Netbird Management: docker logs netbird-management-1
  • Gitea: docker logs gitea
  • Gitea DB: docker logs gitea-db
  • Immich: docker logs immich_server
  • Backups: /var/log/vps-backup.log
  • System: journalctl -u docker

Useful Commands

# SSH to VPS
ssh vps1

# View running containers
docker ps

# View container logs
docker logs -f <container>

# Restart container
docker restart <container>

# Check firewall
sudo ufw status numbered

# Check fail2ban
sudo fail2ban-client status sshd

# Run backup manually
/home/phil/docker/backup/backup.sh

# Check disk usage
df -h

# Check memory
free -h

Pending Tasks

1. SSO Integration Plan 📋 (Optional)

Status: Plan created, ready for implementation

Documentation:

  • docs/sso-integration-plan.md - Comprehensive implementation guide
  • docs/sso-integration-diagram.txt - Visual architecture diagrams

What: Integrate Gitea and Immich with Netbird Zitadel for single sign-on (SSO)

Benefits:

  • Unified authentication across all services
  • Centralized user management via Netbird dashboard
  • Secure OAuth2/OIDC flow with PKCE
  • No need to remember multiple passwords

Prerequisites:

  • Zitadel OIDC endpoint accessible
  • Gitea OAuth2 already enabled
  • DNS and SSL configured for all services
  • Netbird admin access

Estimated Time: ~2.5 hours

See: docs/sso-integration-plan.md for complete implementation guide

Action Required: Mount remote storage to /mnt/backup

Options:

  • S3 bucket via s3fs
  • NFS mount
  • SSHFS
  • WebDAV

Once mounted, update backup script to include Immich photo backup.

Status: Implementation plan created

Documentation:

  • docs/sso-integration-plan.md - Complete implementation guide (NEW)
  • docs/sso-integration-diagram.txt - Architecture diagrams (NEW)
  • docs/oidc-integration-guide.md - Original setup guide

Scope:

  • Gitea + Immich + Netbird Zitadel SSO

Ready to implement when needed

Success Metrics

  • All containers running and healthy
  • Firewall active and protecting system
  • Fail2ban blocking SSH brute force (5 IPs banned)
  • Automated backups configured (databases + photos)
  • Immich photo backup active (39.34GB, daily 04:00)
  • Gitea deployed with admin user created
  • SSL certificates for all domains
  • Security headers configured
  • Remote backup storage (recommended)
  • OIDC SSO (optional, plan created)

Conclusion

The VPS is now fully operational with:

  1. Secure baseline: UFW firewall, fail2ban, security headers
  2. Git hosting: Gitea with PostgreSQL, admin user created
  3. Photo management: Immich with 39GB of photos, fully backed up
  4. VPN & SSO: Netbird with Zitadel identity provider
  5. Automated backups: Daily backups of all databases AND photos
  6. Reverse proxy: Caddy handling SSL and routing for all services

All core services are production-ready with complete backup coverage.

Optional enhancements:

  • Mount remote backup storage to /mnt/backup for off-site backups
  • Configure OIDC SSO for Gitea and Immich (plan created)
  • Set up container monitoring

Last Updated: 2026-01-25 System Status: Production Ready Total Services: 12 containers across 3 applications