Hugo Campus

Setting up Git, Nginx, and the Server

This post describes the steps to get Hugo running on a new web site. It’s not user-friendly.

I built two sites, one for testing and one for production. I am developing (writing) the site on my laptop.

Create the Server

I created a small server on DigitalOcean.

I installed Nginx for my web server, then created an entry in my ~/.ssh/config file for it called “parking.”

Nginx setup

I created folders for a production and testing website on the droplet. (The character is my prompt.)

➜ mkdir -p /var/www/hugocampus.com/public
➜ chown -R mdhender:mdhender /var/www/hugocampus.com

➜ mkdir -p /var/www/testing.hugocampus.com/public
➜ echo 'nginx set up correctly' > /var/www/testing.hugocampus.com/public/index.html
➜ chown -R mdhender:mdhender /var/www/testing.hugocampus.com

I created config files for both sites.

➜ cat /etc/nginx/sites-available/hugocampus.com

server {
  server_name hugocampus.com;
  root        /var/www/hugocampus.com/public;
  index       index.html;
  access_log  /var/log/nginx/hugocampus.com.access.log;
  error_log   /var/log/nginx/hugocampus.com.error.log  crit;

  location / {
    try_files $uri $uri/ =404;
  }
}

(The one for testing is similar, with different paths.)

I copied the configuration files to enable the two sites.

➜ cp /etc/nginx/sites-available/hugocampus.com /etc/nginx/sites-enabled/
➜ cp /etc/nginx/sites-available/testing.hugocampus.com /etc/nginx/sites-enabled/

I tested the configuration, then restarted the Nginx server.

➜ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

➜ systemctl restart nginx

I wanted HTTPS, so I ran certbot for both servers.

➜ certbot --nginx -d hugocampus.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for hugocampus.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/hugocampus.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/hugocampus.com/privkey.pem
This certificate expires on 2025-12-07.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for hugocampus.com to /etc/nginx/sites-enabled/hugocampus.com
Congratulations! You have successfully enabled HTTPS on https://hugocampus.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Github

I created a new Github repository to store the Hugo Campus source.

Github repository

Local setup

I’m on a Mac, so I used brew to install Hugo.

➜ which hugo
/opt/homebrew/bin/hugo

➜ hugo version
hugo v0.148.2+extended+withdeploy darwin/arm64 BuildDate=2025-07-27T12:43:24Z VendorInfo=brew

I created a new site using the hugo new site command.

➜ pwd
/Users/wraith/hugo

➜ hugo new site hugocampus.com
Congratulations! Your new Hugo site was created in /Users/wraith/hugo/hugocampus.com.

Just a few more steps...

1. Change the current directory to /Users/wraith/hugo/hugocampus.com.
2. Create or install a theme:
   - Create a new theme with the command "hugo new theme <THEMENAME>"
   - Or, install a theme from https://themes.gohugo.io/
3. Edit hugo.toml, setting the "theme" property to the theme name.
4. Create new content with the command "hugo new content <SECTIONNAME>/<FILENAME>.<FORMAT>".
5. Start the embedded web server with the command "hugo server --buildDrafts".

See documentation at https://gohugo.io/.

Then I added .gitattributes, .gitignore, COPYING, and README.md files.

➜ cd hugocampus.com

➜ ls -al
total 80
drwxr-xr-x  15 wraith  staff    480 Sep  8 09:24 .
drwxr-xr-x   5 wraith  staff    160 Sep  8 09:18 ..
-rw-r--r--   1 wraith  staff    367 Sep  8 09:15 .gitattributes
-rw-r--r--   1 wraith  staff     25 Sep  8 09:12 .gitignore
drwxr-xr-x   3 wraith  staff     96 Sep  8 08:52 archetypes
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 assets
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 content
-rw-r--r--   1 wraith  staff  22955 Sep  8 09:02 COPYING
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 data
-rw-r--r--   1 wraith  staff     83 Sep  8 08:52 hugo.toml
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 i18n
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 layouts
-rw-r--r--   1 wraith  staff    542 Sep  8 09:24 README.md
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 static
drwxr-xr-x   2 wraith  staff     64 Sep  8 08:52 themes

Next, I ran git init to create my local repo.

➜ git init .
Initialized empty Git repository in /Users/wraith/hugo/hugocampus.com/.git/
➜ git commit -m "initial commit"
[main (root-commit) 97a7418] initial commit
 6 files changed, 496 insertions(+)
 create mode 100644 .gitattributes
 create mode 100644 .gitignore
 create mode 100644 COPYING
 create mode 100644 README.md
 create mode 100644 archetypes/default.md
 create mode 100644 hugo.toml

Note: git ignores the empty directories (assets, content, data, i18n, layouts, static, themes). I could add a .gitkeep file to each if I really wanted to add them to the repository.

I added my Github repo as the upstream.

➜ git remote add origin git@github.com:mdhender/hugocampus.git

➜ git remote -v
origin	git@github.com:mdhender/hugocampus.git (fetch)
origin	git@github.com:mdhender/hugocampus.git (push)

Then pushed to it.

