Adding Hugo to Your Technovangelist Homelab - Complete Guide

This comprehensive tutorial will walk you through adding Hugo to your existing technovangelist homelab setup. We’ll cover Docker configuration, Caddy reverse proxy setup, proper DNS configuration, and troubleshooting Safari iOS compatibility issues.

πŸ“‹ Prerequisites

  • Working technovangelist homelab setup
  • Caddy reverse proxy running (usually as caddy2)
  • Domain name with Cloudflare DNS management
  • SSH access to your server
  • Basic understanding of Docker and Docker Compose

🎯 What You’ll Have After This Tutorial

  • Hugo website running in Docker
  • Proper DNS setup with A and CNAME records
  • Safari iOS compatibility (important!)
  • Secure HTTPS via Cloudflare Origin Certificates
  • Easy content management workflow

πŸ“ Step 1: Create Hugo Directory Structure

cd homelab
mkdir hugo
cd hugo

🐳 Step 2: Create Docker Compose Configuration

Create the file docker-compose.yml:

version: '3.8'

services:
  hugo:
    image: ghcr.io/gohugoio/hugo:latest
    container_name: hugo
    restart: unless-stopped
    user: "${UID}:${GID}"
    volumes:
      - ./site:/src
    working_dir: /src
    command: server --bind 0.0.0.0 --port 1313 --baseURL ${HUGO_BASE_URL} --disableLiveReload --watch=false
    environment:
      - HUGO_ENV=production
    networks:
      - caddy2_default

networks:
  caddy2_default:
    external: true

Important: Adjust the network name (caddy2_default) to match your Caddy setup. Check with docker network ls | grep caddy.

πŸ“ Step 3: Environment Configuration

Create the file example.env:

HUGO_BASE_URL=https://yourdomain.com
UID=1001
GID=1001

Copy to your active configuration:

cp example.env .env

# Update with your actual values
echo "UID=$(id -u)" > .env
echo "GID=$(id -g)" >> .env
echo "HUGO_BASE_URL=https://yourdomain.com" >> .env

πŸš€ Step 4: Initialize Hugo Site

# Initialize new Hugo site
docker run --rm -v $(pwd):/src -w /src --user $(id -u):$(id -g) --entrypoint hugo ghcr.io/gohugoio/hugo:latest new site site

# Verify site creation
ls -la site/

You should see Hugo’s basic directory structure including content/, themes/, hugo.toml, etc.

🎨 Step 5: Install PaperMod Theme

cd site

# Initialize git repository
git init

# Add PaperMod theme as submodule
git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
git submodule update --init --recursive

# Return to hugo directory
cd ..

βš™οΈ Step 6: Configure Hugo

Edit the file site/hugo.toml and replace the content:

baseURL = 'https://yourdomain.com'
languageCode = 'en'
title = 'Your Site Title'
theme = 'PaperMod'

enableRobotsTXT = true
buildDrafts = false
buildFuture = false
buildExpired = false

[params]
env = "production"
title = "Your Site Title"
description = "Your personal website and homelab"
author = "Your Name"
DateFormat = "January 2, 2006"
defaultTheme = "auto"
disableThemeToggle = false

ShowReadingTime = true
ShowShareButtons = true
ShowPostNavLinks = true
ShowBreadCrumbs = true
ShowCodeCopyButtons = true
ShowWordCount = true
UseHugoToc = true
disableSpecial1stPost = false
disableScrollToTop = false
comments = false
hidemeta = false
hideSummary = false
showtoc = false
tocopen = false

[params.homeInfoParams]
Title = "Welcome to Your Homelab"
Content = "Your personal website running on your homelab infrastructure"

[[params.socialIcons]]
name = "github"
url = "https://github.com/yourusername"

[menu]
[[menu.main]]
identifier = "home"
name = "Home"
url = "/"
weight = 10

[[menu.main]]
identifier = "posts"
name = "Posts"
url = "/posts/"
weight = 20

[[menu.main]]
identifier = "about"
name = "About"
url = "/about/"
weight = 30

πŸ“ Step 7: Create Initial Content

Create Your First Post

# Create a new post
docker run --rm -v $(pwd)/site:/src -w /src --user $(id -u):$(id -g) --entrypoint hugo ghcr.io/gohugoio/hugo:latest new posts/homelab-setup.md

Edit site/content/posts/homelab-setup.md:

---
title: "My Homelab Setup with Hugo"
date: 2025-06-26T12:00:00+02:00
draft: false
tags: ["hugo", "homelab", "self-hosting"]
categories: ["homelab"]
description: "How I set up Hugo on my technovangelist homelab"
---

# Welcome to My Homelab Website!

This website is running on my personal homelab infrastructure using:

## Tech Stack

- **Hugo** - Fast static site generator
- **PaperMod** - Clean and modern theme
- **Docker** - Containerized deployment
- **Caddy** - Automatic HTTPS and reverse proxy
- **Cloudflare** - DNS management and SSL
- **Tailscale** - Secure access to homelab

## Homelab Components

My homelab runs the technovangelist setup with:

- Docker Compose for service orchestration
- Caddy for automatic HTTPS and reverse proxy
- Tailscale VPN for secure external access
- Various self-hosted applications

## Why Self-Host?

Self-hosting gives me:

- **Control** over my data and services
- **Learning opportunities** with new technologies
- **Cost savings** compared to cloud services
- **Privacy** and security benefits
- **Fun!** Building and maintaining systems

## What's Next?

I'll be writing about:

- Homelab projects and experiments
- Docker and container management
- Self-hosting tutorials
- Infrastructure automation
- Privacy and security topics

Stay tuned for more content!

Create About Page

# Create about page
docker run --rm -v $(pwd)/site:/src -w /src --user $(id -u):$(id -g) --entrypoint hugo ghcr.io/gohugoio/hugo:latest new about.md

Edit site/content/about.md:

---
title: "About"
date: 2025-06-26T12:00:00+02:00
draft: false
description: "About me and this website"
---

# About Me

Welcome to my personal website!

## Who Am I?

I'm a technology enthusiast passionate about self-hosting, privacy, and building efficient systems. This website runs on my own homelab infrastructure.

## My Interests

- **Homelab & Self-Hosting:** Running my own services and infrastructure
- **Privacy & Security:** Maintaining control over personal data
- **Open Source:** Contributing to and using open source software
- **Automation:** Making systems work efficiently with minimal intervention
- **Learning:** Constantly exploring new technologies and approaches

## This Website

This site is powered by:

- **Hugo** for fast, static content generation
- **Docker** for reliable, reproducible deployments
- **Caddy** for automatic HTTPS and reverse proxy
- **Cloudflare** for DNS management and edge security
- **Tailscale** for secure access to my homelab

The entire setup follows the technovangelist homelab approach, emphasizing simplicity and reliability.

## Get In Touch

- **Email:** [[email protected]]
- **GitHub:** [github.com/yourusername]
- **Mastodon:** [@[email protected]]

## Homelab Services

Other services running on my homelab:

- **n8n:** Workflow automation
- **Various other self-hosted applications**

---

*This website is built with Hugo and the PaperMod theme, deployed via Docker on my homelab infrastructure.*

πŸ§ͺ Step 8: Test Hugo Locally

# Start Hugo development server
docker compose up

Test your website locally:

  • Direct: http://[server-ip]:1313
  • Via Tailscale: Access your server IP on port 1313

You should see your Hugo website with the PaperMod theme and your content!

🌐 Step 9: DNS Configuration (Critical!)

This is the most important step for Safari iOS compatibility.

In Cloudflare Dashboard β†’ DNS β†’ Records:

Create these DNS records:

  1. Root Domain (A Record):

    • Type: A
    • Name: @
    • IPv4 address: [your-server-ip]
    • Proxy status: 🟠 Proxied (orange cloud ON)
    • TTL: Auto
  2. WWW Subdomain (CNAME):

    • Type: CNAME
    • Name: www
    • Target: yourdomain.com
    • Proxy status: 🟠 Proxied (orange cloud ON)
    • TTL: Auto
  3. Other Subdomains (CNAME):

    • Type: CNAME
    • Name: n8n (or other services)
    • Target: yourdomain.com
    • Proxy status: 🟠 Proxied (orange cloud ON)
    • TTL: Auto

Find Your Server IP:

# On your server
curl ifconfig.me

πŸ”§ Step 10: Caddy Configuration

