Spring Boot: Forwarding Port 8080 to 80 and LetsEncrypt SSL

I have seen many articles on utilizing Spring Boot with port forwarding and SSL certificates. None of these articles seem complete. Recently, I have had to deploy a Spring Boot app into production. I could not find good reference material for what I was trying to accomplish. I needed the app to be usable on port 80 with SSL enabled using LetsEncrypt as the certificate authority. In Linux, any port under 1024 has special privileges. There are two main options. The first is to use iptables to redirect port 80 traffic to the port that the Java web app is running on, usually port 8080. This option lacks SSL capabilities. The second option is to use a proxy, usually Apache or Nginx.

Iptables

If you don’t need SSL capabilities, iptables is the easiest and most simple option:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 # Port 80 traffic will be directed to port 8080

The main drawback of this approach is that iptables cannot redirect to HTTPS only sites. If you need to remove this, then just enter these simple commands in your terminal:

iptables -t nat --line-numbers -L # List rules
iptables -t nat -D PREROUTING {num} # Remove rule. Replace {num} with the number from the command above.

Apache

Using Apache or Nginx is the most flexible option. Configuration is much more onerous than using iptables. In this tutorial, we will be using Apache on Ubuntu.

  1. First install Apache and enable modules:
             sudo apt-get install apache2
             sudo a2enmod proxy
             sudo a2enmod proxy_http

2. Navigate to configuration directory:

cd /etc/apache2/sites-available

3. Now you will need to modify the 000-default.conf file adding these lines under the "VirtualHost" brackets:

ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/

4. Restart Apache:

sudo service apache2 restart

Now port 80 should be serving traffic through port 8080. If the app doesn’t use SSL, feel free to stop reading here. Make sure everything is working before continuing. The next step is enabling SSL.

To create the LetsEncrypt SSL certificate, we must first ensure that we are inside the terminal on the production server. This will not work on your local machine. Here are the steps to produce the certificate:

wget https://dl.eff.org/certbot-auto # Download client to server
chmod a+x certbot-auto # Make executable
./certbot-auto # Install dependencies to server
./cerbot-auto certonly -a standalone -d {domainName} -d {secondDomainName} # Create certificate (on Debian derivatives it will create the certificates at "/etc/letsencrypt/live/{domainName}"

Now we must navigate into the directory that LetsEncrypt generated:

sudo su # Need root to see files
cd /etc/letsencrypt/live/{domainName}

Finally, we can see the contents that LetsEncrypt created:

cert.pem  chain.pem  fullchain.pem  privkey.pem

Our next step is to create keys that are compatible with Spring Boot. To create a keystore for Spring Boot:

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name tomcat -CAfile chain.pem -caname root

Now move the key somewhere readable to your Spring Boot application and then append the following attributes to the application-properties:

security.require-ssl=true
server.ssl.key-store={key_store_location}
server.ssl.key-store-password={key_store_password}
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=tomcat

Now we need to modify Apache configuration file again. To make all HTTP requests redirect to HTTPS, append this to the top of the config file:

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Next we need to ensure that we can proxy to port 8080 with SSL, we need to add the SSLCertificateKeyFile, SSLCertificateChainFile, and SSLCertificateFile. Your final config file should look something like this:

# Making all web requests HTTPS
 
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}


	ServerAdmin webmaster@localhost # Replace this if you want.
	ServerName {domain}
       
      

	SSLEngine on
	SSLProxyEngine On
	SSLProtocol All -SSLv2 -SSLv3 # Disable SSL versions with POODLE vulnerability

	SSLCertificateKeyFile /etc/letsencrypt/live/{domain}/privkey.pem
	SSLCertificateChainFile /etc/letsencrypt/live/{domain}/chain.pem
	SSLCertificateFile /etc/letsencrypt/live/{domain}/fullchain.pem


	
	ProxyRequests Off
	ProxyPreserveHost On
	ProxyPass / https://localhost:8080/
	ProxyPassReverse / https://localhost:8080/


	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

Now restart Apache:

 sudo service apache2 restart

Finally, we have HTTPS traffic which proxies traffic from port 80 to 8080. I think this process is very onerous just to get SSL running for a Spring Boot app. Hopefully, Spring Boot will have a “no configuration” solution soon.

References:

3 thoughts on “Spring Boot: Forwarding Port 8080 to 80 and LetsEncrypt SSL”

  1. Using configuration like the example above means the application will no longer support plain HTTP connector at port 8080.

  2. Great solution, thank you so much. I tested the apache “version” in the past, but for now i need just iptable approach and that is great.

Leave a Reply

Your email address will not be published.