Skip to content

Deployment Phase

Objective: Deploy the application to a production-ready server in this case (Hetzner) for now, with proper configuration, security, and monitoring in place.


1. Deployment Preparation

1.1 Tools

Tool Purpose
Docker Build and run application containers.
Hetzner Console Manage server infrastructure.
Nginx Reverse proxy for handling HTTP/HTTPS traffic.
Certbot Generate and renew SSL certificates.

1.2 Checklist

  • Confirm Hetzner credentials and IP address.
  • Verify that the database credentials are available.
  • Ensure Docker Hub account access.
  • Check that the production .env file is ready with correct values.

2. Docker [Local]

2.1 Build the Docker Image

docker build -t app/app_backend:0.0.1 --build-arg REQUIREMENTS_FILE=prod.txt .

2.2 Test Docker

docker run -p 8000:80 app/app_backend:0.0.1

2.3 Login to Docker Hub

docker login -u app

2.4 Tag the Docker Image

docker tag app/app_backend:0.0.1 app/app_backend:0.0.1

2.5 Push the Docker Image

docker push app/app_backend:0.0.1

3. Database Setup

3.1 Connect to Hetzner Managed Database

Retrieve credentials from Hetzner and log in:

psql -d app_db -U app -h some_host.your-server.de

3.2 Verify Database

\dt

4. Server Preparation

4.1 Connect to the Server

ssh root@<ip>

4.2 Install Required Packages

apt update
apt install -y docker.io nginx certbot python3-certbot-nginx
systemctl enable --now docker

4.3 Pull Docker Image

docker pull app/app_backend:0.0.1

4.4 Set Up Environment Variables

Create /app/.env with the following content:

DATABASE_NAME=app_db
DATABASE_USER=app
DATABASE_PASSWORD=<password>
DATABASE_HOST=some_host.your-server.de
DATABASE_PORT=5432
DJANGO_SECRET_KEY=<your_secret_key>
DEBUG=False


5. Docker Deployment [Server]

5.1 Run the Docker Container

docker run -d --name app_backend \
  --env-file /app/.env \
  -v /app/staticfiles:/app/staticfiles \
  -p 8000:80 \
  app/app_backend:0.0.1

5.2 Verify the Docker Container

docker ps
docker logs <container_id>

5.3 Check Database Migrations

psql -d app_db -U app -h some_host.your-server.de
Run migrations if needed:
python manage.py migrate


6. Static Files Setup [Server]

6.1 Collect Static Files

docker exec -it app_backend bash
python manage.py collectstatic --noinput

6.2 Verify Static Files

ls /app/staticfiles

7. Nginx Configuration

7.1 Configure Nginx

Update /etc/nginx/sites-available/default:

server {
    listen 80;
    server_name api.app.no;

    location /static/ {
        alias /app/staticfiles/;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

7.2 Test and Restart Nginx

nginx -t
systemctl restart nginx

7.3 Verify Static Files Access

curl http://api.app.no/static/admin/css/base.css

8. SSL Setup

8.1 Install Certbot

apt install certbot python3-certbot-nginx

8.2 Obtain SSL Certificate

certbot --nginx -d api.app.no

8.3 Test SSL Certificate

curl https://api.app.no

8.4 Enable Auto Renewal

certbot renew --dry-run

9. DNS Configuration

9.1 Add A Record

Type Host Value TTL
A @ ip 192.0.0.1 1 Hour

9.2 Add CNAME Record (Optional)

Type Host Value TTL
CNAME www api.app.no 1 Hour

10. Verification and Testing

10.1 Verify Application

  • Access the application via https://api.app.no.
  • Verify API endpoints.
  • Confirm the database is populated correctly.

10.2 Test Static Files

curl https://api.app.no/static/admin/css/base.css

11. Rollback (If Required)

TODO separate document

11.1 Stop the Current Container

docker stop app_backend
docker rm app_backend

11.2 Deploy the Previous Version

docker pull app/app_backend:<previous_version>
docker run -d --name app_backend \
  --env-file /app/.env \
  -v /app/staticfiles:/app/staticfiles \
  -p 8000:80 \
  app/app_backend:<previous_version>

12. Post-Deployment Monitoring

12.1 Monitoring

Tool Purpose
Prometheus Real-time application and server monitoring.
Grafana Visualization of metrics from Prometheus.
ELK Stack Centralized log aggregation (Elasticsearch, Logstash, Kibana).

12.2 Set Up Metrics and Alerts

  • Track critical metrics:
  • CPU and memory usage.
  • API response times.
  • Error rates (4xx/5xx HTTP status codes).
  • Configure alerts for critical thresholds using Prometheus or another monitoring tool.

12.3 Monitor Logs

  • Use ELK Stack or a similar solution to centralize logs:
    apt install filebeat
    filebeat setup
    

13 Firewall Configuration

TODO, separate docs as well as cloudflare config and setup todo

  • Restrict server access:
    ufw allow OpenSSH
    ufw allow 'Nginx Full'
    ufw enable
    

13.3 Secure Environment Variables

  • Move .env file out of the application directory.
  • Set permissions to restrict access:
    chmod 600 /path/to/.env
    chown app_user:app_user /path/to/.env
    

14 CI/CD GitHub Actions

Step Description
Build Docker image Automate Docker builds on new code pushes.
Push to Docker Hub Automatically push the latest images to Docker Hub.
Deploy to Hetzner SSH into Hetzner and pull the new Docker image.

15. Backup Strategy

15.1 Database Backup

Schedule automatic backups using pg_dump:

pg_dump -U app -h some_host.your-server.de app_db > app_db_$(date +%F).sql

15.2 Docker Image Backup

Tag Docker images with a version before any changes:

docker tag app/app_backend:latest app/app_backend:backup-$(date +%F)
  ```

### 15.3 Environment File Backup
Encrypt sensitive backups using GPG:

```bash
gpg --encrypt --recipient "email@example.com" /path/to/.env

16. E2E Testing After Deployment

Test Type Steps
API Tests Verify all endpoints return expected responses.
UI Tests Check user flows in the frontend (if applicable).
Load Tests Simulate high traffic to test application limits.

17. Regular Maintenance

Task Frequency
Rotate API keys Monthly
Backup Verification Weekly
Security Updates As Needed
Log Review Daily

18. Rollback Plan

TODO separate document