Self-Hosted Markdown Blog Solutions

Static Site Generators + Web Server

  1. Hugo with Caddy

    FROM klakegg/hugo:0.107.0 AS build
    COPY . /src
    RUN hugo --minify
    
    FROM caddy:2.6.4-alpine
    COPY --from=build /src/public /usr/share/caddy
    
    • Features:
      • Single-binary deployment
      • Automatic HTTPS
      • HTTP/3 support
  2. Jekyll + Nginx

    server {
        listen 80;
        server_name blog.example.com;
        root /var/www/blog/_site;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
    

Self-Hosted CMS Options

  • Ghost (Pro)
    • Requirements:

      • Node.js 16/18
      • MySQL 8
    • Deployment:

      ghost install --local
      
  • Strapi + Markdown Plugin
    • Markdown field type

    • REST/GraphQL API

    • Docker-compose example:

      services:
        postgres:
          image: postgres:15
        strapi:
          image: strapi/strapi:4.11.7
          depends_on:
            - postgres
      

Markdown Editors with Self-Hosting

  1. Jupyter Notebooks

    • Convert .ipynb to Markdown
    • JupyterHub deployment
  2. Outline (Knowledge base)

    • Markdown WYSIWYG
    • Docker deployment

Deployment Environments

Environment Requirements Setup Complexity
VPS 1GB RAM, 20GB SSD Medium
Home Server Raspberry Pi 4+ High
Container Docker, Kubernetes Variable
Serverless AWS Lambda, Cloudflare Low

Automation & CI/CD

# .github/workflows/deploy.yml
name: Deploy Blog
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build Hugo
        run: hugo --minify
      - name: Deploy to SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SSH_HOST }}
          key: ${{ secrets.SSH_KEY }}
          source: "public/"
          target: "/var/www/blog"

Security Considerations

  • SSL/TLS with Let's Encrypt

    certbot --nginx -d blog.example.com
    
  • Firewall rules (UFW example):

    ufw allow 22/tcp
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw enable
    
  • Regular backups

    # Daily backup script
    0 2 * * * tar -czf /backups/blog-$(date +\%F).tar.gz /var/www/blog
    

Monitoring & Maintenance

  • Prometheus + Grafana for metrics

  • Logrotate configuration:

    /var/log/nginx/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0640 www-data adm
        sharedscripts
    }
    
  • Systemd Service example for Hugo:

    [Unit]
    Description=Hugo Blog Service
    After=network.target
    
    [Service]
    User=bloguser
    WorkingDirectory=/var/www/blog
    ExecStart=/usr/local/bin/hugo server --bind 0.0.0.0 --baseURL https://blog.example.com
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    
  1. Simple: Hugo + Caddy + Docker
  2. Full CMS: Ghost + MySQL + Cloudflare Tunnel
  3. Dynamic: Strapi + Next.js + AWS Lightsail

Alternative Approaches:

  • Cloudflare Pages + Git (Managed self-hosting)