Proxying Node application through Apache

My Express-based Node.js application is in most cases used on the localhost since it is still in early development stage. However, I would like to start using Internet-facing domain name and SSL certificate to handle OAuth or other APIs that require my application to be accessible.

Understanding the basics

The express-based application is acting as the web-server on its own. The problem is that I don’t want it to be attached to the port 80 or 443 of my web server, because I have more sites that are using this port. All of them are handled by Apache server using name-based virtual hosts. The second issue is that I want to use Let’s Encrypt SSL certificate which can be easily configured for Apache but not for Node.js application.

Given that, I started by creating the regular name-based Apache website pointing to the temporary directory. Let’s assume that the domain I used is tracker.mydomain.com. I also installed Let’s Encrypt on this website and forced HTTP to HTTPS redirect using Apache configuration. My application is up and running on the port 3000 of my server. Now I want my Apache server to call my Node application every time someone requests tracker.mydomain.com.

Proxying basics

To use Apache as a proxy, you should make sure that required modules are enabled.

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_html
sudo systemctl restart apache2

The second step will be to update the Apache website configuration. In my case, I added few lines in my Virtual Host configuration:

<VirtualHost *:80>
[...]
Redirect "/" "https://tracker.mydomain.com/"
[...]
</VirtualHost>

<VirtualHost *:443>
[...]
ServerName tracker.mydomain.com

ProxyPass /.well-known/ !
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
ProxyPreserveHost On
[...]
</VirtualHost>

As I wrote before, I added the redirect to switch my site to HTTPS completely. The proxy configuration I used is rather straight, but I want to point out few things. I used ProxyPass /.well-known/ ! to make sure that my Let’s Encrypt scripts will run fine and my SSL certificate will be updated without problems. I also used both ProxyPass and ProxyPassReverse to make sure that the headers will be adjusted properly. ProxyPreserveHost, on the other hand, was used to pass hostname to my Express application. Now I only need to restart the Apache, and I’m ready.

Proxying remote application

As you can imagine, you can also proxy to the remote application. In this case you can use the IP and port of your remote server instead of http://127.0.0.1:3000/. The other method is to create SSH tunnel between your remote server and your Apache server and use proper local port (the local end of the tunnel). For example, If you will configure SSH tunnel to end on port 5001 of your Apache server, you can use http://127.0.0.1:5001/ in your proxy configuration. You can also use such proxy to access the site which is normally not allowed by the firewall you are behind.

8 Replies to “Proxying Node application through Apache”

  1. Hello, very nice article indeed, but there are some missing parts to understand it completely. Namely:
    1. are you using http or https on the Node.js side?
    2. Are you using SSLEngine On and all the SSL config parameters on the 443 Virtual Host? If so, would you mind sharing the whole config with us?

    Thanks!

    1. Good point. I will try to prepare few more words on configuration after the weekend 🙂

    2. Answering your questions:

      1) My SSL connection is terminated by Apache and the connection between Apache and Node is handled in pure HTTP with no encryption.
      2) My Apache configuration is prepared to work properly with Let’s Encrypt. My Apache config for this website looks as follows:


      <VirtualHost *:80>
      DocumentRoot /var/www/tracker
      ServerName tracker.mydomain.com
      Redirect "/" "https://tracker.mydomain.com/"
      ErrorLog /var/log/httpd/tracker/error.log
      </VirtualHost>

      <VirtualHost *:443>
      DocumentRoot /var/www/tracker
      ServerName tracker.mydomain.com

      ProxyPass /.well-known/ !
      ProxyPass / http://127.0.0.1:3000/
      ProxyPassReverse / http://127.0.0.1:3000/
      ProxyPreserveHost On

      ErrorLog /var/log/httpd/tracker/error.log

      <IfModule mod_ssl.c>
      SSLEngine on
      SSLProtocol All -SSLv2 -SSLv3
      SSLHonorCipherOrder on
      SSLCertificateFile /certificates/ssl/tracker.com-le.crt
      SSLCertificateKeyFile /certificates/ssl/tracker.com-le.key
      SSLCertificateChainFile /certificates/ssl/tracker.com-le.bundle
      SSLUseStapling on
      SSLStaplingResponderTimeout 5
      SSLStaplingReturnResponderErrors off
      </IfModule>
      </VirtualHost>

  2. Really useful, thank you for writing this up. This is the clearest example I can find of what someone, who doesn’t already have lots of experience in this area, is meant to do.

    Might be worth adding for others finding this: I found my configuration files at /etc/apache2/sites-enabled/000-default.conf (for Port 80) and /etc/apache2/sites-enabled/000-default-le-ssl.conf (Port 443) respectively.

  3. This came in extremely handy with running a local WAMP server along with a NodeJS Botpress server instance on local port 3000.

    Thank you so much.

Comments are closed.