Skip to content

Instantly share code, notes, and snippets.

@kocisov
Last active February 3, 2025 07:27
Show Gist options
  • Select an option

  • Save kocisov/2a9567eb51b83dfef48efce02ef3ab06 to your computer and use it in GitHub Desktop.

Select an option

Save kocisov/2a9567eb51b83dfef48efce02ef3ab06 to your computer and use it in GitHub Desktop.
How to setup next.js app on nginx with letsencrypt

How to setup next.js app on nginx with letsencrypt

next.js, nginx, reverse-proxy, ssl

1. Install nginx and letsencrypt

$ sudo apt-get update
$ sudo apt-get install nginx letsencrypt

Also enable nginx in ufw

# after installing nginx!
$ sudo ufw allow 'Nginx Full'

2. Edit our default nginx site file

$ sudo vim /etc/nginx/sites-available/default
Content
# *q is our domain
server {
  listen 80 default_server;
  listen [::]:80 default_server;

  root /var/www/html;
  index index.html index.htm index.nginx-debian.html;

  server_name q*;

  location / {
    try_files $uri $uri/ =404;
  }
  
  # for letsencrypt
  location ~ /.well-known {
    allow all;
  }
}

Restart nginx

$ sudo nginx -t # check syntax errors
$ sudo systemctl restart nginx

3. Setup letsencrypt

# *q is our domain
$ sudo letsencrypt certonly -a webroot --webroot-path=/var/www/html -d *q -d www.q*

Generate Strong DH Group

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Create nginx config file with Strong Encryption Settings

$ sudo vim /etc/nginx/snippets/ssl-params.conf
Content
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;

resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Edit our nginx file

# *q is our domain

# redirect http to https
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name *q www.*q;
  return 301 https://$server_name$request_uri;
}

server {
  # listen on *:443 -> ssl; instead of *:80
  listen 443 ssl http2 default_server;
  listen [::]:443 ssl http2 default_server;

  server_name q*;
  
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  include snippets/ssl-params.conf;

  location / {
    # reverse proxy for next server
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  
    # we need to remove this 404 handling
    # because next's _next folder and own handling
    # try_files $uri $uri/ =404;
  }
  
  location ~ /.well-known {
    allow all;
  }
}

Restart nginx again

$ sudo service nginx restart

4. Setup next.js app

$ yarn build # build our app for production (npm build script: next build)
$ yarn global add pm2 # install pm2 to keep next app alive forever*

# run start/stop
$ pm2 start npm --name "next" -- start # start next app (npm start script: next start)
$ pm2 stop next # for stopping app

We are done

Now you have next.js app up and running on nginx reverse proxy with ssl!

@vlavella

Copy link
Copy Markdown

Thank you very much for this :)

@kidow

kidow commented Jan 4, 2019

Copy link
Copy Markdown

What means 'Edit our nginx file'? what file?

@cdolek

cdolek commented Jan 10, 2019

Copy link
Copy Markdown

@kidow What means 'Edit our nginx file'? what file?

nginx web server configuration file.

On linux based systems usually found at:

/etc/nginx/sites-available/some_name.conf

and may have a symbolic link at (or you can place your config file here as well):

 /etc/nginx/sites-enabled/some_name.conf

@juanslinger

Copy link
Copy Markdown

Great job, you save me hours of work!!!

Just to improve some details, example.com has to be updated for *q