Navigate to your Caddy directory and edit the Caddyfile:

cd ../caddy  # or ../caddy2
nano Caddyfile

Add Hugo configuration:

# Hugo website on both root and www domains
yourdomain.com {
    tls /etc/caddy/certs/yourdomain.com.crt /etc/caddy/certs/yourdomain.com.key
    reverse_proxy hugo:1313
}

www.yourdomain.com {
    tls /etc/caddy/certs/yourdomain.com.crt /etc/caddy/certs/yourdomain.com.key
    reverse_proxy hugo:1313
}

# Existing services remain
n8n.yourdomain.com {
    tls /etc/caddy/certs/yourdomain.com.crt /etc/caddy/certs/yourdomain.com.key
    reverse_proxy n8n:5678
}

Note: Adjust certificate paths and service names according to your existing setup.

βš™οΈ Step 11: Cloudflare SSL/TLS Settings

Configure optimal SSL settings in Cloudflare Dashboard:

SSL/TLS β†’ Overview:

  • Encryption mode: Full (strict) βœ…

SSL/TLS β†’ Edge Certificates:

  • Always Use HTTPS: ON βœ…
  • HTTP Strict Transport Security (HSTS): OFF (initially)
  • Minimum TLS Version: TLS 1.2 βœ…
  • Opportunistic Encryption: ON βœ…
  • TLS 1.3: ON βœ…

πŸš€ Step 12: Deploy to Production

# Stop local testing
cd ../hugo
docker compose down

# Start in production mode
docker compose up -d

# Restart Caddy to load new configuration
cd ../caddy
docker compose restart

βœ… Step 13: Testing and Verification

Test Both Domains:

# Test root domain
curl https://yourdomain.com

# Test www subdomain
curl https://www.yourdomain.com

# Both should return your Hugo website HTML

Test All Browsers:

  • Desktop browsers: Chrome, Firefox, Safari, Edge
  • Mobile browsers: Especially Safari iOS (critical!)
  • Different devices: iPhone, Android, tablet

πŸ“± Safari iOS Compatibility (Important!)

Critical Issue: Safari iOS may show a white screen on the root domain (yourdomain.com) while working fine on the www subdomain (www.yourdomain.com).

Solution: Both domains are configured in Caddy, so users can access either:

  • https://yourdomain.com (works on most browsers)
  • https://www.yourdomain.com (works on all browsers including Safari iOS)

πŸ”„ Daily Content Management

Creating New Posts:

cd homelab/hugo/site
docker run --rm -v $(pwd):/src -w /src --user $(id -u):$(id -g) --entrypoint hugo ghcr.io/gohugoio/hugo:latest new posts/my-new-post.md

Managing the Hugo Container:

cd homelab/hugo

# View logs
docker compose logs -f

# Restart
docker compose restart

# Stop
docker compose down

# Start
docker compose up -d

Content Updates:

Hugo automatically detects changes in the site/ directory and reloads the website. No manual rebuilds needed!

πŸ› οΈ Troubleshooting

Website Not Accessible

Check container status:

docker ps | grep hugo
docker ps | grep caddy

Check logs:

docker compose logs hugo
docker compose logs caddy

Test connectivity:

# Test if Caddy can reach Hugo
docker exec caddy ping hugo

# Test Hugo directly
docker run --rm --network caddy2_default alpine/curl curl http://hugo:1313

Permission Errors

# Fix ownership
sudo chown -R $USER:$USER site/

# Update UID/GID in .env
echo "UID=$(id -u)" > .env
echo "GID=$(id -g)" >> .env

Theme Not Loading

# Check theme directory
ls -la site/themes/PaperMod/

# Reinstall theme if needed
cd site
git submodule update --init --recursive

Safari iOS White Screen

This is the most common issue!

Symptoms:

  • Website works on desktop browsers
  • Website works on Chrome/Firefox mobile
  • Safari iOS shows white screen

Solution:

  • Use https://www.yourdomain.com instead of https://yourdomain.com
  • Both URLs are configured and work
  • This is a known Safari iOS quirk with certain SSL configurations

Testing:

  • Test on actual iOS device with Safari
  • Try both root domain and www subdomain
  • Clear Safari cache if needed

Network Connection Issues

# Check Docker networks
docker network ls

