反向代理Github Pages启用HTTPS

Due to Github Pages not supporting custom domain HTTPS, I spent some time today setting up a reverse proxy from Nginx to Github Pages on a VPS. I used a certificate issued by Let’s Encrypt to achieve full HTTPS for the entire site (all external resource links were also changed to HTTPS). Here’s a simple record of the process.

Issuing Certificates

First, add one (or several) A records for the domain you want to issue a certificate for, pointing to your VPS.
Then, pull certbot from Github to issue the certificate, along with the Certbot User Guide:

1
2
$ git clone git@github.com:certbot/certbot.git
$ cd certbot

At this point, stop Nginx and any program using ports 80 and 443:

1
/etc/init.d/nginx stop

Next, use certbot to issue the certificate:

1
$ ./certbot-auto certonly --standalone -d example.com -d www.example.com

Replace example.com with your domain, and execute it in the directory where you pulled certbot. For more parameters, please refer to the certbot usage introduction. If successful, you will see the following prompt:
let-successfuly
It indicates that a certificate has been issued for your domain and saved in the directory /etc/letsencrypt/live/imzlp.com/.

Configuring Nginx Reverse Proxy for Github Pages

Then, edit the Nginx configuration (Nginx’s configuration file is in /etc/nginx/conf.d):
Create a configuration file named after your domain, for example, imzlp.com.conf:

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
server {
listen 80;
listen [::]:80;

server_name imzlp.com;
rewrite ^(.*) https://$server_name$1 permanent;

location / {
proxy_pass https://imzlp.com;

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 443 ssl;
ssl on;
server_name imzlp.com;

ssl_certificate /etc/letsencrypt/live/imzlp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/imzlp.com/privkey.pem;

location / {
proxy_pass https://151.101.73.147;

proxy_redirect off;
proxy_set_header Host imzlp.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Note that in the HTTPS server configuration, proxy_pass cannot be filled directly with https://xxx.github.io, as it will result in a Github 404 error. You must first ping the IP of xxx.github.io, then give Github Pages a custom domain, and finally fill in the IP you pinged above in proxy_pass, changing proxy_set_header to the configured custom domain.

You can also reverse proxy another domain that has had A records added and certificates issued, using the same method, but proxy_set_header must be filled with the custom domain specified in Github Pages to avoid a Github 404 error:
Similarly, create another configuration file named after your domain, like zhalipeng.com.conf:

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
server {
listen 80;
listen [::]:80;

server_name zhalipeng.com;
rewrite ^(.*) https://$server_name$1 permanent;

location / {
proxy_pass https://zhalipeng.com;

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 443 ssl;
ssl on;
server_name zhalipeng.com;

ssl_certificate /etc/letsencrypt/live/zhalipeng.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/zhalipeng.com/privkey.pem;

location / {
proxy_pass https://151.101.73.147;

proxy_redirect off;
proxy_set_header Host imzlp.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Then save and exit, and reload Nginx configuration.

1
$ service nginx reload

Force HTTPS in Hexo
Taking Hexo-Next-Theme as an example, add the following code within <head></head> of next/themes/layout/_layout.swig:
Since I’m using two domains above, I need to check if it matches either one:

1
2
3
4
5
6
<script type="text/javascript">
var hostA = "imzlp.com";
var hostB = "zhalipeng.com";
if (((hostA == window.location.host)||(hostB == window.location.host)) && (window.location.protocol != "https:"))
window.location.protocol = "https";
</script>

Make sure to change it to your own domain.

Allow multiple domains to obtain unified comment content from Gitment
Modify the content of gitment.swig and add the following code within var gitment = new Gitment({}):

1
id:window.location.pathname,

After adding:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% if page.comments and theme.gitment.enable and theme.gitment.username and theme.gitment.repoName and theme.gitment.client_id and theme.gitment.client_secret %}
{% set username = theme.gitment.username %}
{% set repoName = theme.gitment.repoName %}
{% set client_id = theme.gitment.client_id %}
{% set client_secret = theme.gitment.client_secret %}
<link rel="stylesheet" href="https://imsun.github.io/gitment/style/default.css">
<script src="https://imsun.github.io/gitment/dist/gitment.browser.js"></script>
<script>
var gitment = new Gitment({
id:window.location.pathname,
owner: '{{username}}',
repo: '{{repoName}}',
oauth: {
client_id: '{{client_id}}',
client_secret: '{{client_secret}}'
}
});
gitment.render('gitment_container');
</script>
{% endif %}

Automatically Renew Certificates

Since the validity of Let’s Encrypt’s certificates is 90 days, it’s quite unpleasant to have to manually execute the certbot issuing command when they expire.
You can use the following method to automatically issue the certificate, essentially a sh script that can be done in one line, also using certbot:

1
2
# Note that the path for certbot-auto needs to be set to where you stored it
$ /root/certbot/certbot-auto renew --pre-hook "service nginx stop" --post-hook "service nginx reload" --quiet

Note: The --quiet parameter means not outputting content to the console and generating logs.
Then, you can use crontab to create a scheduled task.

1
2
# Edit the current user's crontab
$ crontab -e

Enter the following code (also remember to change the path for certbot to where you stored it):

1
0 0 1 * * /root/certbot/certbot-auto renew --pre-hook "service nginx stop" --post-hook "service nginx reload" --quiet

Note: The renewal command will only request a new certificate if it detects that the renewal time is less than 30 days. Otherwise, it will not regenerate.

References

Changelog

2018.02.05

  • Added some detailed descriptions
  • Added Automatic Certificate Renewal
The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:反向代理Github Pages启用HTTPS
Author:LIPENGZHA
Publish Date:2017/09/07 20:49
Update Date:2018/02/05 13:26
World Count:2.9k Words
Link:https://en.imzlp.com/posts/18841/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!