Loading…


Instead of routing example.com/app1 and example.com/app2 to different backends, you can give each application its own hostname, such as app1.example.com and app2.example.com. This is done with one name-based virtual host per hostname, each containing its own ProxyPass. This guide covers Apache 2.4 on Debian/Ubuntu, with RHEL-family differences noted.

How It Differs From Path-Based Proxying

  • Path-based: one virtual host, several rules such as ProxyPass "/app1" "http://127.0.0.1:3000/".
  • Server-name-based: Apache selects the virtual host from the request's Host header (or SNI for HTTPS), then ProxyPass "/" sends everything to that host's backend.

Before You Start

  • You need root or sudo access, for example on an ICSDC VPS.
  • Create a DNS A/AAAA record for each hostname pointing to the server's public IP.
  • Confirm each backend responds locally: curl -I http://127.0.0.1:3000/.
  • Back up the configuration: sudo cp -a /etc/apache2 /etc/apache2.bak (RHEL: /etc/httpd).

Step-by-Step Configuration

1. Enable the proxy modules

sudo a2enmod proxy proxy_http

On RHEL/AlmaLinux the modules are normally loaded already. Confirm with httpd -M | grep proxy.

2. Create one virtual host per hostname

Create /etc/apache2/sites-available/app1.example.com.conf:

<VirtualHost *:80>
    ServerName app1.example.com
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass "/" "http://127.0.0.1:3000/"
    ProxyPassReverse "/" "http://127.0.0.1:

3000/"    ErrorLog ${APACHE_LOG_DIR}/app1-error.log    CustomLog ${APACHE_LOG_DIR}/app1-access.log combined</VirtualHost>

Create app2.example.com.conf the same way, changing ServerName, the port (for example 4000), and the log names.

What the key directives do:

  • ServerName selects the virtual host. Always set it explicitly.
  • ProxyRequests Off prevents Apache from acting as an open forward proxy.
  • ProxyPreserveHost On sends the original Host header to the backend, which many applications need to build correct URLs.
  • ProxyPassReverse rewrites backend redirect headers to your public hostname.

On RHEL-family systems, save the files in /etc/httpd/conf.d/ and skip a2ensite. Replace ${APACHE_LOG_DIR} with /var/log/httpd.

3. Enable the sites and test the syntax

sudo a2ensite app1.example.com.conf app2.example.com.confsudo apache2ctl configtestsudo apache2ctl -S

configtest should print Syntax OK. The -S output lists every virtual host Apache parsed. Both hostnames should appear under port 80 with the correct file paths.

4. Reload Apache

sudo systemctl reload apache2

On RHEL: sudo systemctl reload httpd.

Verify the Result

Test each hostname without waiting for DNS propagation. Replace SERVER_IP with your server's IP:

curl -I --resolve app1.example.com:80:SERVER_IP http://app1.example.com/curl -I --resolve app2.example.com:80:SERVER_IP http://app2.example.com/

Each request should return its own backend's response, not the Apache default page. The separate access logs should also show the matching requests.

Troubleshooting

  • Apache default page or wrong app appears: the ServerName is missing, misspelled, or not loaded. When no name matches, Apache uses the first virtual host for that IP and port. Re-check apache2ctl -S.
  • Invalid command 'ProxyPass': mod_proxy is not enabled. Repeat step 1.
  • 503 Service Unavailable: the backend is stopped or the port is wrong. Run sudo tail -n 50 /var/log/apache2/error.log, then retest the backend with curl.
  • 503 on RHEL with SELinux enforcing: SELinux may block Apache's outbound connections. Check sudo ausearch -m avc -ts recent. If it shows denials for httpd, run sudo setsebool -P httpd_can_network_connect 1. Do not disable SELinux.
  • Redirects point to 127.0.0.1:3000: confirm ProxyPassReverse matches the ProxyPass target. Also check the application's own base URL setting.
  • Missing or doubled slashes in URLs: use a trailing slash on both ProxyPass arguments, or on neither.
  • Still unclear: add LogLevel info proxy:debug inside the virtual host, reload, and read the error log. Remove it afterwards.

Optional: HTTPS by Hostname

Run sudo a2enmod ssl, then add a *:443 virtual host for each hostname with the same ServerName, SSLEngine on, SSLCertificateFile, SSLCertificateKeyFile, and the same proxy lines. Each certificate must cover its hostname. If the backend itself uses HTTPS, add SSLProxyEngine On and use an https:// backend URL.

If you prefer not to maintain Apache yourself, ICSDC offers Managed VPS Hosting.