ssl_certificate /etc/letsencrypt/live/*q/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/*q/privkey.pem;

@slavic18

Copy link
Copy Markdown

thanks man!

@js5882

js5882 commented Jan 13, 2020

Copy link
Copy Markdown

It also works for me thanks for the gist.. One thing more which should be the primary thing that we have to open port 443 (https).for the server

@kocisov

kocisov commented Jan 13, 2020

Copy link
Copy Markdown
Author

It also works for me thanks for the gist.. One thing more which should be the primary thing that we have to open port 443 (https).for the server

Well, the sudo ufw allow 'Nginx Full' does that.

@TrejoCode

Copy link
Copy Markdown

Hi, thanks for the help, I can visualize my Web now, but, I can't get the images and styles to load, the 404 error in / img returns to my console. Any suggestions?

@bmisanthropy

Copy link
Copy Markdown

Thank you!

@disaada

disaada commented Jan 26, 2021

Copy link
Copy Markdown

where i should put my next.js app?

@kocisov

kocisov commented Jan 26, 2021

Copy link
Copy Markdown
Author

where i should put my next.js app?

Hello, that does not matter.
You can put the app anywhere you like. Afterwards, if you start it with pm2, Nginx will proxy that app based on the port and local ip.

But maybe /usr/src/app, maybe /var/www/app or even in home folder like ~/app.

@disaada

disaada commented Jan 27, 2021

Copy link
Copy Markdown

Hello, i put my project in home ~/disaada.github.io (is it okk to use this folder name? because its cloned from github) but when pm2 already online and i access it using my domain, its just loading for long time and failed to load the page and said "This site canโ€™t be reached". What sould i do?

@kocisov

kocisov commented Jan 27, 2021

Copy link
Copy Markdown
Author

Yes, the name of the folder is alright as I mentioned before.
If the site can't be reached I would try to change Nginx configuration to a default state with your domain in place and test if it is working correctly with static files (eg. index.html).

If that works then I would also check if Nginx can reach the port of the app that runs in pm2.

@disaada

disaada commented Jan 28, 2021

Copy link
Copy Markdown

My bad. I forgot to add https security group at my cloud server. And now it works! I'm sorry. Big much thank you!

@kocisov

kocisov commented Jan 28, 2021

Copy link
Copy Markdown
Author

No problem, glad you got it resolved.

@chas13

chas13 commented Feb 8, 2021

Copy link
Copy Markdown

Hi there, could anyone help with renewing the let's encrypt certificate, please?

sudo letsencrypt certonly -a webroot --webroot-path=/var/www/html -d mydomain.com -d www.mydomain.com

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: mydomain.com 
   Type:   unauthorized
   Detail: Invalid response from
   https://mydomain.com/.well-known/acme-challenge/kJKsq-0rKw_v9nf3oVLlg7l4xOiRy7nZcBkQyouVxt0
   [51.89.192.19]: "<html>\r\n<head><title>404 Not
   Found</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>404
   Not Found</h1></center>\r\n<hr><center>"

@gigapoc

gigapoc commented May 19, 2021

Copy link
Copy Markdown

Thank you for this ! Really helpful and clear, A+ grade SSL certs !

@Xoffio

Xoffio commented Jun 2, 2021

Copy link
Copy Markdown

By doing this do you lose the performance optimizations of Next.js?
I got this from the official doc:

Before deciding to use a custom server please keep in mind that it should only be used when the integrated router of Next.js can't meet your app requirements. A custom server will remove important performance optimizations, like serverless functions and Automatic Static Optimization.

@kocisov

kocisov commented Jun 3, 2021

Copy link
Copy Markdown
Author

By doing this do you lose the performance optimizations of Next.js?
I got this from the official doc:

Before deciding to use a custom server please keep in mind that it should only be used when the integrated router of Next.js can't meet your app requirements. A custom server will remove important performance optimizations, like serverless functions and Automatic Static Optimization.

Hello, no that is not the case, we are not using custom server in this guide.

@dryleaf

dryleaf commented Jun 18, 2021

Copy link
Copy Markdown

@kocisov, Could you please explain why we need to do 2. Edit our default nginx site file step? Seems like a duplicate from step 3 nginx file, as same configuration is present there.

@kocisov

kocisov commented Jun 18, 2021

Copy link
Copy Markdown
Author

@kocisov, Could you please explain why we need to do 2. Edit our default nginx site file step? Seems like a duplicate from step 3 nginx file, as same configuration is present there.

Hello, we do the second step because we need to tell Nginx that we want to serve on our domain before running letsencrypt.
This configuration file is also quite different in 3rd step because it's after generating certificates and we also set up proxy pass there.

@brunodesde1987

Copy link
Copy Markdown

Thank you! ๐Ÿ™

@kazi-shahin

Copy link
Copy Markdown

Really useful. Thank you

@truongnc1997

truongnc1997 commented Sep 2, 2021

Copy link
Copy Markdown

Thanks you man

@ouweiya

ouweiya commented Dec 10, 2021

Copy link
Copy Markdown

My suggestion is to replace http://localhost:3000 with http://127.0.0.1:3000.

It may cause an error.

connect() failed (111: Connection refused) while connecting to upstream,

@MehulJain2616

MehulJain2616 commented Jun 21, 2022

Copy link
Copy Markdown

it's working on safari. but not on chrome. please help

@JuanQuenga

Copy link
Copy Markdown

This worked for me thank you ๐Ÿ™

@escarlson

Copy link
Copy Markdown

Other than needing to use a newer version of node this concluded my hours of troubleshooting. Thank you!

@Dan-Levi

Copy link
Copy Markdown

Thanks! Just what i needed :-)

@maorgur

maorgur commented Aug 2, 2024

Copy link
Copy Markdown

Worked great!, there are a lot of guides on the internet that doesn't work but this one does!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment