April 22, 2026, 12:52 p.m.
This Website
Audio
*AI-generated content
Technical Architecture: caiodonalisio.com
This document describes the technical architecture of caiodonalisio.com, covering everything from network infrastructure to the CI/CD pipeline.
Overview
Internet
↓
Cloudflare Tunnel
↓
NGINX → static files
↓
Django/Gunicorn
↓
PostgreSQL ←→ Redis
1. Network Infrastructure
Hardware
The site runs on a single-node Kubernetes cluster hosted on a local mini-PC. The network topology is as follows:
Internet
↓
Mikrotik Router (RouterOS)
• Inter-VLAN routing
• Firewall per VLAN
↓ trunk port (tagged)
Managed Switch (VLAN-aware)
• VLAN 10: Home
• VLAN 20: Servers
• VLAN 30: IoT
↓ access port (VLAN 20)
Mini-PC
• Ubuntu Server
• K3s single-node
VLAN Isolation
The server resides in a dedicated VLAN (VLAN 20), isolated from the rest of the home network. The Mikrotik manages:
- Inter-VLAN firewall: the server VLAN has no access to the home network
- Management access: only specific devices from the main VLAN can access SSH
- Internet egress: permitted for the Cloudflare Tunnel to establish an outbound connection
This segmentation ensures that even in the event of server compromise, the attacker would have no lateral access to home devices.
Internet Exposure
There is no port forwarding on the router. All incoming traffic passes through the Cloudflare Tunnel, which maintains a persistent outbound connection to Cloudflare's edge. This eliminates the need for:
- A static public IP
- Open firewall ports
- Manual TLS certificate management
2. Kubernetes (K3s)
Cluster
K3s single-node with the following resources deployed in the caiodonalisio namespace:
| Resource | Replicas | Role | |----------|----------|------| | Django/Gunicorn | 2 | Web application | | NGINX | 1 | Reverse proxy + static files | | PostgreSQL | 1 | Database | | Redis | 1 | Cache + session store | | Cloudflared | 1 | Tunnel daemon |
Storage
Uses K3s's local-path provisioner:
- staticfiles-pvc (2Gi): collected static files
- media-pvc (2Gi): uploads and media files
- postgres-pvc (10Gi): PostgreSQL data
Health Checks and Resilience
The Django deployment configures:
```yaml readinessProbe: httpGet: path: /health/ port: 3334 initialDelaySeconds: 60 periodSeconds: 15 failureThreshold: 3
livenessProbe: httpGet: path: /health/ port: 3334 initialDelaySeconds: 90 periodSeconds: 30 failureThreshold: 5 ```
Combined with a PodDisruptionBudget (minAvailable: 1) and rolling updates (maxUnavailable: 0, maxSurge: 1), this ensures zero-downtime during deploys.
Graceful Shutdown
A pre-stop hook with a 15-second sleep allows in-flight connections to drain before SIGTERM:
yaml
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 15"]
3. Cloudflare Tunnel
The cloudflared daemon runs as a deployment in the cluster, configured via ConfigMap:
yaml
tunnel: <tunnel-id>
credentials-file: /etc/cloudflared/creds/credentials.json
ingress:
- hostname: caiodonalisio.com
service: http://nginx-svc:80
- hostname: www.caiodonalisio.com
service: http://nginx-svc:80
- service: http_status:404
Relevant settings:
- hostNetwork: true: avoids intermittent 502 issues on single-node clusters
- dnsPolicy: ClusterFirstWithHostNet: preserves internal service resolution
- protocol: http2: multiplexed connection to the edge
4. Application Stack
Backend
| Component | Version | Configuration | |-----------|---------|---------------| | Python | 3.12 | - | | Django | 5.1 | Modular settings (dev/prod/test) | | Gunicorn | - | 4 workers, port 3334 | | Celery | 5.4 | Configured, workers disabled |
Database and Cache
| Component | Version | Usage | |-----------|---------|-------| | PostgreSQL | 16.4 | Primary persistence | | Redis | 7.4.1 | Sessions, cache, Celery broker |
Django Structure
``` website/ # Project settings ├── settings/ │ ├── base.py │ ├── production.py │ └── development.py ├── urls.py # Routes + /health/ endpoint └── celery.py
blog/ # Main app ├── models.py # Post, PostFile, PostBook ├── views.py # Markdown rendering └── storage.py # Custom OverwriteStorage
accounts/ # Authentication └── models.py # CustomUser
pages/ # Static pages ```
Serving
- NGINX: reverse proxy, serves
/static/and/media/directly - WhiteNoise: fallback for static files with CompressedManifestStaticFilesStorage
- Gunicorn: WSGI server for dynamic requests
5. CI/CD Pipeline
GitHub Actions
The build_release.yml workflow runs on push to main:
Test (pytest)
↓
Build (docker)
↓
Semantic Release
↓
├→ Trivy Scan
├→ Push to Docker Hub
└→ Update K8s Manifests
↓
Argo CD Auto-Sync
Semantic Versioning
Versions are generated automatically via python-semantic-release:
fix:→ PATCHfeat:→ MINORBREAKING CHANGE:→ MAJOR
GitOps with Argo CD
Argo CD monitors the k8s/ directory and applies changes automatically:
yaml
syncPolicy:
automated:
prune: true
selfHeal: true
retry:
limit: 5
backoff:
duration: 5s
maxDuration: 3m
factor: 2
The update-k8s-manifest GitHub Actions job updates the image tag in k8s/website.yml, triggering an Argo CD sync.
6. Containerization
Multi-stage Build
```dockerfile
Stage 1: Builder
FROM python:3.12.4-slim AS builder COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ RUN uv pip compile requirements.txt -o requirements.lock RUN uv pip sync requirements.lock
Stage 2: Runtime
FROM python:3.12.4-slim COPY --from=builder /.venv /.venv COPY . /usr/src/ EXPOSE 3334 CMD ["./entrypoint.sh"] ```
The use of uv (a Rust-based package manager) significantly speeds up dependency builds.
Entrypoint
entrypoint.sh runs on container startup:
- Waits for PostgreSQL (healthcheck via netcat)
collectstaticmigrate- Media file sync
- Starts Gunicorn
7. Full Request Flow
INTERNET
↓
CLOUDFLARE EDGE
(DDoS, SSL)
↓ tunnel
MIKROTIK → VLAN 20 → Mini-PC
↓
K3s CLUSTER
↓
cloudflared (hostNetwork)
↓
nginx-svc
• /static/ → staticfiles-pvc
• /media/ → media-pvc
• /* → website-svc
↓
website-svc (2 replicas)
Django + Gunicorn :3334
↓
postgres-svc ←→ redis-svc
8. Security Considerations
| Layer | Measure | |-------|---------| | Network | VLAN isolation, no port forwarding | | Edge | Cloudflare DDoS protection, WAF | | Transport | TLS managed by Cloudflare | | Cluster | Network policies, secrets for credentials | | Application | CSRF, secure cookies, ALLOWED_HOSTS | | CI/CD | Trivy scan for image vulnerabilities |
Last updated: January 2026