How To Setup Hugo On VPS

Nov 7, 2018 18:16 · 2723 words · 13 minute read hugo blog setup tutorial vps

Choosing blog engine

When I first started thinking about running a blog I wanted to write it on my own. Probably many developers have the same idea.

The next project! I will create all the features I need, and no more. It will be perfect.

But after some time thinking about it I knew I need to start as fast as possible and I shouldn’t build my own blog server. There is no need. Blog isn’t the most interesting development problem, and writing it wouldn’t be as fun as it seemed at first.

So I decided to choose something that already exists. I had bad experience with WordPress in the past, but it was a really long time ago. I am sure it’s much better now. However I wanted to try something different. I knew there is a product out there that I would like. I just need to do a research and it didn’t take to much time when I found Hugo, static site generator written in Go. I was amazed by this project and it looked exactly what I need. However creating first post requires some preparation and I didn’t even have server yet. I have chosen Medium for my first two blog posts. I knew I will change it later, but I really felt the need to make the first post right away.

I am after my first two blog posts, and it’s time to dump Medium away. Someone might ask why I am not staying with Medium. I have just a couple of reasons.

  1. I really don’t like experience of reading Medium Post on mobile device when I’m not logged in. That top bar, that doesn’t disappear is extremely annoying. I don’t want this on my site. I know that I could login, but that limits me to reading 3 posts daily. I’m not commenting about this business decision, it’s just not for me.

  2. I don’t have much expectations, but I want to have small information of next deadline at main page. With Medium it’s not possible

  3. I just want to have Blog on my server, it feels right to me and it’s just my preference.

  4. Medium doesn’t support RSS

So I have decided to use Hugo. Now I need a domain and place to host my blog. I have bought a domain and VPS at DigitalOcean. VPS is a bit of an overkill. I could easily host my blog on something like Github Pages but I wanted to use VPS for more than just blog.
(I just like to tinker with servers.)

As a summary of my task, I decided to create this tutorial.

How to setup Hugo Blog on your own VPS

In the tutorial I will be using following syntax to specify where should be command run:

  • as root at the server (vps)#
  • as user at the server (vps)$
  • as user at local machine $


To setup Hugo on your own VPS like I did you should have:

  • Server
  • Domain

I got my domain at OVH and VPS at DigitalOcean will be my server. If you have you domain or server from different provider there might be some minor differences. Most of this tutorial should still apply. If you have any questions, feel free to contact me for help.

Setting up server

Create Droplet

To create new VPS at DigitalOcean, login and at right site of upper panel click
Create -> Droplets


Choose your operating system. I suggest Ubuntu, it’s the easies one and has most of the basic configuration already done.


For blog running on Hugo, the smallest size should be more than enough.


Choose the region of the server. I have chosen the one closest to me.


Typed hostname, it will be kind of a name for your server. Then click Create


After that, DigitalOcean will start automated droplet setup. When they finish you will receive an e-mail with root password and server ip address.

Configure Droplet

The first thing I always do on new machines is:

  • Create new user
  • Change root password
  • Disable ssh for root and change ssh port
  • Setup SSH keys
  • Configure basic firewall

I suggest you do the same.
To do all of these things You need to be connected to the server.
If you are on Mac/Linux just open terminal and type:

$ ssh root@server_ip

You will be asked for password - paste it from the e-mail you got from DO.
If you are on Windows you will have to use Putty.

Change root password

When you connect to the VPS for the first time you might be asked to change password. If you don’t just run passwd command.

(vps)# passwd root

I personally don’t use sudo on my servers. If my user will be compromised I don’t want the attacker to have access to root. Instead I change root password to some long generated string that I store in my password manager.

Create new user

To create new user use command adduser followed by username.

(vps)# adduser konradb

Disable ssh for root and change ssh port

This is quite important, gives next layer of protection. If anyone will try to bruteforce on to your server they try to use root username. I always disable possibility to connect to VPS using root. If I need root I will connect using my normal user, then change to root directly on the server. Settings for SSH are in /etc/ssh/sshd_config. I suggest editing it with nano.

(vps)# nano /etc/ssh/sshd_config

To disable ssh for root, find and comment out PermitRootLogin yes.

# Authentication:
LoginGraceTime 120
#PermitRootLogin yes
StrictModes yes

Then I suggest changing port from default 22 into something different like 55555. In the same file find Port 22 and change to Port 55555.

