Skip to main content

Nginx Reverse Proxy in front of SpringBoot

In the last post we were doing some exercises about how to deploy a VueJS app with SpringBoot using SSL, but exposing the whole backend with SSL is not recommended because of security things, the best thing to do is let the backend running just in localhost mode and using this powerful tool which Nginx gives us the Reverse Proxy to be in front the SpringBoot app int this case.

What is a reverse proxy?
A reverse proxy is a server that sits in front of web servers and forwards client (e.g. web browser) requests to those web servers. Reverse proxies are typically implemented to help increase security, performance, and reliability.

let's suppose you've got in your backend 2 endpoints running through the port 7075:

/docker/itemspaginados/0
/docker/createitems/

so if the backend is up and running you can run in the server
curl http://127.0.0.1:7075/docker/itemspaginados/0 you should get back something like:

{"totalItems":"5","totalPages":"1","items":[{"name":"itemanem","id":"1"},{"name":"itemanemdos","id":"2"},{"name":"itemanemtres","id":"3"},{"name":"newone","id":"4"},{"name":"none1","id":"5"}]}

now, the next step would be doing the same thing but using a web browser so that this is the way the frontend is going to get communicated with the backend



as you could see in this URL http://hypercaloricmassmuscle.com/docker/itemspaginados/0 
I did not write anywhere the port so that Nginx behind is the one is setting the port by me, is making the reverse proxy, so these are the Nginx settings to set in the /etc/nginx/nginx.conf 
by the purpose of this example, it is an Nginx running on a Linux Centos 7
it is just being set up just with the basic things, a frontend VueJS app located at /usr/share/nginx/html/dist
the frontend settings are the same for VueJS or ReactJS, now we've got

location /api {
         proxy_pass http://localhost:7075;
}

that is the piece of code which is redirecting us the request done in the browser without the need to specify the port so that Nginx will do http://127.0.0.1:7075/api/itemspaginados/0 for us behind

and all of this is possible because we are enabling some X-Forwarded HTTP headers

X-Forwarded-For forwards request's origin IP address (address of user's computer). It is useful in case of a logging origin of a request.

X-Forwarded-Proto passes protocol (http, https, ...) of public address. For example for site https://hypercaloricmassmuscle.com a https value is passed to Spring application. Without it, Spring application would not be able to generate correct absolute URLs.

X-Forwarded-Port passes port number (80, 443, ...) of public address. Even though this configuration is not mentioned in Spring Boot's documentation it is needed by some utilities. For example in ServletUriComponentsBuilder.initFromRequest() method port number is used to determine whether application is running securely.

Host re-sets a host header to a public domain name like hypercaloricmassmuscle.com from a local domain name (usually localhost). Again, it is useful for generating correct absolute URLs.


server {

      listen       80 default_server;
     
      server_name  _;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header HOST $http_host;


      root   /usr/share/nginx/html/dist;
      location / {
          root /usr/share/nginx/html/dist;
          try_files $uri /index.html;
      }

      location /docker {

        proxy_pass http://localhost:7075;

      }

}

if you've got SELinux activated do not forget to run this boolean value for httpd network connect to on (Nginx uses the httpd label).

setsebool httpd_can_network_connect on

To make the change persist use the -P flag.

setsebool httpd_can_network_connect on -P

You can see a list of all available SELinux booleans for httpd using

getsebool -a | grep httpd

if "502 Bad Gateway" error throws on centos api url for api gateway proxy pass on Nginx, run following command to solve the issue

setsebool -P httpd_can_network_connect 1

and that's it, now that you can access your backend through the web browser, you can send or get the requests using VueJS, ReactJS, Angular or whatever frontend you want.


Using Nginx Reverse Proxy with SSL

now, what about if you want to use SSL for your backend and frontend application and what about if you want to use Namecheap or Sectigo SSL certificate, or any other?

it is an easy task just create another server tag and add something like this:



server {

      listen 443 ssl;

      ssl_certificate /etc/ssl/cert-chain.crt;
      ssl_certificate_key /etc/ssl/server.key;


      server_name  https://hypercaloricmassmuscle.com;

      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header HOST $http_host;


      root   /usr/share/nginx/html/dist;
      location / {
        root /usr/share/nginx/html/dist;
          try_files $uri /index.html;
      }

      location /docker {

        proxy_pass http://localhost:7075;

      }


    }


Using Nginx Reverse Proxy behind an AWS Load Balancer

