For this to work, we are going serve React's static files for the client, and are going to proxy our Express server to /api
.
Disclaimer - Ensure you are the root user, otherwise some of these commands may not work. The Express app also needs to server under a seperate route from the client (e.g /api
), so all backend routes will look like this: /api/signup
.
apt-get update # update packages
apt-get install nginx # install nginx package
nginx # start nginx server
- Go to http://localhost if on a local machine
- Go to http://[PUBLIC IPv4 Address] if remote to machine
curl localhost # see if it is running locally
- Ensure
npm run build
oryarn build
has been executed - Go inside the build directory
cp -r * /var/www/html # move all build files to the html folder
cd /etc/nginx # go to nginx directory
rm nginx.conf # there is a default config file, we are going to overwrite it
vim nginx.conf # edit nginx.conf, use any text editor you wish
Add the following to the file:
http {
server {
# Root of static files
root /var/www/html;
# Serve static files correctly
include /etc/nginx/mime.types;
location / {
# Forward all requests to index.html (get react router working)
try_files $uri /index.html;
}
events {}
- Save and exit the file (Esc then :wq)
nginx -s reload # restart the nginx server
- Your React app should now be working
- Go inside your app's directory
- Ensure
npm i
has been executed npm i pm2 -g # pm2 is a CLI that allows us to run node applications for production
pm2 start (entry point).js # run the express app with pm2
pm2 startup ubuntu # will run the app every time the system boots
cd /etc/nginx
vim nginx.conf
- Add a proxy to the server's port in the server block
http {
server {
# Proxy the backend to /api, this can vary depending on what extenion Express adds to the route
location /api {
# Dependent on the Express server's port
proxy_pass http://localhost:5000;
}
}
events {}
nginx -s reload
- The Express App should now be working
- Ensure your server is hooked up to your domain
- Add the server name to the server block:
server {
# Domain Name
server_name example.com www.example.com;
}
nginx -s reload
- The domain should now be ready, bare in mind this can take up to 48 hours (though it doesn't usually) to take effect
add-apt-repository ppa:certbot/certbot # add the certbot repository
apt-get update
apt-get install python3-certbot-nginx # install certbot for nginx
certbot --nginx -d example.com -d www.example.com
crontab -e # open the cronjobs file
- Add this:
0 12 * * * /usr/bin/certbot renew --quiet
- auto renews the SSL certificate - Close the file
- You should now have SSL
- Append
http2
to this line:listen 443 ssl http2; # managed by Certbot
- Change the http block to look like this:
http {
server {
# Root of static files
root /var/www/html;
# Serve static files correctly
include /etc/nginx/mime.types;
# Domain Name
server_name example.com www.example.com;
location / {
# Only allow these HTTP methods
limit_except GET { deny all; }
# Forward all requests to index.html (get react router working)
try_files $uri /index.html;
}
# Proxy the backend to /api
location /api {
# Only allow these HTTP methods
limit_except GET POST PUT DELETE { deny all; }
# Dependent on the Express server's port
proxy_pass http://localhost:5000;
}
# Security settings
# Stop sending information about the NGINX server
server_tokens off;
# Prevents DoS attacks
client_body_buffer_size 1k;
# Prevents clickjacking
add_header X-Frame-Options "SAMEORIGIN";
# Only allow HTTPS requests
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
# XSS protection
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header X-XSS-Protection "1; mode=block";
# Below is kept the same
listen 443 ssl http2; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/exple.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
We should now have a working React + ExpressJS site!