# What ports, IPs and protocols we listen for
Port 55555
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
Protocol 2

To save changes press CTRL-X followed by y.

To apply these changes reload sshd service

(vps)# systemctl reload sshd

Setup SSH keys

I like to setup ssh keys. Not only they are more comfortable but also more secure.
If you have never done that you need to generate keys on your local machine.
If you use Mac Os/Linux just type:

$ ssh-keygen

For Windows checkout PuttyGen

The default settings will create private and public key in ~/.ssh

  • Private Key id_rsa
  • Public key

To make it possible to login into new droplet using these keys we need to paste the public key into the server. It can be done manually into the ~/.ssh/authorized_keys file or using command

$ ssh-copy-id konradb@server_ip -p 55555

Now it should be possible to login without typing password in.

I connect to my server using ssh many times and I like to add ip to my local machine config.
To do it, edit or create ~/.ssh/config file, and type following

Host droplet
HostName server_ip
Port 55555
User konradb

Now it should be possible to connect to your server just by typing

$ ssh droplet

Configure basic firewall

In the past, whenever I had created new server I was copying my long list of iptables rules. Now with Ubuntu UFW it’s much easier. If you just want basic firewall rules, it’s a good tool.

Connect to droplet, change user to root using su command. Then use ufw

(vps)# ufw allow 55555/tcp

This will create rule in iptables that allows to connect to ssh using 55555 port. If you have changed ssh port to something different, change accordingly. To apply the changes and start firewall use

(vps)# ufw enable

Be sure to use correct port. If you use different port than the one you setup in SSH config, you won’t be able to connect to VPS.
If it happened to you, don’t worry you can always use console through DigitalOcean panel.

You can check ufw active rules using

(vps)# ufw status

It should look like this

Status: active

To                         Action      From
--                         ------      ----
55555/tcp                  ALLOW       Anywhere
55555/tcp (v6)             ALLOW       Anywhere (v6)


After creating server and obtaining ip address it’s good to point domain to it.
I have bought my domain at OVH so I’ll show how to do it on their web panel.

At many websites you might find information to point NS records to DigitalOcean. What it does is makes DigitalOcean place that handles all the other records of your domain. I personally don’t like to do this. I use my domain for e-mail address too, so I’d have to configure MX at DigitalOcean.
If I ever want to migrate my blog, let’s say to AWS, I’d have to change NS records to AWS and then at AWS configure MX again.

I like to leave OVH as my nameserver provider. On their panel I set A records that points to ip of VPS, as well as my MX records for e-mail. If I decide to change hosting of my blog, all I have to do is to change A record to the new ip address. This way I don’t risk loosing any e-mail while doing it.

Configure A record at OVH

At OVH Web Panel choose your domain from menu


Go to DNS Zone tab


A right side there should be button to add new record


Clicking it brings up this window where you should choose A record.


At the second step of adding the record, there is an option to set sub-domain.
If you have domain and you would like to have blog under you have to insert blog into sub-domain field.
I want my blog to be under so I will leave that field empty.
As target paste ip address of the VPS. Click Next.


And then confirm


Just like OVH informs us on the last step, the dns propagation might take some time.



I’m using Mac, and if you have Mac with Homebrew it’s straight forward

$ brew install hugo

If you have other system, checkout Hugo documentation

Create new site

To create new project use hugo new site command followed by name.

$ hugo new site blog

This will create new folder blog with following content

├── archetypes
│   └──
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes

The most important file at the beginning is config.toml. It contains most of the configuration. When created, it contains only three lines.

baseURL = ""
languageCode = "en-us"
title = "My New Hugo Site"

Change them according to your preferences.

Full list of configuration options you can find at:

Create first post

Let’s create first post so we could see Hugo in action. In main folder of blog run following command:

$ hugo new posts/

This will create folder under content called posts. It’s the place where all new posts will be stored.

Open the newly created file content/posts/ Content should be similar to this:

title: "First Post"
date: 2018-11-07T10:05:25+01:00
draft: true

Add some content for the first post.

