Compare commits

..

4 Commits

Author SHA1 Message Date
Quality App Developer
a4262da7c9 chore: fix file permissions and ownership across project
- Changed ownership of all files to scheianu:scheianu
- Set directories to 755 permissions (rwxr-xr-x)
- Set files to 644 permissions (rw-r--r--)
- Made shell scripts executable (755)
- Allows development without requiring sudo for file modifications
- Improves development workflow and security
2026-01-15 22:39:51 +02:00
Quality App Developer
024430754c docs: add comprehensive quick deployment guide
- Complete deployment workflow documentation
- Container architecture explanation
- Step-by-step deployment process
- Common commands reference
- Troubleshooting section
- SSL certificate management
- Performance tuning guide
- Security checklist
- Health checks information
- Database backup/restore procedures
2026-01-15 22:31:37 +02:00
Quality App Developer
d17ed79e29 chore: remove caddy-related and obsolete files
Removed:
- Caddyfile: Caddy reverse proxy config (replaced by nginx.conf)
- setup_https.sh: Caddy HTTPS setup script
- https_manager.py: Caddy HTTPS management utility
- HTTPS_STATUS.txt: Old HTTPS documentation
- docker-compose.http.yml: HTTP-only Caddy compose file
- player_auth_module.py: Old authentication module (unused)
- player_config_template.ini: Old player config template (unused)
- test connection.txr: Test file

Updated:
- init-data.sh: Removed references to deleted caddy/obsolete files
- .dockerignore: Removed obsolete ignore entries

This completes the Caddy → Nginx migration cleanup.
2026-01-15 22:25:13 +02:00
root
21eb63659a feat: complete nginx migration from caddy
- Replace Caddy reverse proxy with Nginx (nginx:alpine)
- Add nginx.conf with HTTP/HTTPS, gzip, and proxy settings
- Add nginx-custom-domains.conf template for custom domains
- Update docker-compose.yml to use Nginx service
- Add ProxyFix middleware to Flask app for proper header handling
- Create nginx_config_reader.py utility to read Nginx configuration
- Update admin blueprint to display Nginx status in https_config page
- Add Nginx configuration display to https_config.html template
- Generate self-signed SSL certificates for localhost
- Add utility scripts: generate_nginx_certs.sh
- Add documentation: NGINX_SETUP_QUICK.md, PROXY_FIX_SETUP.md
- All containers now running, HTTPS working, HTTP redirects to HTTPS
- Session cookies marked as Secure
- Security headers properly configured
2026-01-15 22:15:11 +02:00
110 changed files with 1078 additions and 1287 deletions

4
.dockerignore Executable file → Normal file
View File

@@ -52,6 +52,4 @@ PLAYER_AUTH.md
PROGRESS.md
README.md
# Config templates
player_config_template.ini
player_auth_module.py

0
.gitignore vendored Executable file → Normal file
View File

View File

@@ -1,73 +0,0 @@
{
# Global options
email admin@example.com
# Admin API for configuration management (listen on all interfaces)
admin 0.0.0.0:2019
}
# Shared reverse proxy configuration
(reverse_proxy_config) {
reverse_proxy digiserver-app:5000 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Proto {scheme}
# Timeouts for large uploads
transport http {
read_timeout 300s
write_timeout 300s
}
}
# File upload size limit (2GB)
request_body {
max_size 2GB
}
# Security headers
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
}
# Logging
log {
output file /var/log/caddy/access.log
}
}
# Localhost (development/local access - HTTP only for local dev)
http://localhost {
import reverse_proxy_config
}
# Main HTTPS entry point with multiple hostnames and IP
https://digiserver, https://10.76.152.164, https://digiserver.sibiusb.harting.intra {
import reverse_proxy_config
tls internal
}
# HTTP redirects to HTTPS for each hostname
http://digiserver {
redir https://{host}{uri}
}
http://10.76.152.164 {
redir https://{host}{uri}
}
http://digiserver.sibiusb.harting.intra {
redir https://{host}{uri}
}
# Catch-all for any other HTTP requests
http://* {
import reverse_proxy_config
}
# Catch-all for any other HTTPS requests (fallback)
https://* {
import reverse_proxy_config
tls internal
}

0
Dockerfile Executable file → Normal file
View File

View File

