Jses.ioby Shaojiang

Deploy multiple domains with http3 support with Nginx

Shaojiang

Date:

Deploy multiple domains with http3 support with Nginx

1. Introduction

I am using Nginx happily to deploy a Next.js application https://myex.ai on the server (Linode cloud server). At current stage, I run yarn build & yarn start to launch the Next.js server in production mode (port 3000 by default), then Nginx acts as a reverse proxy to manage the incoming requests. It handles the SSL certificates, caching, HTTP/3 configuration, etc., then forwards the requests to the Node.js server at port 3000. We can imagine Nginx is a gatekeeper to handle requests first. For better performance, I configure Nginx to serve through HTTP/3. Please check this article for the HTTP/3 configuration.

The Nginx conf file is like:

1server {
2 listen 80 default_server;
3 listen [::]:80 default_server;
4
5 location / {
6 return 301 https://$host$request_uri;
7 }
8}
9
10server {
11 listen 443 quic reuseport;
12 listen 443 ssl;
13 #listen [::]:443 ssl;
14 server_name myex.ai;
15 ssl_certificate /root/myex_ai.crt;
16 ssl_certificate_key /root/myex-ssl.key;
17 ssl_protocols TLSv1.2 TLSv1.3;
18 quic_retry on;
19 ssl_early_data on;
20
21 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
22 ssl_prefer_server_ciphers off;
23 ssl_stapling on;
24 ssl_stapling_verify on;
25 resolver 127.0.0.1;
26
27 location / {
28 add_header Alt-Svc 'h3=":$server_port"; ma=86400';
29 add_header X-Quic $server_protocol always;
30 add_header Strict-Transport-Security max-age=15768000;
31 proxy_pass http://localhost:3000;
32 proxy_http_version 1.1;
33 proxy_set_header Upgrade $http_upgrade;
34 proxy_set_header Connection "upgrade";
35 proxy_set_header Host $host;
36 proxy_cache_bypass $http_upgrade;
37 # root /usr/share/nginx/html;
38 # index index.html index.htm;
39 }
40 error_page 500 502 503 504 /50x.html;
41 location = /50x.html {
42 root /usr/share/nginx/html;
43 }
44}
45

Now I have another site, let's say, jscoder.io, and I would like to deploy it on the same server in the similar way.

2. Jscoder.io

Create a new next.js app and push the GitHub repo at https://github.com/agongdai/nextjs-performance. Clone the repo to the cloud server, then run:

1$ yarn install
2$ yarn build
3$ yarn start --port 3001

Since port 3000 has been occupied by https://myex.ai, here jscoder.io uses port 3001.

3. Nginx conf

Now we want to add Nginx as the reverse engine to serve jscoder.io at port 3001. The easy way is simply copy the myex.ai Nginx conf file for jscoder.io. Run sudo cp /etc/nginx/conf.d/myex.ai.conf /etc/nginx/conf.d/jscoder.io.conf, then change the content:

1server {
2 listen 80; # default_server;
3 listen [::]:80; # default_server;
4
5 location / {
6 return 301 https://$host$request_uri;
7 }
8}
9
10server {
11 listen 443 quic; # reuseport;
12 listen 443 ssl;
13 server_name jscoder.io;
14 ssl_certificate /root/jscoder_io.crt;
15 ssl_certificate_key /root/jscoder-ssl.key;
16 ssl_protocols TLSv1.2 TLSv1.3;
17 quic_retry on;
18 ssl_early_data on;
19
20 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
21 ssl_prefer_server_ciphers off;
22 ssl_stapling on;
23 ssl_stapling_verify on;
24 resolver 127.0.0.1;
25
26 location / {
27 add_header Alt-Svc 'h3=":$server_port"; ma=86400';
28 add_header X-Quic $server_protocol always;
29 add_header Strict-Transport-Security max-age=15768000;
30 proxy_pass http://localhost:3001;
31 proxy_http_version 1.1;
32 proxy_set_header Upgrade $http_upgrade;
33 proxy_set_header Connection "upgrade";
34 proxy_set_header Host $host;
35 proxy_cache_bypass $http_upgrade;
36 # root /usr/share/nginx/html;
37 # index index.html index.htm;
38 }
39 error_page 500 502 503 504 /50x.html;
40 location = /50x.html {
41 root /usr/share/nginx/html;
42 }
43}

In this conf, remember to:

  1. change server_name to jscoder.io.

  2. change SSL certificates to jscoder.io certificates. Refer to this article for SSL certificate application and deployment: A complete guide to make your first website online with HTTPS.

  3. change reverse proxy port from 3000 to 3001.

Moreover, at line 2 and 3, remove the default_server setting. This directive defines the default server for port 80, which cannot have multiple. Otherwise, we will get error:

1root@localhost:~# nginx -t
2nginx: [emerg] a duplicate default server for 0.0.0.0:80 in /etc/nginx/conf.d/myex.ai.conf:2
3nginx: configuration file /etc/nginx/nginx.conf test failed

Again more, at line 11, remove the reuseport setting. Otherwise, we get the error:

1root@localhost:~# nginx -t
2nginx: [emerg] duplicate listen options for 0.0.0.0:443 in /etc/nginx/conf.d/myex.ai.conf:16
3nginx: configuration file /etc/nginx/nginx.conf test failed

For more details, please check this GitHub issue: Nginx configures multiple sites to share 443/udp ports.

Remember to reload or restart the nginx server: $ sudo service nginx restart. Then you can visit both https://myex.ai and https://jscoder.io.