# Verify Hugo is on correct network
docker inspect hugo | grep -A 10 Networks

# Test network connectivity
docker run --rm --network caddy2_default alpine/curl curl http://hugo:1313

DNS Issues

Check DNS propagation:

# Check if DNS has propagated
dig yourdomain.com
dig www.yourdomain.com

# Check from different locations
nslookup yourdomain.com 8.8.8.8

Cloudflare settings:

  • Ensure proxy status is ON (orange cloud)
  • Check for conflicting Page Rules
  • Verify SSL mode is “Full (strict)”

Hugo Content Issues

Check content directory:

ls -la site/content/
ls -la site/content/posts/

Verify Hugo configuration:

cat site/hugo.toml | grep baseURL

Test Hugo directly:

docker exec hugo hugo version
docker exec hugo ls -la /src/content/

🎯 Advanced Configuration

Custom CSS

Add custom styling by creating files in site/assets/css/:

mkdir -p site/assets/css
cat > site/assets/css/extended.css << 'EOF'
/* Custom styles for your site */
.custom-header {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    padding: 20px;
    border-radius: 8px;
}
EOF

Performance Optimization

Enable minification in Hugo config:

[minify]
  disableXML = true
  minifyOutput = true

[markup]
  [markup.goldmark]
    [markup.goldmark.renderer]
      unsafe = true

Backup Strategy

Regular backups of your site content:

# Simple backup
tar -czf hugo-backup-$(date +%Y%m%d).tar.gz site/

# With git (recommended)
cd site
git add .
git commit -m "Content update $(date)"
git push origin main

Automated Deployments

For advanced setups, consider:

  • GitHub Actions for automated builds
  • Webhooks for content updates
  • CI/CD pipelines for testing

πŸ”’ Security Considerations

Current Security Layers:

  1. Tailscale VPN - Primary access control
  2. Cloudflare Proxy - DDoS protection and edge security
  3. Full SSL/TLS - End-to-end encryption
  4. Container Isolation - Hugo runs in isolated container
  5. No Exposed Ports - Hugo only accessible via Caddy

Additional Security:

  • Regular Hugo updates via container image updates
  • Monitor Cloudflare security events
  • Keep Caddy and Docker updated
  • Regular backup testing

πŸš€ Performance and Scaling

Current Setup Benefits:

  • Fast Loading - Hugo generates static files
  • CDN Integration - Cloudflare edge caching
  • Efficient Resource Usage - Minimal server requirements
  • High Availability - Container restart policies

Scaling Options:

  • Multi-server deployment with load balancing
  • CDN optimization with Cloudflare Workers
  • Database integration for dynamic content
  • Search functionality with client-side search

πŸŽ‰ Conclusion

You now have a fully functional Hugo website integrated into your homelab! This setup provides:

  • βœ… Professional Website - Fast, secure, and reliable
  • βœ… Safari iOS Compatible - Works on all browsers and devices
  • βœ… Easy Management - Simple content creation workflow
  • βœ… Secure Access - Protected by Tailscale and Cloudflare
  • βœ… Scalable Architecture - Easy to expand and modify
  • βœ… Modern Stack - Docker, Caddy, Hugo, and Cloudflare

Key Lessons Learned:

  1. DNS Configuration is Critical - Proper A and CNAME records prevent many issues
  2. Safari iOS Compatibility - www subdomain works better than root domain
  3. Network Configuration - Ensure containers can communicate
  4. Security Layers - Multiple levels of protection work together

Next Steps:

  • Write more content and build your audience
  • Explore Hugo’s advanced features
  • Add more homelab services
  • Share your homelab journey with the community

Happy blogging and enjoy your new homelab website! 🎊


This tutorial was tested with the technovangelist homelab setup. Adjust commands and configurations according to your specific environment.

Troubleshooting Quick Reference:

Issue Solution
Safari iOS white screen Use www.yourdomain.com instead
Hugo not accessible Check Docker networks and container status
DNS not resolving Verify Cloudflare proxy settings
SSL certificate errors Check Cloudflare SSL mode (Full strict)
Permission denied Fix file ownership and UID/GID
Theme not loading Reinstall git submodules
Container won’t start Check logs and volume mounts

For additional help, consult the Hugo documentation, Caddy documentation, or the technovangelist community.