While I’ve been writing the Certification Journey to cover the theoretical side of security, today I want to show you how those concepts—specifically Defense in Depth and Separation of Concerns—manifest in the actual architecture of this blog.

By moving away from a traditional “all-in-one” server and adopting a modular, Docker-based approach, I can create a stack that is not only faster but significantly more resilient to attack.

The Architectural Blueprint

Instead of a single server handling everything, my stack is divided into three distinct functional layers: The Builder, The Server, and The Gatekeeper.

1. The Content Builder (Hugo)

The first layer is the Hugo container (hugomods/hugo). In a standard setup, you might run hugo server and let it handle web traffic. However, from a security perspective, this isn’t ideal because the builder has access to your entire source directory—including configuration files and raw markdown.

In my hardened stack, the Hugo container is strictly a builder.

  • Role: It watches the source directory for changes.
  • Action: It generates static HTML/CSS/JS files and writes them to a specific ./public directory.
  • Security Benefit: This container is never exposed to the internet. It lives entirely within the internal Docker network.

2. The Web Server (Nginx Alpine)

Once the files are built, I need something to serve them. I use a lightweight nginx:alpine container for this.

  • Least Privilege: This container only has read access to the ./public folder. It has no idea the Hugo source files even exist.
  • Isolation: If this container were somehow compromised, the attacker would find themselves in a “jail” with nothing but static HTML files and no way to reach the source code or the builder.
  • Performance: Nginx is world-class at serving static assets, ensuring the site remains snappy even under load.

3. The Gatekeeper (Nginx Proxy Manager + CrowdSec)

The final layer is where the “Network+” and “Security+” concepts really shine. I use Nginx Proxy Manager (NPM) as a reverse proxy.

  • SSL Termination: NPM handles my Let’s Encrypt certificates, ensuring all traffic is encrypted (HTTPS) before it reaches my internal network.
  • IP Masking: External users never talk to the Nginx web server directly; they only ever see the proxy.
  • CrowdSec Integration: This is my “Secret Sauce.” I use a specialized version of NPM (npmplus) that has a CrowdSec Bouncer built-in.

CrowdSec acts as my Intrusion Prevention System (IPS). It parses the logs from the proxy in real-time. If a bot starts brute-forcing the admin panel or scanning for vulnerabilities, CrowdSec identifies the behavior and tells the proxy to drop all traffic from that IP instantly.

The “Infrastructure as Code” Implementation

All of this is managed via a single docker-compose.yaml file. This allows me to define my entire network topology and security rules in a version-controlled document.

services:
  # The Gatekeeper (Reverse Proxy + Bouncer)
  npm:
    image: 'zoeyvid/npmplus:latest'
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./npm-data:/data
 
  # The IPS (Log Parser)
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    volumes:
      - ./npm-data/logs:/var/log/npm:ro
 
  # The Builder (Watching for changes)
  hugo:
    image: hugomods/hugo:exts
    volumes:
      - .:/src
    command: hugo --watch --poll 700ms
 
  # The Web Server (Internal only)
  my-website:
    image: nginx:alpine
    volumes:
      - ./public:/usr/share/nginx/html:ro

Why This Matters

This architecture embodies several core security principles:

  1. Attack Surface Reduction: The only container exposed to the internet is the Proxy. Everything else is tucked away behind a virtual firewall.
  2. Immutability: My web server serves static files. There is no database to inject, no PHP to exploit, and no server-side logic to hijack.
  3. Collaborative Defense: Through CrowdSec, my server isn’t just defending itself; it’s benefiting from the shared intelligence of thousands of other servers worldwide.

By treating my infrastructure as code and applying a layered defense strategy, I’ve built a platform that is as secure as it is simple to maintain.