Quick Version Recap
Version 1
The first version of mykytaso.com was a simple webpage hosted on a Raspberry Pi 4 and exposed from my home network via a Cloudflare Tunnel.

Version 2
The second iteration was a Django application deployed on AWS, where I implemented a block-based editor for creating posts (similar to Notion blocks).
GitHub RepoVersion 3 (current)
For the third version, I fully rewrote the codebase. It's still built with Django, but now includes many new features and is deployed on Hetzner instead of AWS.
GitHub Repo
Tech Stack
- Backend: Django 6.0+ · Python 3.12+ · PostgreSQL
- Frontend: HTML · CSS + BEM · HTMX · Vanilla JS · Django Templates
- Infrastructure: Docker · Gunicorn + Uvicorn · Nginx · Hetzner · Sentry
- Tools: GitHub Actions CI/CD · uv · Ruff · Mistune + Pygments · Mailgun API
CI/CD
GitHub Actions runs a two-stage pipeline (build and deploy) on pushes to main.
Build job
- Builds the Docker image.
- Tags it with
latestand$GITHUB_SHA. - Pushes the image to
ghcr.io.
Deploy job
- Generates
.envfrom GitHub secrets. - Uploads config files to the production server via SCP.
- SSHes into the server to pull the image and run
docker compose up -d.

Database Design
- UUID primary keys.
- Soft deletes for users to preserve data integrity.
- Database-level constraints to prevent duplicate likes.
- Indexes on frequently queried fields.
- Composite indexes for multi-field lookups.
- Cached rendered HTML to speed up Markdown rendering.
PostgreSQL Backup System
I set up an automated daily PostgreSQL backup system on my home server (a 2014 Mac mini running Ubuntu Server).
A Python script, scheduled with cron, does the following:
- Connects to the production server.
- Creates a PostgreSQL backup with
pg_dump. - Copies the backup file to the home server and removes it from the production server.
- Deletes backups older than 7 days.
- Sends Telegram notifications for both successful runs and errors.

Email Sending
I’ve integrated the Mailgun API to handle:
- Email confirmations for registrations and email changes.
- Password reset emails.

Frontend Architecture
- Although I’m primarily a backend developer, I chose pure CSS with BEM over frameworks.
- Mobile and desktop layouts.
- HTMX-driven interactions.
- Dark and light themes with
localStoragepersistence. - Client-side time zone conversion.
- Image zoom with Lightense.
Security and Monitoring
- Nginx is configured to trust Cloudflare IP ranges and extract the real client IP.
- Nginx uses Cloudflare Origin Certificates to encrypt traffic between Cloudflare and the origin server.
- Nginx rate limiting.
- Email verification and password reset tokens.
- Strong password hashing and validation.
- Early bot detection implemented via a hidden honeypot field.
- reCAPTCHA v2 on auth endpoints.
- Separate environments for development and production.
- Sentry error tracking.
- Custom request logging middleware.
Posts
- Markdown rendering via a custom Mistune renderer.
- Pygments syntax highlighting for code blocks.
- Stores rendered Markdown HTML in the database, clearing it only when content changes.
- Supports both auto-rendered Markdown and pre-rendered HTML.
- Auto-generated, URL-friendly slugs with uniqueness guarantees.
- OpenGraph metadata for SEO.
Engagement
- Likes for both authenticated users and anonymous visitors.
- One-like-per-user/IP enforced at the database level.
- View counting and visibility controls.
- Comments for authenticated users.
SEO
- Automatic
sitemap.xmlgeneration. robots.txt.- Open Graph metadata.
Good job!
Kekus, thanks!