@@ -1,413 +0,0 @@
╔═══════════════════════════════════════════════════════════════════════════════╗
║ HTTPS MANAGEMENT SYSTEM IMPLEMENTATION ║
║ ✅ COMPLETE ║
╚═══════════════════════════════════════════════════════════════════════════════╝
📦 DELIVERABLES
═══════════════════════════════════════════════════════════════════════════════
✅ CREATED FILES (9 new files)
───────────────────────────────────────────────────────────────────────────────
1. 🗄️ DATABASE MODEL
└─ app/models/https_config.py
• HTTPSConfig database model
• Fields: hostname, domain, ip_address, port, status, audit trail
• Methods: get_config(), create_or_update(), to_dict()
• Auto timestamps for created/updated dates
2. 🛣️ ADMIN ROUTES
└─ app/blueprints/admin.py (UPDATED)
• GET /admin/https-config - Configuration page
• POST /admin/https-config/update - Update settings
• GET /admin/https-config/status - JSON status endpoint
• Full validation and error handling
• Admin-only access control
3. 🎨 ADMIN TEMPLATE
└─ app/templates/admin/https_config.html
• Beautiful, user-friendly configuration interface
• Status display section
• Configuration form with toggle switch
• Input validation feedback
• Real-time preview of access points
• Comprehensive help sections
• Responsive mobile design
4. 📊 ADMIN DASHBOARD
└─ app/templates/admin/admin.html (UPDATED)
• New card: "🔒 HTTPS Configuration"
• Links to HTTPS configuration page
• Gradient design with lock icon
5. 🔄 DATABASE MIGRATION
└─ migrations/add_https_config_table.py
• Creates https_config table
• Sets up indexes and constraints
• Audit trail fields
6. 🖥️ CLI UTILITY
└─ https_manager.py
• Command-line interface
• Commands: status, enable, disable, show
• Useful for automation and scripting
7. 🚀 SETUP SCRIPT
└─ setup_https.sh
• Automated setup script
• Runs database migration
• Displays step-by-step instructions
8. 📚 DOCUMENTATION
├─ HTTPS_CONFIGURATION.md (Comprehensive guide)
├─ HTTPS_IMPLEMENTATION_SUMMARY.md (Architecture & details)
└─ HTTPS_QUICK_REFERENCE.md (Admin quick start)
═══════════════════════════════════════════════════════════════════════════════
✅ UPDATED FILES (3 modified files)
───────────────────────────────────────────────────────────────────────────────
1. ✏️ app/models/__init__.py
• Added HTTPSConfig import
• Exported in __all__ list
2. ✏️ app/blueprints/admin.py
• Imported HTTPSConfig model
• Added three new routes for HTTPS management
• 160+ lines of new admin functionality
3. ✏️ app/templates/admin/admin.html
• Added HTTPS Configuration card to dashboard
• Purple gradient with lock icon
4. ✏️ Caddyfile
• Updated to use domain: digiserver.sibiusb.harting.intra
• IP fallback: 10.76.152.164
═══════════════════════════════════════════════════════════════════════════════
🎯 KEY FEATURES
═══════════════════════════════════════════════════════════════════════════════
✅ WEB INTERFACE
• Enable/Disable HTTPS with toggle switch
• Configure hostname, domain, IP address, port
• Status display with current settings
• Real-time preview of access URLs
• User-friendly form with validations
• Responsive design for all devices
✅ CONFIGURATION OPTIONS
• Hostname: Short server name
• Domain: Full domain name (e.g., digiserver.sibiusb.harting.intra)
• IP Address: Server IP (e.g., 10.76.152.164)
• Port: HTTPS port (default 443)
• Enable/Disable toggle
✅ SECURITY
• Admin-only access with permission checks
• Input validation (domain, IP, port)
• Admin audit trail (who changed what, when)
• Server-side validation
• Logged in system logs
✅ VALIDATION
• Domain format validation
• IPv4 address validation (0-255 range)
• Port range validation (1-65535)
• Required field checks
• User-friendly error messages
✅ LOGGING
• All configuration changes logged
• Admin username recorded
• Timestamps for all changes
• Searchable in admin dashboard
✅ INTEGRATION
• Works with existing Caddy reverse proxy
• Automatic Let's Encrypt SSL certificates
• No manual certificate management
• Automatic certificate renewal
• HTTP/HTTPS dual access
═══════════════════════════════════════════════════════════════════════════════
🚀 QUICK START (5 Minutes)
═══════════════════════════════════════════════════════════════════════════════
1⃣ RUN DATABASE MIGRATION
┌─ Option A: Automated
│ bash setup_https.sh
└─ Option B: Manual
python /app/migrations/add_https_config_table.py
2⃣ START APPLICATION
docker-compose up -d
3⃣ LOG IN AS ADMIN
• Navigate to admin panel
• Use admin credentials
4⃣ CONFIGURE HTTPS
• Go to: Admin Panel → 🔒 HTTPS Configuration
• Toggle: Enable HTTPS ✅
• Fill in:
- Hostname: digiserver
- Domain: digiserver.sibiusb.harting.intra
- IP: 10.76.152.164
- Port: 443
• Click: Save HTTPS Configuration
5⃣ VERIFY
• Check status shows "✅ HTTPS ENABLED"
• Access via: https://digiserver.sibiusb.harting.intra
• Fallback: http://10.76.152.164
═══════════════════════════════════════════════════════════════════════════════
📋 DATABASE SCHEMA
═══════════════════════════════════════════════════════════════════════════════
TABLE: https_config
┌─────────────────┬──────────────┬──────────────────────────────────────┐
│ Column │ Type │ Purpose │
├─────────────────┼──────────────┼──────────────────────────────────────┤
│ id │ INTEGER (PK) │ Primary key │
│ https_enabled │ BOOLEAN │ Enable/disable HTTPS │
│ hostname │ STRING(255) │ Server hostname (e.g., digiserver) │
│ domain │ STRING(255) │ Domain (e.g., domain.local) │
│ ip_address │ STRING(45) │ IP address (IPv4/IPv6) │
│ port │ INTEGER │ HTTPS port (default 443) │
│ created_at │ DATETIME │ Creation timestamp │
│ updated_at │ DATETIME │ Last update timestamp │
│ updated_by │ STRING(255) │ Admin who made change │
└─────────────────┴──────────────┴──────────────────────────────────────┘
═══════════════════════════════════════════════════════════════════════════════
🔐 SECURITY FEATURES
═══════════════════════════════════════════════════════════════════════════════
✅ Access Control
• Admin-only routes with @admin_required decorator
• Permission checks on all endpoints
• Login required for configuration access
✅ Input Validation
• Domain format validation
• IP address validation (IPv4/IPv6)
• Port range validation (1-65535)
• Required field validation
• Error messages for invalid inputs
✅ SSL/TLS Management
• Automatic Let's Encrypt certificates
• Automatic renewal before expiration
• Security headers (HSTS, X-Frame-Options, etc.)
• HTTP/2 and HTTP/3 support via Caddy
✅ Audit Trail
• All changes logged with timestamp
• Admin username recorded
• Enable/disable events tracked
• Searchable in server logs
═══════════════════════════════════════════════════════════════════════════════
🛠️ ADMIN COMMANDS
═══════════════════════════════════════════════════════════════════════════════
CLI UTILITY: https_manager.py
───────────────────────────────────────────────────────────────────────────
Show Status:
python https_manager.py status
Enable HTTPS:
python https_manager.py enable digiserver digiserver.sibiusb.harting.intra 10.76.152.164 443
Disable HTTPS:
python https_manager.py disable
Show Configuration:
python https_manager.py show
═══════════════════════════════════════════════════════════════════════════════
📊 ACCESS POINTS
═══════════════════════════════════════════════════════════════════════════════
AFTER CONFIGURATION:
┌─ HTTPS (Recommended) ────────────────────────────────────────────┐
│ URL: https://digiserver.sibiusb.harting.intra │
│ Protocol: HTTPS (SSL/TLS) │
│ Port: 443 │
│ Certificate: Let's Encrypt (auto-renewed) │
│ Use: All secure connections, recommended for everyone │
└──────────────────────────────────────────────────────────────────┘
┌─ HTTP (Fallback) ────────────────────────────────────────────────┐
│ URL: http://10.76.152.164 │
│ Protocol: HTTP (plain text) │
│ Port: 80 │
│ Use: Troubleshooting, direct IP access, local network │
└──────────────────────────────────────────────────────────────────┘
═══════════════════════════════════════════════════════════════════════════════
📚 DOCUMENTATION FILES
═══════════════════════════════════════════════════════════════════════════════
1. HTTPS_QUICK_REFERENCE.md
• Quick setup guide (5 minutes)
• Admin checklist
• Common tasks
• Troubleshooting basics
• STATUS: ⭐ START HERE!
2. HTTPS_CONFIGURATION.md
• Comprehensive feature guide
• Step-by-step workflow
• Configuration details
• Prerequisites and requirements
• Integration overview
• Troubleshooting guide
• STATUS: For detailed reference
3. HTTPS_IMPLEMENTATION_SUMMARY.md
• Architecture and design
• Files created/modified
• Database schema
• Integration details
• Implementation checklist
• STATUS: For developers
═══════════════════════════════════════════════════════════════════════════════
✅ WORKFLOW
═══════════════════════════════════════════════════════════════════════════════
INITIAL STATE (HTTP ONLY)
┌─────────────────────┐
│ App on Port 80 │
│ HTTP only │
└────────┬────────────┘
└─ Accessible at: http://10.76.152.164
USER CONFIGURES HTTPS
┌─────────────────────────────────────────────┐
│ Admin Sets: │
│ • Hostname: digiserver │
│ • Domain: digiserver.sibiusb.harting.intra │
│ • IP: 10.76.152.164 │
│ • Port: 443 │
└────────┬────────────────────────────────────┘
CONFIGURATION SAVED
┌──────────────────────────────────────────────┐
│ • Settings stored in database │
│ • Change logged with admin name & timestamp │
│ • Status updated in admin panel │
└────────┬─────────────────────────────────────┘
SYSTEM OPERATIONAL
├─ HTTPS Active (Port 443)
│ URL: https://digiserver.sibiusb.harting.intra
│ Certificate: Auto-managed by Let's Encrypt
└─ HTTP Fallback (Port 80)
URL: http://10.76.152.164
For troubleshooting and backup access
═══════════════════════════════════════════════════════════════════════════════
✨ HIGHLIGHTS
═══════════════════════════════════════════════════════════════════════════════
🎯 USER EXPERIENCE
• No manual configuration needed
• Simple toggle to enable/disable
• Real-time preview of settings
• Status display shows current state
• Mobile-responsive interface
🔒 SECURITY
• Admin-only access
• Input validation on all fields
• Audit trail of all changes
• Automatic SSL certificates
• No sensitive data stored in plain text
⚙️ FLEXIBILITY
• Configurable hostname, domain, IP
• Custom port support
• Enable/disable without data loss
• CLI and web interface both available
• Works with existing Caddy setup
📊 MONITORING
• Status endpoint for integration
• Logged changes in server logs
• Admin dashboard status display
• CLI status command
🚀 AUTOMATION
• CLI interface for scripting
• Can be automated via setup scripts
• Supports headless configuration
• REST API endpoint for status
═══════════════════════════════════════════════════════════════════════════════
📋 CHECKLIST
═══════════════════════════════════════════════════════════════════════════════
IMPLEMENTATION
✅ Database model created (https_config.py)
✅ Admin routes added (3 new endpoints)
✅ Admin template created (https_config.html)
✅ Dashboard card added
✅ Database migration created
✅ CLI utility implemented
✅ Setup script created
✅ Documentation completed (3 guides)
✅ Code integrated with existing system
✅ Admin-only access enforced
✅ Input validation implemented
✅ Logging implemented
✅ Error handling added
DEPLOYMENT
⏳ Run database migration: python migrations/add_https_config_table.py
⏳ Start application: docker-compose up -d
⏳ Configure via admin panel
⏳ Verify access points
⏳ Check status display
⏳ Review logs for changes
═══════════════════════════════════════════════════════════════════════════════
🎉 SYSTEM READY
═══════════════════════════════════════════════════════════════════════════════
All files have been created and integrated.
The HTTPS configuration management system is complete and ready to use.
NEXT STEPS:
1. Run database migration
2. Restart application
3. Access admin panel
4. Navigate to HTTPS Configuration
5. Enable and configure HTTPS settings
6. Verify access points
For detailed instructions, see: HTTPS_QUICK_REFERENCE.md
═══════════════════════════════════════════════════════════════════════════════

