Ditching the "Standard" for Ghost: A modern blog

Ditching the "Standard" for Ghost: A modern blog

This post serves as both a documentation of my technical infrastructure and a case study for my professional portfolio. It explains the "why" and "how" behind the deployment of this blog.


Why Ghost? Choosing Security and Simplicity

When deciding on a CMS, the obvious choice for many is WordPress. However, when one thinks about security, prioritize a smaller attack surface and better performance.

  • Security by Design: WordPress is often vulnerable because of its massive ecosystem of third-party plugins and themes, which are frequent targets for exploits. Ghost has a much smaller footprint, which inherently improves security.
  • Minimalism: Ghost focuses strictly on publishing. It provides a clean, distraction-free Markdown editor that saves time compared to the cluttered interfaces of more complex systems.
  • Performance: Built on Node.js, Ghost is significantly faster than PHP-based alternatives. Fast load times improve both user experience and SEO rankings.
  • Built-in Tools: Features like SEO management, newsletters, and memberships are native to Ghost. This removes the need for multiple external plugins that can slow down a site or introduce security risks.

The Technical Stack

I deployed this blog using a modern, containerized architecture on an Ubuntu VPS. This setup ensures the application is isolated, easy to move, and highly secure.

1. Containerization with Docker

I used the official Ghost Docker image to run the application. Using Docker Compose allows me to manage the Ghost instance and its MySQL database as a single, composable unit.

2. Reverse Proxy with Nginx

Nginx sits on the host machine and acts as a reverse proxy. It handles the incoming traffic on ports 80 and 443 and forwards it to the Ghost container. This configuration allows me to handle SSL termination and security headers at the host level.

server {
    listen 443 ssl;
    server_name blog.miane.tech;

    # SSL Configuration (Paths simplified for documentation)
    ssl_certificate /etc/letsencrypt/live/blog.miane.tech/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/blog.miane.tech/privkey.pem;

    # Performance: Increase upload limit for themes/images
    client_max_body_size 50M;

    location / {
        proxy_pass http://localhost:5000;
        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;

        # Optimized for Ghost's Admin UI and Real-time updates
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        proxy_buffering off;
    }
}

3. Edge Security with Cloudflare

To further harden the site, I use Cloudflare as the DNS provider and proxy.

  • IP Masking: Cloudflare hides my VPS's real IP address, preventing direct attacks on the server.
  • SSL/TLS: I configured "Full (strict)" encryption to ensure all traffic between the visitor, Cloudflare, and my server is encrypted.

Conclusion

By self-hosting Ghost behind Nginx and Cloudflare, I have created a platform that is not just a blog, but a demonstration of systems administration and security best practices. This project shows how choosing the right tool for the job—prioritizing focus over "infinite options"—leads to a more stable and professional result.

Subscribe for new projects, tips and tricks!