Configuring Nginx as a reverse proxy web server (including SSL!!!)
Published: May 2, 2021
Updated: August 11, 2024
Use suitable configurations and publish your web apps like a boss.
Nginx and Apache are two of the most popular http servers. While the latter is more appropriate for dealing with static ../media and has its configuration file based on an XML structure, the former is better suited for handling dynamic press. Its configuration file is based on a JSON-like structure (although it is not a JSON file). Both can serve multiple apps on the same server by providing a reverse proxy approach; in other words, Nginx and Apache can be set up to receive requests from a client and forward each request to a different application running on a server's internal port. Coming from a Ruby on Rails background, I've been using Nginx for many years because it is the most common http server used to serve Rails apps worldwide. Therefore, I have some tips for setting up your Nginx and its configuration file like a boss.
First, let's install it. There are two main ways to install it as a package or use it in a docker container. First things first, to install it as a package on your operating system, assuming you're using an Ubuntu 20.04, type:
$ sudo apt update
$ sudo apt install nginx
Alternatively, to get it running a docker container, there are a lot of docker images throughout the internet for Nginx. Personally, this one is good:
Nginx V.1.19 on Alpine
(Make sure you can run it by passing the nginx. Conf from a volume with docker run -d -p 80:80 --read-only -v $(pwd)/nginx-cache:/var/cache/nginx -v $(pwd)/nginx-pid:/var/run nginx
or `volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro` in a docker-compose.yml file).
If you installed it on Ubuntu, you would be able to run a command to confirm that Nginx is really running by typing service nginx status
on your terminal, accessing "localhost" on your browser, or making a curl request against it.
You can install it on your local or inside a
docker container and you can change a crucial file: nginx. Conf. Here is where the magic happens. In the recommended docker image, you can change a local nginx. The conf version is referenced inside the container through a volume link.
To open your nginx.conf, assuming again that you installed it locally, you can choose your favorite text editor, such as nvim/vim, and open it as a super user because
Nginx requires that:
$ sudo vim /etc/nginx/nginx.conf
Then, you shall find in the first five lines a having the following lines:
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
# ...
In these lines, only taking care of the user name is necessary. Avoid setting it as
"root" or your machine's primary user. It is possible to set a password, but leave it
for another blog post because this is a basic overview. Then, you can go to the
section http { ... }
. You can add only a few new lines, except to the
compressing section, although we will add two server sections. Before discussing the
server sections, let's add some configurations for the compression, making your web
application faster if used correctly. You can add/uncomment a section with some gzip
configurations (be careful not to add ../media files such as .png because they consume
too much CPU time).
# /etc/nginx/nginx.conf
http {
#...
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript;
#...
}
After that you will be able to set up the server sections inside the http parent-section. Considering you would like to provide a https-only site, you need to buy a SSL-certificate and generate the ssl-bundle.crt and .key file (there is another file called trusted.crt, but you are not obligated to add it). This source teaches you how to generate these files if you are using Comodo certificates. Next, you need to reference these files to add two server sections. The first is for receiving http-only requests and redirecting to the https requests on the same server. The second is precisely for handling the https-only requests. In this second server section, we are also adding a Location sub-section to handle the rever-proxy forwarding process to an application running on the port 3001 of your localhost. Therefore, any web application running on the port 3001 will receive requests to the www.myawesomesite.awesome
.
Have a look at the comments.
# /etc/nginx/nginx.conf
http {
#...
##
# SSL Settings
##
server {
listen 80;
listen [::]:80;
server_name example.com www.myawesomesite.awesome;
return 301 https://www.myawesomesite.awesome$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
ssl on;
server_name www.myawesomesite.awesome;
# Here you can see the most important configs for the ssl
ssl_certificate /etc/nginx/ssl/www.myawesomesite.awesome/ssl-bundle.crt;
ssl_certificate_key /etc/nginx/ssl/www.myawesomesite.awesome/www.myawesomesite.awesome.key;
ssl_trusted_certificate /etc/nginx/ssl/www.myawesomesite.awesome/trusted.crt;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:20m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:
ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:
DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:
ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:
ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:
ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:
DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:
DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_stapling on;
ssl_stapling_verify on;
# Some useful setings for the reverse proxy app
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-SSL on;
proxy_set_header X-Forwarded-Proto $scheme;
# Finally, the following lines set up the reverse proxy fom the localtion / to the
# app running in the port 3001
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass "http://localhost:3001/";
}
#...
}
#...
}
If you did everything somewhat, you can validate your nginx.conf, check the logs (optional) and restart Nginx to get the new nginx.conf running. Try the following commands:
$ sudo /usr/sbin/nginx -c /etc/nginx/nginx.conf -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
$ sudo journalctl -xe
$ sudo /etc/init.d/nginx restart
Now, enjoy running your application. Stay tuned for the next "episodes" with more powerful settings to add to your nginx.conf.