➜ git push -u origin main
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 10 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (9/9), 8.98 KiB | 8.98 MiB/s, done.
Total 9 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:mdhender/hugocampus.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

I created scripts to automate deployment for testing and production servers. I didn’t need to do this since I plan on using the repository on GitHub to deploy, but it’s interesting to script file pushes.

(Note: “parking” is the alias for the server in my ~/.ssh/config file.)

➜ tools/deploy.sh parking test
📦 Installing extract script on remote host...
📦 Creating tarball (overlay-safe payload)✅ Created tarball: dist/testing/site-20250908-102956.tar.gz
🚀 Uploading to parking ...
✅ Deployed tarball: parking:/var/www/testing.hugocampus.com
🛠️ Extracting on remote server (overlay, no deletions)...
..🛠️ extracting tarball (overlay, no deletions)...
..✅ extract complete (existing files overlaid, nothing deleted).
✅ Extract complete (existing files overlaid, nothing deleted).
📦 Tarball left on server at /var/www/testing.hugocampus.com/site-20250908-102956.tar.gz
🎉 Deployment complete!

You can build out a site without using a theme, but you end up writing the theme in the root level. It is just easier to start out with one.

Create our default theme

I created a new theme, which I called default. Bad choice for a theme name - it will get confusing to talk about later. But it is the “default” theme created by Hugo’s new theme command.

➜ hugo new theme default
Creating new theme in /Users/wraith/hugo/hugocampus.com/themes/default

The new theme command includes some sample content that I don’t want, so let’s remove it.

➜ rm -rf themes/default/content

Then update hugo.toml, Hugo’s configuration file, to use the new theme. While we’re in there, update our baseURL (the path to our production site), and the title for our site.

➜ cat hugo.toml
baseURL = 'https://hugocampus.com/'
languageCode = 'en-us'
title = 'Hugo Campus'
theme = 'default'

Create content

I want the posts for my site to live under blog, so I created folders.

➜ mkdir -p content/blog/post

I created the file you’re reading in there.

➜ ls -l content/blog/posts
total 304
-rw-r--r--@ 1 wraith  staff  139889 Sep  8 09:10 github-repository.png
-rw-r--r--  1 wraith  staff    8520 Sep  8 22:48 initial-setup.md

Building the site

Run hugo server to build the site.

➜ hugo server
Watching for changes in /Users/wraith/hugo/hugocampus.com/{archetypes,assets,content,data,i18n,layouts,static,themes}
Watching for config changes in /Users/wraith/hugo/hugocampus.com/hugo.toml, /Users/wraith/hugo/hugocampus.com/themes/default/hugo.toml
Start building sites …
hugo v0.148.2+extended+withdeploy darwin/arm64 BuildDate=2025-07-27T12:43:24Z VendorInfo=brew


                  │ EN
──────────────────┼────
 Pages            │ 18
 Paginator pages  │  0
 Non-page files   │  1
 Static files     │  1
 Processed images │  0
 Aliases          │  0
 Cleaned          │  0

Built in 10 ms
Environment: "development"
Serving pages from disk
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

That creates the site in the public/ folder.

➜ ls -l public
total 56
drwxr-xr-x   5 wraith  staff    160 Sep  8 13:15 blog
drwxr-xr-x   4 wraith  staff    128 Sep  8 13:15 categories
drwxr-xr-x   3 wraith  staff     96 Sep  8 13:15 css
-rw-r--r--   1 wraith  staff  15406 Sep  8 13:14 favicon.ico
-rw-r--r--   1 wraith  staff   1529 Sep  8 22:49 index.html
-rw-r--r--   1 wraith  staff   1608 Sep  8 22:49 index.xml
drwxr-xr-x   4 wraith  staff    128 Sep  8 13:15 js
drwxr-xr-x   7 wraith  staff    224 Sep  8 13:15 posts
-rw-r--r--   1 wraith  staff   1124 Sep  8 22:49 sitemap.xml
drwxr-xr-x  11 wraith  staff    352 Sep  8 13:15 tags

I am going to deploy using my scripts, so I’ve temporarily added the public/ folder to my .gitignore file. We’ll change that later and use a different deployment process.

Deploying the site

As mentioned earlier, I deploy by running a script.

➜ tools/deploy.sh parking test
📦 Installing extract script on remote host...
extract.sh                                                                                                                100%  777    14.6KB/s   00:00
📦 Creating tarball (overlay-safe payload)✅ Created tarball: dist/testing/site-20250908-225418.tar.gz
🚀 Uploading to parking ...
site-20250908-225418.tar.gz                                                                                               100%  157KB 813.8KB/s   00:00
✅ Deployed tarball: parking:/var/www/testing.hugocampus.com
🛠️ Extracting on remote server (overlay, no deletions)...
..🛠️ extracting tarball (overlay, no deletions)...
..✅ extract complete (existing files overlaid, nothing deleted).
✅ Extract complete (existing files overlaid, nothing deleted).
📦 Tarball left on server at /var/www/testing.hugocampus.com/site-20250908-225418.tar.gz
🎉 Deployment complete!

And now I can view the site in my browser.

Wrapping up

All that’s left is to commit these changes and then deploy to the production web site.

Tags: