Skip to content

Self-hosting a Website with Caddy

Published: 2025-04-16 21:46 +1200
Last Modified: 2025-04-18 16:25 +1200


Background

After getting my Gemini server up and running, I wanted to take the next step and host a website in the same manner. After a few fumbles with Apache HTTP Server, I was encouraged by John Wq to give Caddy a go as it is a bit more user-friendly. It was just what I needed for my beginner level. I still fumbled a bit, but the documentation was a lot more helpful, and I noticed some things along the way that were probably preventing things earlier as well.

I also wanted to try out the new Bash Static Site Generator (BSSG) because it's new, it's bash, and it's got some pretty rad custom themes out of the box. I already have a website where I muck around with styles, and given this one is going to be specifically for notes, I'm happy to not faff around with styling here. Other static site generators I've been weighing up are manpageblog and mdsite, both very simplistic and in line with where I'd like to take this site. For now though, BSSG it is.

Update 2025-04-18: I have chosen MkDocs with the Material for MkDocs plugin as my static site generator. The modern styling, top-notch documentation and easy of use won me over in the end. It is free, and open source.

Method

Install Caddy

Caddy is available in the apt package manager:

  sudo apt install caddy

Add DNS record

In my namecheap.com dashboard, go to Domain List --> Manage (zkbro.com) --> Advanced DNS.

If it's not already enabled, enable Dynamic DNS - This ensures the IP address I assign to this host are updated dynamically if they ever change (which they do). This also requires a Dynamic DNS client to pass my current IP address to namecheap regularly. It is optional, but saves me having to manually update the public IP in the dashboard everytime it changes.

Under "Host Records" add a new record with the following information:

Install ddclient (a Dynamic DNS client):

  sudo apt install ddclient

Follow the basic configuration steps in ddclient and when prompted use the password generated back in the namecheap dashboard.

Ensure the /etc/ddclient.conf file looks something like this:

  # Configuration file for ddclient generated by debconf
  #
  # /etc/ddclient.conf

  protocol=namecheap \
  use=web, web=ipify-ipv4 \
  login=zkbro.com \
  password='DDNS_PASSWORD' \
  gmi,notes

Note I added "notes" so both gmi and notes subdomains get updated.

Forcing an IP update is a good way to test it is working:

  sudo ddclient -verbose -force

Allow ports through firewall

  sudo ufw allow 80/tcp
  sudo ufw allow 443/tcp
  sudo ufw reload

Set port forwarding

Log in to my router GUI at http://192.168.1.1/. In my old Slingshot ISP router menu go to "Advanced Setup" --> "NAT" --> "Virtual Servers" and add a new server with the following configuration:

  • Use interface: ETH WAN
  • Custom Service: Caddy (or whatever)
  • Enable LAN Loopback: true (so I can access the site on my own LAN).
  • Server IP Address: 192.168.1."18" (replace "18" with whatever the server machine is. Check with ip a.)
  • Status: Enable
  • External Port Start: 80 & 443
  • External Port End: 80 & 443
  • Protocol: TCP
  • Internal Port Start: 80 & 443
  • Internal Port Start: 80 & 443

My understanding is that both ports are needed so both http(80) and https(443) can be used.

I got an error when adding port 80 as it was reserved for the router's own interface. I had to go to "Management" --> "Access Control" --> "Services Control" and change the HTTP LAN Port number from 80 to something else to free it up. It means I now have to access my modem via http://192.168.1.1:8080/ now. No biggy.

Create a website

I will not lay out the details here as there are many ways to do it, but for now I am simply following the Material for MkDocs documentation.

Create a Caddyfile

Once the website has been built, navigate to the website's public root directory and create a file called Caddyfile. It will contain the following text:

  notes.zkbro.com

  file_server

This tells Caddy it is a static website. Then run caddy as a daemon:

  sudo caddy start

To stop:

  sudo caddy stop

Instead of creating a Caddyfile, I can just use:

  sudo caddy file-server --domain notes.zkbro.com

Next steps

Fix my workflow. I'm afraid this is going to be a big thing as I've now got 2 websites, a gemini capsule, a laptop and raspberry pi, self-hosted (pi), hosted (neocities), git repositories, text editors, md2gemini converter, tmux, termux, zellij, tailscale, ssh, scp, custom blog scripts, obsidian, logseq, helix, random project folders with md and gmi files, template files, and a bunch of other things to think about. I'm actually looking forward to getting these things a bit tighter.A mind map of all these things will be my starting point.

Resources