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
Hostheader (or SNI for HTTPS), thenProxyPass "/"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_httpOn 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:
ServerNameselects the virtual host. Always set it explicitly.ProxyRequests Offprevents Apache from acting as an open forward proxy.ProxyPreserveHost Onsends the originalHostheader to the backend, which many applications need to build correct URLs.ProxyPassReverserewrites 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 -Sconfigtest 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 apache2On 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
ServerNameis missing, misspelled, or not loaded. When no name matches, Apache uses the first virtual host for that IP and port. Re-checkapache2ctl -S. Invalid command 'ProxyPass':mod_proxyis 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 withcurl. - 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, runsudo setsebool -P httpd_can_network_connect 1. Do not disable SELinux. - Redirects point to
127.0.0.1:3000: confirmProxyPassReversematches theProxyPasstarget. Also check the application's own base URL setting. - Missing or doubled slashes in URLs: use a trailing slash on both
ProxyPassarguments, or on neither. - Still unclear: add
LogLevel info proxy:debuginside 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.