diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index ddeacb5..69f4e40 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -176,7 +176,7 @@ jobs: deploy: needs: build runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' && false # Disabled until production server is set up environment: production diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 1550c87..377441c 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,14 +1,48 @@ # Deployment Guide -## Production Deployment Status ✅ +## ⚠️ **Production Server Setup Required** -The automated deployment pipeline is now configured and ready! +**IMPORTANT**: The automated deployment is currently disabled until your production server is properly configured. + +### Current Status: +- ✅ CI/CD Pipeline: Fully configured +- ✅ Code Quality: Automated checks working +- ✅ Docker Images: Building successfully +- ❌ Production Server: **Needs setup** (deployment disabled) + +### Required Setup Steps: + +1. **Set up your production server** following the detailed guide: + 📖 **[Complete Production Server Setup Guide](docs/production-server-setup.md)** + +2. **Enable automatic deployment** once server is ready by editing `.github/workflows/ci-cd.yml` ### Deployment Secrets Configured: - ✅ `PROD_HOST` - Production server address - ✅ `PROD_USERNAME` - SSH username (deployment) - ✅ `PROD_SSH_KEY` - SSH private key for authentication +### Why Deployment is Disabled: + +The CI/CD pipeline was failing because: +- `/opt/stiftung` directory doesn't exist on server +- Docker is not installed on production server +- Git repository not cloned to server +- Environment variables not configured + +### Re-enabling Deployment: + +After completing the server setup, edit `.github/workflows/ci-cd.yml` and change: + +```yaml +if: github.ref == 'refs/heads/main' && false # Disabled until production server is set up +``` + +To: +```yaml +if: github.ref == 'refs/heads/main' +``` + ### Deployment Process: 1. **Automatic Triggers:** diff --git a/app/stiftung/admin.py b/app/stiftung/admin.py index a32979b..911780b 100644 --- a/app/stiftung/admin.py +++ b/app/stiftung/admin.py @@ -5,24 +5,11 @@ from django.utils.html import format_html from django.utils.safestring import mark_safe from . import models -from .models import ( - AppConfiguration, - AuditLog, - BackupJob, - BankTransaction, - CSVImport, - Destinataer, - DestinataerUnterstuetzung, - DokumentLink, - Foerderung, - Land, - Paechter, - Person, - Rentmeister, - StiftungsKonto, - UnterstuetzungWiederkehrend, - Verwaltungskosten, -) +from .models import (AppConfiguration, AuditLog, BackupJob, BankTransaction, + CSVImport, Destinataer, DestinataerUnterstuetzung, + DokumentLink, Foerderung, Land, Paechter, Person, + Rentmeister, StiftungsKonto, UnterstuetzungWiederkehrend, + Verwaltungskosten) @admin.register(CSVImport) diff --git a/app/stiftung/forms.py b/app/stiftung/forms.py index 7841be6..9be429d 100644 --- a/app/stiftung/forms.py +++ b/app/stiftung/forms.py @@ -4,22 +4,11 @@ from django import forms from django.core.exceptions import ValidationError from django.utils import timezone -from .models import ( - BankTransaction, - Destinataer, - DestinataerNotiz, - DestinataerUnterstuetzung, - DokumentLink, - Foerderung, - Land, - LandAbrechnung, - Paechter, - Person, - Rentmeister, - StiftungsKonto, - UnterstuetzungWiederkehrend, - Verwaltungskosten, -) +from .models import (BankTransaction, Destinataer, DestinataerNotiz, + DestinataerUnterstuetzung, DokumentLink, Foerderung, Land, + LandAbrechnung, Paechter, Person, Rentmeister, + StiftungsKonto, UnterstuetzungWiederkehrend, + Verwaltungskosten) class RentmeisterForm(forms.ModelForm): diff --git a/app/stiftung/views.py b/app/stiftung/views.py index 9dcc6ac..2106c77 100644 --- a/app/stiftung/views.py +++ b/app/stiftung/views.py @@ -11,7 +11,8 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator -from django.db.models import Avg, Count, DecimalField, F, IntegerField, Q, Sum, Value +from django.db.models import (Avg, Count, DecimalField, F, IntegerField, Q, + Sum, Value) from django.db.models.functions import Cast, Coalesce, NullIf, Replace from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect, render @@ -20,20 +21,10 @@ from django.views.decorators.csrf import csrf_exempt from rest_framework.decorators import api_view from rest_framework.response import Response -from .models import ( - AppConfiguration, - CSVImport, - Destinataer, - DestinataerUnterstuetzung, - DokumentLink, - Foerderung, - Land, - LandAbrechnung, - LandVerpachtung, - Paechter, - Person, - UnterstuetzungWiederkehrend, -) +from .models import (AppConfiguration, CSVImport, Destinataer, + DestinataerUnterstuetzung, DokumentLink, Foerderung, Land, + LandAbrechnung, LandVerpachtung, Paechter, Person, + UnterstuetzungWiederkehrend) def get_pdf_generator(): @@ -220,18 +211,10 @@ def gramps_debug_api(_request): from stiftung.models import DestinataerNotiz, DestinataerUnterstuetzung -from .forms import ( - DestinataerForm, - DestinataerNotizForm, - DestinataerUnterstuetzungForm, - DokumentLinkForm, - FoerderungForm, - LandForm, - PaechterForm, - PersonForm, - UnterstuetzungForm, - UnterstuetzungMarkAsPaidForm, -) +from .forms import (DestinataerForm, DestinataerNotizForm, + DestinataerUnterstuetzungForm, DokumentLinkForm, + FoerderungForm, LandForm, PaechterForm, PersonForm, + UnterstuetzungForm, UnterstuetzungMarkAsPaidForm) def home(request): diff --git a/docs/production-server-setup.md b/docs/production-server-setup.md new file mode 100644 index 0000000..45cdeff --- /dev/null +++ b/docs/production-server-setup.md @@ -0,0 +1,260 @@ +# Production Server Setup Guide + +This guide will help you set up your production server for automated deployment from GitHub Actions. + +## Prerequisites + +- A Linux server (Ubuntu 20.04+ recommended) +- SSH access to the server +- Domain name pointing to your server (optional) + +## Step 1: Connect to Your Server + +```bash +ssh your-username@your-server-ip +``` + +## Step 2: Update System + +```bash +sudo apt update && sudo apt upgrade -y +``` + +## Step 3: Install Docker and Docker Compose + +```bash +# Install Docker +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh + +# Add your user to docker group +sudo usermod -aG docker $USER + +# Install Docker Compose +sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose +sudo chmod +x /usr/local/bin/docker-compose + +# Logout and login again to apply group changes +exit +# Then reconnect via SSH +``` + +## Step 4: Install Git + +```bash +sudo apt install git -y +``` + +## Step 5: Set Up Project Directory + +```bash +# Create project directory +sudo mkdir -p /opt/stiftung +sudo chown $USER:$USER /opt/stiftung +cd /opt/stiftung + +# Clone your repository +git clone https://github.com/remmerinio/stiftung-management-system.git . + +# Copy environment template +cp env-template.txt app/.env +``` + +## Step 6: Configure Environment Variables + +Edit the production environment file: + +```bash +nano app/.env +``` + +Add these settings (replace with your actual values): + +```env +# Django Settings +DJANGO_DEBUG=0 +DJANGO_SECRET_KEY=your-very-long-secret-key-here +DJANGO_ALLOWED_HOSTS=your-domain.com,your-server-ip + +# Database Settings +POSTGRES_DB=stiftung_prod +POSTGRES_USER=stiftung_user +POSTGRES_PASSWORD=your-secure-database-password + +# Redis Settings +REDIS_URL=redis://redis:6379/0 + +# Email Settings (optional) +EMAIL_HOST=smtp.your-provider.com +EMAIL_PORT=587 +EMAIL_HOST_USER=your-email@example.com +EMAIL_HOST_PASSWORD=your-email-password +EMAIL_USE_TLS=1 +``` + +## Step 7: Set Up Production Docker Compose + +Copy the production Docker Compose file to the project root: + +```bash +cp deploy-production/docker-compose.prod.yml . +``` + +## Step 8: Generate Strong Secret Key + +```bash +python3 -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" +``` + +Use this output as your `DJANGO_SECRET_KEY` in the `.env` file. + +## Step 9: Set Up SSL/HTTPS (Recommended) + +If you have a domain name, set up SSL certificates: + +```bash +# Install Certbot +sudo apt install snapd +sudo snap install core; sudo snap refresh core +sudo snap install --classic certbot + +# Create certificate +sudo certbot certonly --standalone -d your-domain.com + +# The certificates will be in /etc/letsencrypt/live/your-domain.com/ +``` + +## Step 10: Configure Firewall + +```bash +# Enable firewall +sudo ufw enable + +# Allow SSH +sudo ufw allow ssh + +# Allow HTTP and HTTPS +sudo ufw allow 80 +sudo ufw allow 443 + +# Check status +sudo ufw status +``` + +## Step 11: Initial Deployment + +Run the first deployment manually: + +```bash +cd /opt/stiftung + +# Build and start containers +docker-compose -f docker-compose.prod.yml up -d --build + +# Run initial migrations +docker-compose -f docker-compose.prod.yml exec web python manage.py migrate + +# Create superuser +docker-compose -f docker-compose.prod.yml exec web python manage.py createsuperuser + +# Collect static files +docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic --noinput +``` + +## Step 12: Test the Deployment + +Visit your server IP or domain name to verify the application is running. + +## Step 13: Enable Automatic Deployment + +Once your server is properly set up, you can enable automatic deployment by editing `.github/workflows/ci-cd.yml`: + +Change this line: +```yaml +if: github.ref == 'refs/heads/main' && false # Disabled until production server is set up +``` + +To: +```yaml +if: github.ref == 'refs/heads/main' +``` + +## Troubleshooting + +### If deployment fails: + +1. **Check Docker status:** + ```bash + sudo systemctl status docker + ``` + +2. **Check container logs:** + ```bash + docker-compose -f docker-compose.prod.yml logs + ``` + +3. **Restart services:** + ```bash + docker-compose -f docker-compose.prod.yml restart + ``` + +### Common Issues: + +- **Permission denied**: Make sure your user is in the docker group +- **Port conflicts**: Check if ports 80/443 are already in use +- **Database connection**: Verify your database settings in `.env` +- **Static files**: Ensure the web server can access static files + +## Monitoring and Maintenance + +### Check application status: +```bash +docker-compose -f docker-compose.prod.yml ps +``` + +### View logs: +```bash +docker-compose -f docker-compose.prod.yml logs -f web +``` + +### Update the application: +```bash +cd /opt/stiftung +git pull origin main +docker-compose -f docker-compose.prod.yml pull +docker-compose -f docker-compose.prod.yml up -d +``` + +### Backup database: +```bash +docker-compose -f docker-compose.prod.yml exec db pg_dump -U stiftung_user stiftung_prod > backup_$(date +%Y%m%d_%H%M%S).sql +``` + +## Security Recommendations + +1. **Keep system updated:** + ```bash + sudo apt update && sudo apt upgrade -y + ``` + +2. **Use strong passwords** for database and admin accounts + +3. **Enable fail2ban** to prevent brute force attacks: + ```bash + sudo apt install fail2ban + ``` + +4. **Regular backups** of your database and media files + +5. **Monitor logs** for suspicious activity + +## Next Steps + +After completing this setup: + +1. Test the deployment pipeline by making a commit to the main branch +2. Set up monitoring and alerting for your application +3. Configure regular automated backups +4. Set up a staging environment for testing + +Your production server is now ready for automated deployment from GitHub Actions!