Enabling HTTPS on Hugo with an Nginx Reverse Proxy

Sure, a website works fine over HTTP, but the browser still warns that it’s not secure, which is a bit of a buzzkill. Here’s a quick rundown of how to serve your Hugo site over HTTPS by putting an Nginx reverse proxy in front of it. The content is borrowed from Sulv’s post Deploying a Hugo blog to a Tencent Cloud lightweight server

Steps

1. Install Nginx

First, make sure port 80 and port 443 are not in use. Check them with the commands below; if no output is shown, the ports are free.

1
2
sudo netstat -tulpn | grep :80
sudo netstat -tulpn | grep :443

On Debian-based systems, install Nginx with the command below. For other systems, a quick Baidu or Google search should do.

1
sudo apt update && apt upgrade && apt install nginx

Set Nginx to start on boot:

1
sudo systemctl enable nginx

Start Nginx:

1
sudo systemctl start nginx

Check the status of Nginx (if something is wrong, check whether the port is occupied):

1
sudo systemctl status nginx

That’s it — Nginx is now installed.

2. Other Things You’ll Need

  • Some cloud providers enable a firewall by default, so remember to open ports 80 and 443.
  • Run hugo --gc in the root directory of your blog to generate the static website files, which you’ll need later; the generated files are in the ./public directory.
  • Apply for an SSL certificate. Buying a domain usually comes with a free one-year certificate; renewals can be pricey, but you can just apply for another free one and swap out the old one. You can also look for free SSL certificate providers — a quick online search will find plenty, so I won’t go into detail. Nginx needs two certificate files, ending in .crt and .key.

3. Configure the nginx.conf File

This file is generated in the /etc/nginx directory by default, and you should also move the SSL certificate you applied for above into this directory.

The configuration is provided by Sulv, as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# First place to configure: change the user to root, otherwise you may not have permission
user root;

worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
    
    # http configuration
    server {
        # Second place to configure: port 80 access
        listen       80 default_server; 
        listen       [::]:80 default_server;
        
        # Third place to configure: the domain name
        server_name www.sulvblog.cn;
        # Hide the version number
        server_tokens off;
        # Automatically redirect from http to https
        rewrite ^(.*) https://$server_name$1 permanent;

        # Fourth place to configure: point this to the public folder
        root /home/public;
        
        include /etc/nginx/default.d/*.conf;
        
        # Fifth place to configure
        location / {
            root /home/public;
            index  index.html index.htm;
        }
        
        # Sixth place to configure
        error_page 404 /404.html;
        location = /40x.html {
            root   /home/public;
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
    
    # https configuration
     server {
         listen 443 ssl;
         # Seventh place to configure
         server_name www.sulvblog.cn;
         root /home/public;
         
         # Eighth place to configure
         ssl_certificate /etc/nginx/1_sulvblog.cn_bundle.crt;
         ssl_certificate_key /etc/nginx/2_sulvblog.cn.key;
         
         # Ninth place to configure: you can follow my way of writing
         ssl_session_timeout 10m;
         ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
         ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
         ssl_prefer_server_ciphers on;
         
         # Tenth place to configure
         error_page 404 /404.html;
         location = /404.html {
              root /home/public;
         }

         include /etc/nginx/default.d/*.conf;
     }

}

Once you’ve made all the changes at the marked spots above, remember that the static website files generated by Hugo are in the ./public directory mentioned earlier, and make sure you don’t get the SSL certificate’s path and filename wrong.

Test whether the configuration is correct:

1
sudo nginx -t

Then reload the configuration file with Nginx:

1
sudo nginx -s reload

Check the running status of Nginx:

1
sudo systemctl status nginx

Restart the Nginx service:

1
sudo systemctl restart nginx

The setup is now complete, and you can visit your blog to see the result. Going forward, after you finish writing a post, just regenerate the static website files and the update will show up on your site.

References