Automatically Deploying a Hugo Blog to a Cloud Server with Caddy

After building your blog with Hugo + Stack, the next step is deploying it to your cloud server.

My VPS environment: Ubuntu 24.04

The setup I use:

  • Caddy as the web server
  • SSH + rsync to sync static files

Workflow:
Generate static files locally → One-click sync to VPS → Caddy automatically serves the new content.

Let’s go through it step by step 👇

Server Setup

Install the Caddy service:

1
2
3
4
5
6
7
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Check if Caddy is installed successfully:

1
caddy version

At this point, if you open http://VPS_IP in your browser, you should see the default Caddy welcome page.

Now, create a directory for your blog. I put all my site files under /var/www/sirenlingyu/:

1
mkdir -p /var/www/sirenlingyu

Edit the Caddyfile configuration:

1
sudo nano /etc/caddy/Caddyfile

Comment out everything starting from :80 and add the following:

1
2
3
4
5
6
7
8
sirenlingyu.com {
    root * /var/www/sirenlingyu
    file_server
    encode gzip zstd
    log {
        output file /var/log/caddy/access.log
    }
}

⚠️ Replace sirenlingyu.com with your own domain name. Make sure your domain is already pointing to your VPS. Also replace yourmail@example.com with your own email — Caddy will automatically issue an SSL certificate for you.

Before Caddy can auto-generate certificates, make sure the caddy user has permission to access its working directory:

1
sudo chown -R caddy:caddy /var/lib/caddy

Then reload the Caddy service:

1
sudo systemctl reload caddy

Set Up SSH Key Login

For security reasons, I created a separate user called deploy on the VPS. This user can only access the website directory and is used purely for SSH deployment.

Create the deploy user:

1
2
3
sudo adduser deploy
sudo mkdir -p /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh

Give that user access to the website directory:

1
sudo chown -R deploy:deploy /var/www/sirenlingyu

On your local computer, generate a new SSH key pair:

1
ssh-keygen -t ed25519 -C "yourmail@example.com"

Press Enter all the way through — it’ll generate two files: ~/.ssh/id_ed25519 and ~/.ssh/id_ed25519.pub

Display the public key:

1
cat ~/.ssh/id_ed25519.pub

Then, on your VPS, add the public key to the deploy user:

1
2
3
echo "your-public-key-content" | sudo tee -a /home/deploy/.ssh/authorized_keys
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh

Test the SSH login:

1
ssh deploy@VPS_IP

Deploy the Static Files to the Server

In your local Hugo blog directory, build the static site:

1
hugo

Then run rsync to deploy it:

1
rsync -avz --delete public/ deploy@VPS_IP:/var/www/sirenlingyu/

Once that’s done, visit https://sirenlingyu.com — my blog should be live! 🎉

One-Click Deployment Script

To make updates easier, I wrote a simple deploy.sh script and placed it in the root of the blog directory:

1
2
3
4
#!/bin/bash

hugo
rsync -avz --delete public/ deploy@VPS_IP:/var/www/sirenlingyu/

Give it execute permission:

1
chmod +x deploy.sh

Now, whenever you update your blog, just run:

1
./deploy.sh

And that’s it — one command, fully automated deployment. 🚀