title: "First Post"
date: 2018-11-07T10:05:25+01:00
draft: true
# Lorem Ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas nec blandit enim, vehicula bibendum velit. Sed dignissim, risus id suscipit tempus, justo tortor dictum lacus, nec euismod ipsum nunc vel odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus interdum, turpis at ultricies ultricies, purus tellus feugiat nisi, at faucibus nibh magna et ligula. Aliquam eget tortor turpis. Donec vulputate, ex vel pharetra aliquet, magna augue mollis mi, in euismod urna justo ac sapien. Duis volutpat malesuada molestie. Donec libero erat, hendrerit a nunc non, accumsan porttitor erat. Mauris consequat nunc nunc, quis accumsan odio facilisis sed. Sed pulvinar fringilla nunc, et faucibus neque ullamcorper ac. Sed porta suscipit quam, non maximus eros rhoncus eu. Duis congue justo quam, sit amet pellentesque nisl volutpat id.

Installing theme

To display content of blog, you need to choose theme. There is quite big repository of them at

After choosing one of them:

  • open your console and navigate to your project directory.
  • initilize new git repository
  • add theme as submodule
$ cd blog
$ git init
$ git submodule add themes/ananke

This will fetch the theme repository into themes/ananke.

Now open config.toml and add theme option.

baseURL = ""
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"

Run Local Development Server

To see the progres we have done so far, you can run local development server. This will allow you to preview the blog.

$ hugo server -D
                   | EN  
  Pages            | 10  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     |  3  
  Processed images |  0  
  Aliases          |  1  
  Sitemaps         |  1  
  Cleaned          |  0  

Total in 13 ms
Watching for changes in /tmp/blog/{content,data,layouts,static,themes}
Watching for config changes in /tmp/blog/config.toml
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address
Press Ctrl+C to stop

In the output you can see link to http://localhost:1313/. The port may vary. When you open that url in a browser, you should see something like this:


Configure Nginx At VPS

To serve your blog at VPS you need to setup http server. Nginx is a good option.

Login to your droplet

$ ssh droplet

Switch user to root.

(vps)$ su

Install nginx

Nginx should be already installed at Ubuntu, but if its not run following commands:

(vps)# apt update
(vps)# apt install nginx
  • apt update updates package repository
  • apt install nginx installs nginx

Add nginx to allowed in firewall

We have already setup ufw firewall and added ssh rules. Now we have to add rules for nginx. You can list available rules for applications running:

(vps)# ufw app list
Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS

Let’s choose Nginx HTTP since we haven’t setup https yet.

(vps)# ufw allow 'Nginx HTTP'

You can verify current settings by:

(vps)# ufw status
Status: active

To                         Action      From
--                         ------      ----
55555/tcp                  ALLOW       Anywhere
Nginx HTTP                 ALLOW       Anywhere

I like to additionally run

(vps)# ufw reload

to reload the firewall.

Nginx config

At first let’s create new folder for blog. Login back to your user.

(vps)# su konradb

Go to home directory

(vps)$ cd ~/

Create blog folder

(vps)$ mkdir blog

And login back to root

(vps)$ su

Now let’s create nginx configuration file for blog. Go to /etc/nginx/sites-available

(vps)# cd /etc/nginx/sites-available

Create the blog file running:

(vps)# touch blog

Now edit it with nano

(vps)# nano blog

Type following config

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    root /home/konradb/blog;
    index index.html;

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

Be sure to replace, with your domain name and /home/konradb/blog with your username.

Now to activate this config create symlink to sites-enabled:

(vps)# ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/blog

Reload nginx using

(vps)# systemctl reload nginx

Now nginx should be hosting files that you put in your ~/blog folder. So let’s upload blog there.

Simple Deploy

I will show you the most basic way to deploy Hugo. Just by copying files that Hugo creates into previusly created folder at VPS.

Be sure that your blog post has draft: false in the header. Otherwise Hugo won’t include it in output files for deployment.

In blog folder at your local machine run:

$ hugo

This will create new folder public with all files required for deployment. Lets copy them to VSP. You can do it however you want.
You could use FileZilla program, that allows to connect to remote server in an easy way using SSH credentials.

Since we have already configured ssh we can use scp command.

$ scp -r public droplet:~/blog

This will copy public folder, with all subfolders into ~/blog at VPS.

If everything went well, you should be able to open your website!

If you have any problems, let me know and I’ll try to help you.

It’s a just a basic configuration. I decided to split this long tutorial into two parts.
In the next 5 days (12.11) I will post extended tutorial that will include:

  • How to handle images
  • Seting up Github repository
  • Configuration of auto deployment using CircleCI
  • Setting up Let’s Encrypt to support https
  • Adding Disqus
  • Adding Google Analytics

And maybe something more.

tweet Share