487
QUICK_DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,487 @@
# DigiServer v2 - Quick Deployment Guide
## 📋 Overview
DigiServer is deployed using Docker Compose with the following architecture:
```
Internet (User)
Nginx Reverse Proxy (Port 80/443)
Internal Docker Network
Flask App (Gunicorn on Port 5000)
SQLite Database
```
---
## 🚀 Quick Start (One Command)
```bash
cd /srv/digiserver-v2
bash deploy.sh
```
This will:
1. ✅ Start Docker containers
2. ✅ Initialize database
3. ✅ Run migrations
4. ✅ Configure HTTPS
5. ✅ Display access information
---
## 📦 Container Architecture
### **Container 1: digiserver-app (Flask)**
- **Image**: Built from Dockerfile (Python 3.13)
- **Port**: 5000 (internal only)
- **Volumes**:
- `./data:/app` - Persistent application data
- `./data/instance:/app/instance` - Database & configuration
- `./data/uploads:/app/app/static/uploads` - User uploads
- **Startup**: Automatically initializes database on first run
- **Health Check**: Every 30 seconds
### **Container 2: nginx (Reverse Proxy)**
- **Image**: nginx:alpine
- **Ports**: 80 & 443 (exposed to internet)
- **Volumes**:
- `nginx.conf` - Main configuration
- `./data/nginx-ssl/` - SSL certificates
- `./data/nginx-logs/` - Access/error logs
- `./data/certbot/` - Let's Encrypt challenges
- **Startup**: Waits for Flask app to start
- **Health Check**: Every 30 seconds
---
## 🔧 Deployment Steps Explained
### **Step 1: Start Containers**
```bash
docker-compose up -d
```
- Builds Flask app image (if needed)
- Starts both containers
- Waits for containers to be healthy
### **Step 2: Database Initialization** (docker-entrypoint.sh)
When Flask container starts:
1. Create required directories
2. Check if database exists
3. If NOT exists:
- Initialize SQLite database (dashboard.db)
- Create admin user from environment variables
4. Start Gunicorn server (4 workers, 120s timeout)
### **Step 3: Run Migrations**
```bash
docker-compose exec -T digiserver-app python /app/migrations/[migration_name].py
```
Applied migrations:
- `add_https_config_table.py` - HTTPS settings
- `add_player_user_table.py` - Player user management
- `add_email_to_https_config.py` - Email configuration
- `migrate_player_user_global.py` - Global settings
### **Step 4: Configure HTTPS**
- SSL certificates stored in `./data/nginx-ssl/`
- Pre-generated self-signed certs for development
- Ready for Let's Encrypt integration
### **Step 5: Reverse Proxy Routing** (nginx.conf)
```
HTTP (80):
• Redirect all traffic to HTTPS
• Allow ACME challenges for Let's Encrypt
HTTPS (443):
• TLS 1.2+, HTTP/2 enabled
• Proxy all requests to Flask app
• Security headers added
• Gzip compression enabled
• Max upload size: 2GB
• Proxy timeout: 300s
```
### **Step 6: ProxyFix Middleware** (app/app.py)
Extracts real client information from Nginx headers:
- `X-Forwarded-For` → Real client IP
- `X-Forwarded-Proto` → Protocol (http/https)
- `X-Forwarded-Host` → Original hostname
- `X-Forwarded-Port` → Original port
---
## 📂 Directory Structure & Persistence
```
/srv/digiserver-v2/
├── app/ (Flask application code)
├── data/ (PERSISTENT - mounted as Docker volume)
│ ├── app/ (Copy of app/ for container)
│ ├── instance/ (dashboard.db - SQLite database)
│ ├── uploads/ (User uploaded files)
│ ├── nginx-ssl/ (SSL certificates)
│ ├── nginx-logs/ (Nginx logs)
│ └── certbot/ (Let's Encrypt challenges)
├── migrations/ (Database schema updates)
├── docker-compose.yml (Container orchestration)
├── Dockerfile (Flask app image definition)
├── nginx.conf (Reverse proxy configuration)
└── docker-entrypoint.sh (Container startup script)
```
---
## 🔐 Default Credentials
```
Username: admin
Password: admin123
```
⚠️ **CHANGE IMMEDIATELY IN PRODUCTION!**
---
## 🌐 Access Points
After deployment, access the app at:
- `https://localhost` (if deployed locally)
- `https://192.168.0.121` (if deployed on server)
- `https://<DOMAIN>` (if DNS configured)
---
## ⚙️ Environment Variables (Optional)
Create `.env` file in project root:
```bash
# Network Configuration
HOSTNAME=digiserver
DOMAIN=digiserver.example.com
IP_ADDRESS=192.168.0.121
# SSL/HTTPS
EMAIL=admin@example.com
# Flask Configuration
SECRET_KEY=your-secret-key-here
FLASK_ENV=production
# Admin User
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
```
Then start with:
```bash
docker-compose up -d
```
---
## 🛠️ Common Commands
### **Start/Stop Containers**
```bash
# Start containers
docker-compose up -d
# Stop containers
docker-compose down
# Restart containers
docker-compose restart
# Restart specific container
docker-compose restart digiserver-app
docker-compose restart nginx
```
### **View Logs**
```bash
# All containers
docker-compose logs
# Follow logs (real-time)
docker-compose logs -f
# Specific container
docker-compose logs -f digiserver-app
docker-compose logs -f nginx
# Show last 50 lines
docker-compose logs --tail=50 digiserver-app
```
### **Container Status**
```bash
# Show running containers
docker-compose ps
# Show container details
docker-compose ps -a
# Check container health
docker ps --format="table {{.Names}}\t{{.Status}}"
```
### **Database Operations**
```bash
# Access database shell
docker-compose exec digiserver-app sqlite3 /app/instance/dashboard.db
# Backup database
docker-compose exec digiserver-app cp /app/instance/dashboard.db /app/instance/dashboard.db.backup
# Restore database
docker-compose exec digiserver-app cp /app/instance/dashboard.db.backup /app/instance/dashboard.db
```
### **Nginx Operations**
```bash
# Validate Nginx configuration
docker exec digiserver-nginx nginx -t
# Reload Nginx (without restart)
docker exec digiserver-nginx nginx -s reload
# View Nginx logs
docker-compose logs -f nginx
```
---
## 🔒 SSL Certificate Management
### **Generate New Self-Signed Certificate**
```bash
bash generate_nginx_certs.sh 192.168.0.121 365
docker-compose restart nginx
```
Parameters:
- `192.168.0.121` - Domain/IP for certificate
- `365` - Certificate validity in days
### **Set Up Let's Encrypt (Production)**
1. Update `DOMAIN` and `EMAIL` in environment
2. Modify `nginx.conf` to enable certbot challenges
3. Run certbot:
```bash
docker run --rm -v $(pwd)/data/certbot:/etc/letsencrypt \
-v $(pwd)/data/nginx-logs:/var/log/letsencrypt \
certbot/certbot certonly --webroot \
-w /var/www/certbot \
-d yourdomain.com \
-m your-email@example.com \
--agree-tos
```
---
## 🐛 Troubleshooting
### **Containers not starting?**
```bash
# Check docker-compose logs
docker-compose logs
# Check system resources
docker stats
# Restart Docker daemon
sudo systemctl restart docker
```
### **Application not responding?**
```bash
# Check app container health
docker-compose ps
# View app logs
docker-compose logs -f digiserver-app
# Test Flask directly
docker-compose exec digiserver-app curl http://localhost:5000/
```
### **HTTPS not working?**
```bash
# Verify Nginx config
docker exec digiserver-nginx nginx -t
# Check SSL certificates exist
ls -la ./data/nginx-ssl/
# View Nginx error logs
docker-compose logs nginx
```
### **Database issues?**
```bash
# Check database file exists
ls -la ./data/instance/dashboard.db
# Verify database permissions
docker-compose exec digiserver-app ls -la /app/instance/
# Check database tables
docker-compose exec digiserver-app sqlite3 /app/instance/dashboard.db ".tables"
```
### **Port already in use?**
```bash
# Find process using port 80
sudo lsof -i :80
# Find process using port 443
sudo lsof -i :443
# Kill process (if needed)
sudo kill -9 <PID>
```
---
## 📊 Health Checks
Both containers have health checks:
**Flask App**: Pings `http://localhost:5000/` every 30 seconds
**Nginx**: Pings `http://localhost:80/` every 30 seconds
Check health status:
```bash
docker-compose ps
# Look for "Up (healthy)" status
```
---
## 🔄 Database Backup & Restore
### **Backup**
```bash
# Create backup
docker-compose exec digiserver-app cp /app/instance/dashboard.db /app/instance/dashboard.backup.db
# Download to local machine
cp ./data/instance/dashboard.backup.db ./backup/
```
### **Restore**
```bash
# Stop containers
docker-compose stop
# Restore database
cp ./backup/dashboard.backup.db ./data/instance/dashboard.db
# Start containers
docker-compose up -d
```
---
## 📈 Performance Tuning
### **Gunicorn Workers** (docker-entrypoint.sh)
```bash
# Default: 4 workers
# Formula: (2 × CPU_count) + 1
# For 4-core CPU: 9 workers
# Modify docker-entrypoint.sh:
gunicorn --workers 9 ...
```
### **Nginx Worker Processes** (nginx.conf)
```nginx
# Default: auto (CPU count)
worker_processes auto;
# Or specify manually:
worker_processes 4;
```
### **Upload Timeout** (nginx.conf)
```nginx
# Default: 300s
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
```
---
## 🔐 Security Checklist
- [ ] Change admin password immediately
- [ ] Set strong `SECRET_KEY` environment variable
- [ ] Enable firewall rules (allow only ports 80, 443)
- [ ] Set up HTTPS with Let's Encrypt
- [ ] Configure regular database backups
- [ ] Review Nginx security headers
- [ ] Update Flask dependencies regularly
- [ ] Monitor container logs for errors
- [ ] Restrict admin panel access (IP whitelist optional)
- [ ] Enable Flask debug mode only in development
---
## 📞 Support & Documentation
- **Nginx Setup**: See `NGINX_SETUP_QUICK.md`
- **ProxyFix Configuration**: See `PROXY_FIX_SETUP.md`
- **Deployment Commands**: See `DEPLOYMENT_COMMANDS.md`
- **Issue Troubleshooting**: Check `old_code_documentation/`
---
## ✅ Deployment Checklist
- [ ] Docker & Docker Compose installed
- [ ] Running from `/srv/digiserver-v2` directory
- [ ] Environment variables configured (optional)
- [ ] Port 80/443 available
- [ ] Sufficient disk space (min 5GB)
- [ ] Sufficient RAM (min 2GB free)
- [ ] Network connectivity verified
- [ ] SSL certificates generated or obtained
- [ ] Admin credentials changed (production)
---
## 🚀 Next Steps After Deployment
1. **Access Web Interface**
- Login with admin credentials
- Change password immediately
2. **Configure Application**
- Set up players
- Upload content
- Configure groups & permissions
3. **Production Hardening**
- Enable Let's Encrypt HTTPS
- Configure firewall rules
- Set up database backups
- Monitor logs
4. **Optional Enhancements**
- Set up custom domain
- Configure email notifications
- Install optional dependencies (LibreOffice, etc.)
---
**Last Updated**: January 15, 2026