Let's supposed you've got your AWS SSL certificate and your load balancer up and running, in order to redirect the HTTP 80 port traffic to HTTPS 443 SSL, just add this to your nginx.conf server tag

 if ($http_x_forwarded_proto = 'http'){
        return 301 https://$host$request_uri;
 }



server {

      listen       80 default_server;
     
      server_name  _;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header HOST $http_host;

      if ($http_x_forwarded_proto = 'http'){
        return 301 https://$host$request_uri;
      }


      root   /usr/share/nginx/html/dist;
      location / {
          root /usr/share/nginx/html/dist;
          try_files $uri /index.html;
      }

      location /docker {

        proxy_pass http://localhost:7075;

      }

}

now wit that setting your application will be redirected to the 443 HTTPS

Adding multiple microservices with Nginx Reverse Proxy behind

what about if you've got several microservices and you want to do the same process with Nginx?
you just have got to add them like this,

let's suppose you have got 2 other more jars running,  one listening from the port 7075 and the another one from the port


server {

      listen       80 default_server;
     
      server_name  _;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header HOST $http_host;

      if ($http_x_forwarded_proto = 'http'){
        return 301 https://$host$request_uri;
      }


      root   /usr/share/nginx/html/dist;
      location / {
          root /usr/share/nginx/html/dist;
          try_files $uri /index.html;
      }

      location /docker {

        proxy_pass http://localhost:7075;

      }

      location /api2 {

        proxy_pass http://localhost:7079;

      }

      location /api3 {

        proxy_pass http://localhost:7077;

      }

}
remember you can reload changes on Nginx without restarting the whole Nginx with 
service nginx reload




I have uploaded to GitHub https://github.com/juandavidmarin368/nginx_reverse_proxy the project in 4 folders, 

1: PersisterDataDocker
2: api2
3: api3
4: VueJS_Front

to compile the VueJS project run npm run build
it will generate a dist folder, zip it and take it to the server


Comments

Popular posts from this blog

How to deploy a VueJS App using Nginx on Ubuntu

There are thousands of blogs and websites out there explaining how to do a hello world and how to start with VueJS, but in this little post, I’m just going to be explaining how to do deploy a VueJs app after you have run the command through the CLI npm run build . So when you run the command npm run build a dist folder is created and that folder’s got the essential .js files to run our app, when we want to run our app on an Nginx server by default the vue-router is not going to work well so that Nginx does not come ready to work by default with a VueJs app This is basically for a Linux Ubuntu distribution if you’ve got any other Linux distribution just pay attention where is going to be set the www/html folder and the Nginx settings so that this is useful for any Linux distribution  Install and configure nginx sudo apt install nginx Double check to make sure the nginx service is running with command service nginx status, then open your browser and enter url

How to secure SpringBoot with SSL and Tomcat or Undertow

when we are going to take our applications to production mode, we must have an SSL certificate for the FrontEnd and   BackEnd too, in this case, our backend is a  SpringBoot which is using a tomcat embedded server. Terminology TLS vs SSL TLS is the successor to SSL. It is a protocol that ensures privacy between communicating applications. Unless otherwise stated, in this document consider TLS and SSL as interchangable. Certificate (cert) The public half of a public/private key pair with some additional metadata about who issued it etc. It may be freely given to anyone. Private Key A private key can verify that its corresponding certificate/public key was used to encrypt data. It is never given out publicly. Certificate Authority (CA) A company that issues digital certificates. For SSL/TLS certificates, there are a small number of providers (e.g. Symantec/Versign/Thawte, Comodo, GoDaddy, LetsEncrypt) whose certificates are included by most browsers and Operating System

How to do pagination SpringBoot with Jbctemplate, MySQL

We are going to be working on a topic which is a basic need when doing any app, and it is Pagination. let's get started creating a product table at https://mockaroo.com/ create table products ( id INT, name VARCHAR(50), code VARCHAR(50) ); insert into products (id, name, code) values (1, 'Hettinger-Goyette', '42549-680'); insert into products (id, name, code) values (2, 'Konopelski-Klein', '49527-724'); insert into products (id, name, code) values (3, 'Smitham, Kuhlman and Balistreri', '53238-003'); insert into products (id, name, code) values (4, 'Hettinger, Weissnat and Goodwin', '0143-9916'); insert into products (id, name, code) values (5, 'Rowe Inc', '42291-898'); insert into products (id, name, code) values (6, 'Ernser-Hauck', '10544-617'); insert into products (id, name, code) values (7, 'Maggio and Sons', '68788-9087'); insert into products (id, name,