View File

@@ -1,120 +0,0 @@
# 🚀 DigiServer Deployment - Quick Reference Card
## Instant Deployment
```bash
cd /path/to/digiserver-v2
./deploy.sh
```
That's it! ✅
---
## 📖 Documentation Files
| File | Purpose | Size |
|------|---------|------|
| [DEPLOYMENT_INDEX.md](DEPLOYMENT_INDEX.md) | Navigation guide | 8.1 KB |
| [DEPLOYMENT_README.md](DEPLOYMENT_README.md) | Complete guide | 9.4 KB |
| [DOCKER_EXEC_COMMANDS.md](DOCKER_EXEC_COMMANDS.md) | Command reference | 7.6 KB |
| [DEPLOYMENT_COMMANDS.md](DEPLOYMENT_COMMANDS.md) | Detailed guide | 6.8 KB |
---
## 🔧 Executable Scripts
| Script | Purpose | Time |
|--------|---------|------|
| [deploy.sh](deploy.sh) | Fully automated | 2-3 min |
| [setup_https.sh](setup_https.sh) | Semi-automated | 3-5 min |
---
## 🎯 Common Commands
### Check Status
```bash
docker-compose ps
```
### View Logs
```bash
docker-compose logs -f digiserver-app
```
### Verify HTTPS Configuration
```bash
docker-compose exec -T digiserver-app python /app/https_manager.py status
```
### Access the Application
```
https://digiserver.sibiusb.harting.intra
https://10.76.152.164
https://digiserver
```
### Default Login
```
Username: admin
Password: admin123
```
---
## 🆘 Troubleshooting
| Issue | Solution |
|-------|----------|
| Containers won't start | `docker-compose logs` |
| Migration fails | Check DB connection, see docs |
| HTTPS errors | Clear Caddy cache: `docker volume rm digiserver-v2_caddy-*` |
| Port conflict | `lsof -i :443` or change in docker-compose.yml |
See [DEPLOYMENT_README.md#-troubleshooting](DEPLOYMENT_README.md#-troubleshooting) for full guide.
---
## 🌍 Deploy on Different PC
1. Copy project files
2. Install Docker & Docker Compose
3. Run `./deploy.sh`
Done! 🎉
---
## 🔑 Customize Deployment
```bash
HOSTNAME=myserver \
DOMAIN=myserver.internal \
IP_ADDRESS=192.168.1.100 \
EMAIL=admin@example.com \
./deploy.sh
```
---
## 📚 Need More Help?
- **First time?** → [DEPLOYMENT_README.md](DEPLOYMENT_README.md)
- **Need a command?** → [DOCKER_EXEC_COMMANDS.md](DOCKER_EXEC_COMMANDS.md)
- **Lost?** → [DEPLOYMENT_INDEX.md](DEPLOYMENT_INDEX.md)
- **Troubleshooting?** → [DEPLOYMENT_README.md#-troubleshooting](DEPLOYMENT_README.md#-troubleshooting)
---
## ✨ What You Get
✅ Web application with admin dashboard
✅ HTTPS with self-signed certificates
✅ User management system
✅ Player & content management
✅ Fully configured & ready to use
---
**Ready to deploy?** `./deploy.sh` 🚀

5
app/app.py Executable file → Normal file
View File

@@ -4,6 +4,7 @@ Modern Flask application with blueprint architecture
"""
import os
from flask import Flask, render_template
from werkzeug.middleware.proxy_fix import ProxyFix
from dotenv import load_dotenv
from app.config import DevelopmentConfig, ProductionConfig, TestingConfig
@@ -37,6 +38,10 @@ def create_app(config_name=None):
app.config.from_object(config)
# Apply ProxyFix middleware for reverse proxy (Nginx/Caddy)
# This ensures proper handling of X-Forwarded-* headers
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1)
# Initialize extensions
db.init_app(app)
bcrypt.init_app(app)

0
app/blueprints/__init__.py Executable file → Normal file
View File

View File

@@ -11,6 +11,7 @@ from app.extensions import db, bcrypt
from app.models import User, Player, Group, Content, ServerLog, Playlist, HTTPSConfig
from app.utils.logger import log_action
from app.utils.caddy_manager import CaddyConfigGenerator
from app.utils.nginx_config_reader import get_nginx_status
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
@@ -870,10 +871,14 @@ def https_config():
db.session.commit()
log_action('info', f'HTTPS status auto-corrected to enabled (detected from request)')
# Get Nginx configuration status
nginx_status = get_nginx_status()
return render_template('admin/https_config.html',
config=config,
is_https_active=is_https_active,
current_host=current_host)
current_host=current_host,
nginx_status=nginx_status)
except Exception as e:
log_action('error', f'Error loading HTTPS config page: {str(e)}')
flash('Error loading HTTPS configuration page.', 'danger')

0
app/blueprints/api.py Executable file → Normal file
View File

0
app/blueprints/auth.py Executable file → Normal file
View File

0
app/blueprints/content.py Executable file → Normal file
View File

0
app/blueprints/content_old.py Executable file → Normal file
View File

0
app/blueprints/groups.py Executable file → Normal file
View File

0
app/blueprints/main.py Executable file → Normal file
View File

0
app/blueprints/players.py Executable file → Normal file
View File

0
app/blueprints/playlist.py Executable file → Normal file
View File

5
app/config.py Executable file → Normal file
View File

@@ -29,6 +29,11 @@ class Config:
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
# Reverse proxy trust (for Nginx/Caddy with ProxyFix middleware)
# These are set by werkzeug.middleware.proxy_fix
TRUSTED_PROXIES = os.getenv('TRUSTED_PROXIES', '127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16')
PREFERRED_URL_SCHEME = os.getenv('PREFERRED_URL_SCHEME', 'https')
# Cache
SEND_FILE_MAX_AGE_DEFAULT = 300 # 5 minutes for static files

0
app/extensions.py Executable file → Normal file
View File

0
app/models/__init__.py Executable file → Normal file
View File

0
app/models/content.py Executable file → Normal file
View File

0
app/models/group.py Executable file → Normal file
View File

0
app/models/player.py Executable file → Normal file
View File

0
app/models/player_edit.py Executable file → Normal file
View File

0
app/models/player_feedback.py Executable file → Normal file
View File

0
app/models/player_user.py Executable file → Normal file
View File

0
app/models/playlist.py Executable file → Normal file
View File

0
app/models/server_log.py Executable file → Normal file
View File

0
app/models/user.py Executable file → Normal file
View File

0
app/static/icons/edit.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

0
app/static/icons/home.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 311 B

After

Width:  |  Height:  |  Size: 311 B

0
app/static/icons/info.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 329 B

After

Width:  |  Height:  |  Size: 329 B

0
app/static/icons/monitor.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

0
app/static/icons/moon.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 257 B

After

Width:  |  Height:  |  Size: 257 B

0
app/static/icons/playlist.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 259 B

0
app/static/icons/sun.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 651 B

After

Width:  |  Height:  |  Size: 651 B

0
app/static/icons/trash.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 334 B

0
app/static/icons/upload.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 345 B

After

Width:  |  Height:  |  Size: 345 B

0
app/static/icons/warning.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 396 B

0
app/static/uploads/.gitkeep Executable file → Normal file
View File

0
app/templates/admin/admin.html Executable file → Normal file
View File

0
app/templates/admin/customize_logos.html Executable file → Normal file
View File

0
app/templates/admin/dependencies.html Executable file → Normal file
View File

0
app/templates/admin/editing_users.html Executable file → Normal file
View File

View File

@@ -160,6 +160,95 @@
</form>
</div>
<!-- Nginx Status Card -->
<div class="card nginx-status-card">
<h2>🔧 Nginx Reverse Proxy Status</h2>
{% if nginx_status.available %}
<div class="nginx-status-content">
<div class="status-item">
<strong>Status:</strong>
<span class="badge badge-success">✅ Nginx Configured</span>
</div>
<div class="status-item">
<strong>Configuration Path:</strong>
<code>{{ nginx_status.path }}</code>
</div>
{% if nginx_status.ssl_enabled %}
<div class="status-item">
<strong>SSL/TLS:</strong>
<span class="badge badge-success">🔒 Enabled</span>
</div>
{% else %}
<div class="status-item">
<strong>SSL/TLS:</strong>
<span class="badge badge-warning">⚠️ Not Configured</span>
</div>
{% endif %}
{% if nginx_status.http_ports %}
<div class="status-item">
<strong>HTTP Ports:</strong>
<code>{{ nginx_status.http_ports|join(', ') }}</code>
</div>
{% endif %}
{% if nginx_status.https_ports %}
<div class="status-item">
<strong>HTTPS Ports:</strong>
<code>{{ nginx_status.https_ports|join(', ') }}</code>
</div>
{% endif %}
{% if nginx_status.server_names %}
<div class="status-item">
<strong>Server Names:</strong>
{% for name in nginx_status.server_names %}
<code>{{ name }}</code>{% if not loop.last %}<br>{% endif %}
{% endfor %}
</div>
{% endif %}
{% if nginx_status.upstream_servers %}
<div class="status-item">
<strong>Upstream Servers:</strong>
{% for server in nginx_status.upstream_servers %}
<code>{{ server }}</code>{% if not loop.last %}<br>{% endif %}
{% endfor %}
</div>
{% endif %}
{% if nginx_status.ssl_protocols %}
<div class="status-item">
<strong>SSL Protocols:</strong>
<code>{{ nginx_status.ssl_protocols|join(', ') }}</code>
</div>
{% endif %}
{% if nginx_status.client_max_body_size %}
<div class="status-item">
<strong>Max Body Size:</strong>
<code>{{ nginx_status.client_max_body_size }}</code>
</div>
{% endif %}
{% if nginx_status.gzip_enabled %}
<div class="status-item">
<strong>Gzip Compression:</strong>
<span class="badge badge-success">✅ Enabled</span>
</div>
{% endif %}
</div>
{% else %}
<div class="status-disabled">
<p>⚠️ <strong>Nginx configuration not accessible</strong></p>
<p>Error: {{ nginx_status.error|default('Unknown error') }}</p>
<p style="font-size: 12px; color: #666;">Path checked: {{ nginx_status.path }}</p>
</div>
{% endif %}
</div>
<!-- Information Section -->
<div class="card info-card">
<h2> Important Information</h2>
@@ -466,6 +555,45 @@
color: #0066cc;
}
.nginx-status-card {
background: linear-gradient(135deg, #f0f7ff 0%, #e7f3ff 100%);
border-left: 5px solid #0066cc;
margin-bottom: 30px;
}
.nginx-status-card h2 {
color: #0066cc;
margin-top: 0;
}
.nginx-status-content {
padding: 10px 0;
}
.status-item {
padding: 12px;
background: white;
border-radius: 4px;
margin-bottom: 10px;
border-left: 3px solid #0066cc;
font-size: 14px;
}
.status-item strong {
display: inline-block;
min-width: 150px;
color: #333;
}
.status-item code {
background: #f0f7ff;
padding: 4px 8px;
border-radius: 3px;
font-family: 'Courier New', monospace;
color: #0066cc;
word-break: break-all;
}
.info-sections {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

0
app/templates/admin/leftover_media.html Executable file → Normal file
View File

0
app/templates/admin/user_management.html Executable file → Normal file
View File

0
app/templates/auth/change_password.html Executable file → Normal file
View File

0
app/templates/auth/login.html Executable file → Normal file
View File

0
app/templates/auth/register.html Executable file → Normal file
View File

0
app/templates/base.html Executable file → Normal file
View File

0
app/templates/content/content_list.html Executable file → Normal file
View File

0
app/templates/content/content_list_new.html Executable file → Normal file
View File

0
app/templates/content/edit_content.html Executable file → Normal file
View File

0
app/templates/content/manage_playlist_content.html Executable file → Normal file
View File

0
app/templates/content/media_library.html Executable file → Normal file
View File

0
app/templates/content/upload_content.html Executable file → Normal file
View File

0
app/templates/content/upload_media.html Executable file → Normal file
View File

0
app/templates/dashboard.html Executable file → Normal file
View File

0
app/templates/errors/403.html Executable file → Normal file
View File

0
app/templates/errors/404.html Executable file → Normal file
View File

0
app/templates/errors/500.html Executable file → Normal file
View File

0
app/templates/groups/create_group.html Executable file → Normal file
View File

0
app/templates/groups/edit_group.html Executable file → Normal file
View File

0
app/templates/groups/group_fullscreen.html Executable file → Normal file
View File

0
app/templates/groups/groups_list.html Executable file → Normal file
View File

0
app/templates/groups/manage_group.html Executable file → Normal file
View File

0
app/templates/players/add_player.html Executable file → Normal file
View File

0
app/templates/players/edit_player.html Executable file → Normal file
View File

0
app/templates/players/edited_media.html Executable file → Normal file
View File

0
app/templates/players/manage_player.html Executable file → Normal file
View File

0
app/templates/players/player_fullscreen.html Executable file → Normal file
View File

0
app/templates/players/player_page.html Executable file → Normal file
View File

0
app/templates/players/players_list.html Executable file → Normal file
View File

0
app/templates/playlist/manage_playlist.html Executable file → Normal file
View File

0
app/utils/__init__.py Executable file → Normal file
View File

0
app/utils/group_player_management.py Executable file → Normal file
View File

0
app/utils/logger.py Executable file → Normal file
View File

View File

@@ -0,0 +1,120 @@
"""Nginx configuration reader utility."""
import os
import re
from typing import Dict, List, Optional, Any
class NginxConfigReader:
"""Read and parse Nginx configuration files."""
def __init__(self, config_path: str = '/etc/nginx/nginx.conf'):
"""Initialize Nginx config reader."""
self.config_path = config_path
self.config_content = None
self.is_available = os.path.exists(config_path)
if self.is_available:
try:
with open(config_path, 'r') as f:
self.config_content = f.read()
except Exception as e:
self.is_available = False
self.error = str(e)
def get_status(self) -> Dict[str, Any]:
"""Get Nginx configuration status."""
if not self.is_available:
return {
'available': False,
'error': 'Nginx configuration not found',
'path': self.config_path
}
return {
'available': True,
'path': self.config_path,
'file_exists': os.path.exists(self.config_path),
'ssl_enabled': self._check_ssl_enabled(),
'http_ports': self._extract_http_ports(),
'https_ports': self._extract_https_ports(),
'upstream_servers': self._extract_upstream_servers(),
'server_names': self._extract_server_names(),
'ssl_protocols': self._extract_ssl_protocols(),
'client_max_body_size': self._extract_client_max_body_size(),
'gzip_enabled': self._check_gzip_enabled(),
}
def _check_ssl_enabled(self) -> bool:
"""Check if SSL is enabled."""
if not self.config_content:
return False
return 'ssl_certificate' in self.config_content
def _extract_http_ports(self) -> List[int]:
"""Extract HTTP listening ports."""
if not self.config_content:
return []
pattern = r'listen\s+(\d+)'
matches = re.findall(pattern, self.config_content)
return sorted(list(set(int(p) for p in matches if int(p) < 1000)))
def _extract_https_ports(self) -> List[int]:
"""Extract HTTPS listening ports."""
if not self.config_content:
return []
pattern = r'listen\s+(\d+).*ssl'
matches = re.findall(pattern, self.config_content)
return sorted(list(set(int(p) for p in matches)))
def _extract_upstream_servers(self) -> List[str]:
"""Extract upstream servers."""
if not self.config_content:
return []
upstream_match = re.search(r'upstream\s+\w+\s*{([^}]+)}', self.config_content)
if upstream_match:
upstream_content = upstream_match.group(1)
servers = re.findall(r'server\s+([^\s;]+)', upstream_content)
return servers
return []
def _extract_server_names(self) -> List[str]:
"""Extract server names."""
if not self.config_content:
return []
pattern = r'server_name\s+([^;]+);'
matches = re.findall(pattern, self.config_content)
result = []
for match in matches:
names = match.strip().split()
result.extend(names)
return result
def _extract_ssl_protocols(self) -> List[str]:
"""Extract SSL protocols."""
if not self.config_content:
return []
pattern = r'ssl_protocols\s+([^;]+);'
match = re.search(pattern, self.config_content)
if match:
return match.group(1).strip().split()
return []
def _extract_client_max_body_size(self) -> Optional[str]:
"""Extract client max body size."""
if not self.config_content:
return None
pattern = r'client_max_body_size\s+([^;]+);'
match = re.search(pattern, self.config_content)
return match.group(1).strip() if match else None
def _check_gzip_enabled(self) -> bool:
"""Check if gzip is enabled."""
if not self.config_content:
return False
return bool(re.search(r'gzip\s+on\s*;', self.config_content))
def get_nginx_status() -> Dict[str, Any]:
"""Get Nginx configuration status."""
reader = NginxConfigReader()
return reader.get_status()

0
app/utils/pptx_converter.py Executable file → Normal file
View File

0
app/utils/uploads.py Executable file → Normal file
View File

View File

@@ -1,27 +0,0 @@
version: '3.8'
services:
digiserver:
build: .
container_name: digiserver-v2-http
ports:
- "80:5000" # Direct HTTP exposure on port 80
volumes:
- ./instance:/app/instance
- ./app/static/uploads:/app/app/static/uploads
environment:
- FLASK_ENV=production
- SECRET_KEY=${SECRET_KEY:-your-secret-key-change-this}
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123}
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/').read()"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Usage: docker-compose -f docker-compose.http.yml up -d
# Access at: http://localhost or http://your-server-ip
# Note: This is for development/testing only. Use docker-compose.yml for production HTTPS.

24
docker-compose.yml Executable file → Normal file
View File

@@ -26,19 +26,19 @@ services:
networks:
- digiserver-network
# Caddy reverse proxy with automatic HTTPS
caddy:
image: caddy:2-alpine
container_name: digiserver-caddy
# Nginx reverse proxy with HTTPS support
nginx:
image: nginx:alpine
container_name: digiserver-nginx
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3 support
- "2019:2019" # Caddy admin API
volumes:
- ./data/Caddyfile:/etc/caddy/Caddyfile:ro
- ./data/caddy-data:/data
- ./data/caddy-config:/config
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx-custom-domains.conf:/etc/nginx/conf.d/custom-domains.conf:rw
- ./data/nginx-ssl:/etc/nginx/ssl:ro
- ./data/nginx-logs:/var/log/nginx
- ./data/certbot:/var/www/certbot:ro # For Let's Encrypt ACME challenges
environment:
- DOMAIN=${DOMAIN:-localhost}
- EMAIL=${EMAIL:-admin@localhost}
@@ -46,6 +46,12 @@ services:
digiserver-app:
condition: service_started
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
- digiserver-network

0
fix_player_user_schema.py Executable file → Normal file
View File

30
generate_nginx_certs.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/bash
# Generate self-signed SSL certificates for Nginx
# Usage: ./generate_nginx_certs.sh [domain] [days]
DOMAIN=${1:-localhost}
DAYS=${2:-365}
CERT_DIR="./data/nginx-ssl"
echo "🔐 Generating self-signed SSL certificate for Nginx"
echo "Domain: $DOMAIN"
echo "Valid for: $DAYS days"
echo "Certificate directory: $CERT_DIR"
# Create directory if it doesnt exist
mkdir -p "$CERT_DIR"
# Generate private key and certificate
openssl req -x509 -nodes -days "$DAYS" \
-newkey rsa:2048 \
-keyout "$CERT_DIR/key.pem" \
-out "$CERT_DIR/cert.pem" \
-subj "/CN=$DOMAIN/O=DigiServer/C=US"
# Set proper permissions
chmod 644 "$CERT_DIR/cert.pem"
chmod 600 "$CERT_DIR/key.pem"
echo "✅ Certificates generated successfully!"
echo "Certificate: $CERT_DIR/cert.pem"
echo "Key: $CERT_DIR/key.pem"

View File

@@ -1,157 +0,0 @@
"""Utility script for managing HTTPS configuration from command line."""
import sys
import os
sys.path.insert(0, '/app')
from app.app import create_app
from app.models.https_config import HTTPSConfig
def show_help():
"""Display help information."""
print("""
HTTPS Configuration Management Utility
======================================
Usage:
python https_manager.py <command> [arguments]
Commands:
status Show current HTTPS configuration status
enable <hostname> <domain> <email> <ip> [port]
Enable HTTPS with specified settings
disable Disable HTTPS
show Show detailed configuration
Examples:
# Show current status
python https_manager.py status
# Enable HTTPS
python https_manager.py enable digiserver digiserver.sibiusb.harting.intra admin@example.com 10.76.152.164 443
# Disable HTTPS
python https_manager.py disable
# Show detailed config
python https_manager.py show
""")
def show_status():
"""Show current HTTPS status."""
app = create_app()
with app.app_context():
config = HTTPSConfig.get_config()
if config:
print("\n" + "=" * 50)
print("HTTPS Configuration Status")
print("=" * 50)
print(f"Status: {'✅ ENABLED' if config.https_enabled else '⚠️ DISABLED'}")
print(f"Hostname: {config.hostname or 'N/A'}")
print(f"Domain: {config.domain or 'N/A'}")
print(f"IP Address: {config.ip_address or 'N/A'}")
print(f"Port: {config.port}")
print(f"Updated: {config.updated_at.strftime('%Y-%m-%d %H:%M:%S')} by {config.updated_by or 'N/A'}")
if config.https_enabled:
print(f"\nAccess URL: https://{config.domain}")
print(f"Fallback: http://{config.ip_address}")
print("=" * 50 + "\n")
else:
print("\n⚠️ No HTTPS configuration found. Use 'enable' command to create one.\n")
def enable_https(hostname: str, domain: str, ip_address: str, email: str, port: str = '443'):
"""Enable HTTPS with specified settings."""
app = create_app()
with app.app_context():
try:
port_num = int(port)
config = HTTPSConfig.create_or_update(
https_enabled=True,
hostname=hostname,
domain=domain,
ip_address=ip_address,
email=email,
port=port_num,
updated_by='cli_admin'
)
print("\n" + "=" * 50)
print("✅ HTTPS Configuration Updated")
print("=" * 50)
print(f"Hostname: {hostname}")
print(f"Domain: {domain}")
print(f"Email: {email}")
print(f"IP Address: {ip_address}")
print(f"Port: {port_num}")
print(f"\nAccess URL: https://{domain}")
print(f"Fallback: http://{ip_address}")
print("=" * 50 + "\n")
except Exception as e:
print(f"\n❌ Error: {str(e)}\n")
sys.exit(1)
def disable_https():
"""Disable HTTPS."""
app = create_app()
with app.app_context():
try:
config = HTTPSConfig.create_or_update(
https_enabled=False,
updated_by='cli_admin'
)
print("\n" + "=" * 50)
print("⚠️ HTTPS Disabled")
print("=" * 50)
print("The application is now running on HTTP only (port 80)")
print("=" * 50 + "\n")
except Exception as e:
print(f"\n❌ Error: {str(e)}\n")
sys.exit(1)
def show_config():
"""Show detailed configuration."""
app = create_app()
with app.app_context():
config = HTTPSConfig.get_config()
if config:
print("\n" + "=" * 50)
print("Detailed HTTPS Configuration")
print("=" * 50)
for key, value in config.to_dict().items():
print(f"{key:.<30} {value}")
print("=" * 50 + "\n")
else:
print("\n⚠️ No HTTPS configuration found.\n")
def main():
"""Main entry point."""
if len(sys.argv) < 2:
show_help()
sys.exit(1)
command = sys.argv[1].lower()
if command == 'status':
show_status()
elif command == 'enable':
if len(sys.argv) < 6:
print("\nError: 'enable' requires: hostname domain email ip_address [port]\n")
show_help()
sys.exit(1)
hostname = sys.argv[2]
domain = sys.argv[3]
email = sys.argv[4]
ip_address = sys.argv[5]
port = sys.argv[6] if len(sys.argv) > 6 else '443'
enable_https(hostname, domain, ip_address, email, port)
elif command == 'disable':
disable_https()
elif command == 'show':
show_config()
elif command in ['help', '-h', '--help']:
show_help()
else:
print(f"\nUnknown command: {command}\n")
show_help()
sys.exit(1)
if __name__ == '__main__':
main()

View File

@@ -4,7 +4,7 @@
set -e
echo "🔧 Initializing data folder..."
mkdir -p data/{app,instance,uploads,caddy-data,caddy-config}
mkdir -p data/{app,instance,uploads}
echo "📁 Copying app folder..."
rm -rf data/app
@@ -16,14 +16,10 @@ rm -rf data/migrations
cp -r migrations data/
echo "🔧 Copying utility scripts..."
cp https_manager.py player_auth_module.py fix_player_user_schema.py data/
echo "📄 Copying Caddyfile..."
cp Caddyfile data/
cp fix_player_user_schema.py data/
echo "🔐 Setting permissions..."
chmod 755 data/{app,instance,uploads,caddy-data,caddy-config}
chmod 644 data/Caddyfile
chmod 755 data/{app,instance,uploads}
chmod -R 755 data/app/
find data/app -type f \( -name "*.py" -o -name "*.html" -o -name "*.css" -o -name "*.js" \) -exec chmod 644 {} \;
chmod 777 data/instance data/uploads

0
migrations/add_player_user_table.py Executable file → Normal file
View File

0
migrations/migrate_player_user_global.py Executable file → Normal file
View File

21
nginx-custom-domains.conf Normal file
View File

@@ -0,0 +1,21 @@
# Nginx configuration for custom HTTPS domains
# This file will be dynamically generated based on HTTPSConfig database entries
# Include this in your nginx.conf with: include /etc/nginx/conf.d/custom-domains.conf;
# Example entry for custom domain:
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name digiserver.example.com;
#
# ssl_certificate /etc/nginx/ssl/custom/cert.pem;
# ssl_certificate_key /etc/nginx/ssl/custom/key.pem;
#
# location / {
# proxy_pass http://digiserver_app;
# 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;
# }
# }

117
nginx.conf Normal file
View File

@@ -0,0 +1,117 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 2048M;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml;
# Upstream to Flask application
upstream digiserver_app {
server digiserver-app:5000;
keepalive 32;
}
# HTTP Server - redirect to HTTPS
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# Allow ACME challenges for Let's Encrypt
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Redirect HTTP to HTTPS for non-ACME requests
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS Server (with self-signed cert by default)
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name localhost;
# SSL certificate paths (will be volume-mounted)
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# SSL Configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# Proxy settings
location / {
proxy_pass http://digiserver_app;
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_set_header X-Forwarded-Host $server_name;
# Timeouts for large uploads
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
# Buffering
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
# Static files caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://digiserver_app;
proxy_cache_valid 200 60d;
expires 60d;
add_header Cache-Control "public, immutable";
}
}
# Additional server blocks for custom domains can be included here
include /etc/nginx/conf.d/*.conf;
}

0
old_code_documentation/.env.example Executable file → Normal file
View File

0
old_code_documentation/DOCKER.md Executable file → Normal file
View File

0
old_code_documentation/HTTPS_SETUP.md Executable file → Normal file
View File

View File

View File

@@ -0,0 +1,84 @@
# Quick Start: Nginx Setup for DigiServer v2
## Pre-requisites
- SSL certificates in `./data/nginx-ssl/cert.pem` and `./data/nginx-ssl/key.pem`
- Docker and Docker Compose installed
- Port 80 and 443 available
## Quick Setup (3 steps)
### 1. Generate Self-Signed Certificates
```bash
./generate_nginx_certs.sh localhost 365
```
### 2. Update Nginx Configuration
- Edit `nginx.conf` to set your domain:
```nginx
server_name localhost; # Change to your domain
```
### 3. Start Docker Compose
```bash
docker-compose up -d
```
## Verification
### Check if Nginx is running
```bash
docker ps | grep nginx
```
### Test HTTP → HTTPS redirect
```bash
curl -L http://localhost
```
### Test HTTPS (with self-signed cert)
```bash
curl -k https://localhost
```
### View logs
```bash
docker logs digiserver-nginx
docker exec digiserver-nginx tail -f /var/log/nginx/access.log
```
## Using Production Certificates
### Option A: Let's Encrypt (Free)
1. Install certbot: `apt-get install certbot`
2. Generate cert: `certbot certonly --standalone -d your-domain.com`
3. Copy cert: `cp /etc/letsencrypt/live/your-domain.com/fullchain.pem ./data/nginx-ssl/cert.pem`
4. Copy key: `cp /etc/letsencrypt/live/your-domain.com/privkey.pem ./data/nginx-ssl/key.pem`
5. Fix permissions: `sudo chown 101:101 ./data/nginx-ssl/*`
6. Reload: `docker exec digiserver-nginx nginx -s reload`
### Option B: Commercial Certificate
1. Place your certificate files in `./data/nginx-ssl/cert.pem` and `./data/nginx-ssl/key.pem`
2. Fix permissions: `sudo chown 101:101 ./data/nginx-ssl/*`
3. Reload: `docker exec digiserver-nginx nginx -s reload`
## Troubleshooting
| Issue | Solution |
|-------|----------|
| Port 80/443 in use | `sudo netstat -tlnp \| grep :80` or `:443` |
| Certificate permission denied | `sudo chown 101:101 ./data/nginx-ssl/*` |
| Nginx won't start | `docker logs digiserver-nginx` |
| Connection refused | Check firewall: `sudo ufw allow 80/tcp && sudo ufw allow 443/tcp` |
## File Locations
- Main config: `./nginx.conf`
- SSL certs: `./data/nginx-ssl/`
- Logs: `./data/nginx-logs/`
- Custom domains: `./nginx-custom-domains.conf` (auto-generated)
## Next: Production Setup
1. Update `.env` with your DOMAIN and EMAIL
2. Configure HTTPS settings in admin panel
3. Run: `python nginx_manager.py generate`
4. Test: `docker exec digiserver-nginx nginx -t`
5. Reload: `docker exec digiserver-nginx nginx -s reload`

0
old_code_documentation/OPTIONAL_DEPENDENCIES.md Executable file → Normal file
View File

0
old_code_documentation/PLAYER_EDIT_MEDIA_API.md Executable file → Normal file
View File

Some files were not shown because too many files have changed in this diff Show More