Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Run your Node.js application on a private loopback port, then let Apache accept public HTTP(S) traffic and reverse-proxy requests to that process. The essential configuration is ProxyRequests Off, a ProxyPass route, and a matching ProxyPassReverse route. Apache 2.4.47 and later can tunnel WebSockets through mod_proxy_http with upgrade=websocket; older releases require mod_proxy_wstunnel.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
What “Node.js behind Apache” means
Node.js still runs the application server. Apache does not execute your JavaScript; it receives requests on the public address, selects a virtual host, and forwards each request to Node on an internal address such as 127.0.0.1:3000. The response travels back through Apache to the browser.
As an Amazon Associate I earn from qualifying purchases.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteThis arrangement gives one public web server a stable place to handle virtual hosts, TLS termination, access logging, compression, and static files while each Node application listens on its own local port. Binding the application to loopback also prevents clients from bypassing Apache and reaching the Node listener directly. Use the exact interface and port your application is configured to use; the examples below use 127.0.0.1:3000.
Request flow
- A browser requests
http://example.com/. - Apache matches
ServerName example.comin the virtual host. ProxyPassforwards the path tohttp://127.0.0.1:3000/.- Node generates the response, and
ProxyPassReverseadjusts redirect-related response headers before Apache returns the response to the browser.
ProxyPassReverse rewrites the Location, Content-Location, and URI response headers. It does not rewrite links embedded in an HTML body. If an application emits absolute links that point at its internal hostname or port, use the application’s public URL settings or add the separately provided mod_proxy_html solution rather than assuming ProxyPassReverse will edit the page.
#1 Best Overall
Before you configure Apache
Confirm the application and port
Start the Node application locally and verify that it answers on the intended port before introducing Apache. A request made on the server should return your application’s normal response:
curl -i http://127.0.0.1:3000/
If this fails, fix the Node process first. A reverse proxy cannot compensate for a crashed process, a different listening port, or an application bound only to an address Apache cannot reach.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Choose a loopback listener
Configure the application to listen on 127.0.0.1 (or another deliberately restricted local interface) and the selected port. Apache must be able to connect to that address, while outside clients should use Apache’s public address. Keep the port consistent in every place it appears: the Node startup command, the ProxyPass target, health checks, and any process manager configuration.
Identify the Apache release
WebSocket configuration depends on Apache’s version. Check the installed version:
apache2ctl -v
| Apache version | WebSocket approach | Important detail |
|---|---|---|
| 2.4.47 and later | mod_proxy_http with upgrade=websocket |
Protocol Upgrade tunnelling is handled by the HTTP proxy module; mod_proxy_wstunnel is deprecated. |
| 2.4.46 and earlier | mod_proxy_wstunnel |
Use a ws:// or wss:// route for the WebSocket path. |
Enable the Apache proxy modules
Ubuntu’s Apache package keeps many modules disabled until you enable them. The usual module set for an HTTP reverse proxy is proxy and proxy_http; add proxy_wstunnel when an older Apache release needs it. The a2enmod command changes the local Apache configuration, so use the module names available in your Ubuntu package.
sudo a2enmod proxy
sudo a2enmod proxy_http
# Apache 2.4.46 and earlier, when WebSockets are required:
sudo a2enmod proxy_wstunnel
Reload only after validating the complete configuration. If a module name is unavailable, inspect the package’s enabled-module directory and the Apache error output rather than copying a directive from a different release.
Rank #2
Create the reverse-proxy virtual host
Minimal HTTP configuration
Create or edit the site’s virtual-host file under Ubuntu’s Apache configuration directory. Replace the example hostname with the DNS name that points to this server.
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost Off
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>
ProxyRequests Off is a security boundary: it keeps Apache in reverse-proxy mode instead of acting as a forward proxy for arbitrary clients. Apache’s mod_proxy documentation explicitly states, “It is not necessary to turn ProxyRequests on in order to configure a reverse proxy.” Do not enable it as a way to make reverse proxying work.
Understand ProxyPreserveHost
The directive defaults to Off, and Apache documentation says it should normally remain off. With the default, the backend receives a host value appropriate to the proxy connection. Set ProxyPreserveHost On only when the application or a proxied name-based virtual host specifically requires the browser’s original Host header. Changing it can affect tenant selection, URL generation, and host-based security checks, so make the choice deliberately rather than treating it as a universal Node.js requirement.
Match trailing slashes
Keep the slash convention identical on both sides of each mapping. If the first argument ends with /, the backend argument should also end with /; if one omits it, omit it from the other as well. The matching form in the example maps every path below the public root without accidentally joining path segments.
Enable the site and test it
On Ubuntu, site files are commonly enabled with a symbolic link through a2ensite. Use the filename you actually created:
sudo a2ensite example.com.conf
sudo apache2ctl configtest
Proceed only when the command reports a successful syntax check. Then reload Apache so existing connections are treated as gracefully as the service permits:
sudo systemctl reload apache2
Request the public hostname and compare it with the direct local request:
curl -i http://example.com/
A response from the Node application confirms the basic route. A default Apache page, a “503 Service Unavailable” response, or a connection refusal points to a different stage of the setup; use the troubleshooting section below instead of adding random proxy directives.
Configure WebSockets correctly
Apache 2.4.47 and newer
For current Apache releases, add an Upgrade-aware route using mod_proxy_http. The route’s public path must match the path used by the client and by the Node WebSocket server:
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost Off
ProxyPass "/ws/" "http://127.0.0.1:3000/ws/" upgrade=websocket
ProxyPassReverse "/ws/" "http://127.0.0.1:3000/ws/"
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>
The WebSocket mapping appears before the catch-all HTTP mapping. Apache’s documentation gives this ordering for mixed traffic: the more specific WebSocket route is evaluated first, then the general HTTP route handles everything else.
The upgrade=websocket parameter tells Apache to tunnel the protocol Upgrade request. It does not create a WebSocket endpoint in Node; your application must already accept connections at /ws/.
Apache 2.4.46 and earlier
Older releases use mod_proxy_wstunnel. Enable that module and map the WebSocket path with a WebSocket backend URL:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #4
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost Off
ProxyPass "/ws/" "ws://127.0.0.1:3000/ws/"
ProxyPassReverse "/ws/" "ws://127.0.0.1:3000/ws/"
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>
Do not blindly keep an old mod_proxy_wstunnel recipe on a newer server: that module is deprecated, and Apache 2.4.47 introduced HTTP-proxy Upgrade handling as the preferred path. The directive ProxyWebsocketFallbackToProxyHttp defaults to On; it controls whether the WebSocket tunnel module hands eligible requests to mod_proxy_http.
Use the correct public scheme
If Apache terminates TLS, the browser connects with wss://example.com/ws/ while Apache can connect to Node over ws://127.0.0.1:3000/ws/ on the private side. If TLS is passed through to a TLS-speaking backend instead, use the corresponding wss:// target and certificate arrangement. Keep the public and backend schemes conceptually separate: the browser-facing scheme is not automatically the same as the local hop.
Path mapping and application URLs
Root-mounted application
The root mapping shown above sends /assets/app.js to the backend as /assets/app.js. This is the least surprising layout when the Node application was built to run at the site root.
Application mounted below a prefix
You can expose an app below a prefix, but the application must know its public base path. For example:
Free tools Windows power users keep installed
One-click scans. No signup required.
ProxyPass "/game/" "http://127.0.0.1:3000/"
ProxyPassReverse "/game/" "http://127.0.0.1:3000/"
With this mapping, Apache removes the public /game/ prefix before forwarding. The app must generate links, redirects, cookie paths, and WebSocket URLs that work under /game/; otherwise requests for scripts or sockets may appear to “randomly” fall outside the proxy route. If changing the app’s base URL is impossible, map the backend path so that the path it expects remains intact and test every redirect.
Redirects and absolute links
When Node responds with a redirect, ProxyPassReverse can rewrite the relevant response headers so the client sees the public address. It cannot alter an absolute URL written inside an HTML document or JavaScript bundle. Configure the application’s public origin first. Consider mod_proxy_html only for a deliberate HTML-rewriting design, because rewriting generated content can affect scripts, caching, and security policies.
Best Value
Run the Node process reliably
Apache can proxy only while the Node process is running. For production, use a process supervisor and run the application as a non-root account with a controlled environment. A typical systemd unit is a deployment pattern rather than a requirement of Apache:
[Unit]
Description=Node application
After=network.target
[Service]
Type=simple
User=nodeapp
WorkingDirectory=/srv/nodeapp
Environment=NODE_ENV=production
ExecStart=/usr/bin/node /srv/nodeapp/server.js
Restart=always
[Install]
WantedBy=multi-user.target
Adjust the Node executable path, working directory, account, and startup file to your installation. After placing a unit in the systemd service directory, reload systemd, enable the service, and start it. Verify the service’s local response before reloading Apache. Keep secrets out of the unit file when your deployment platform offers a safer environment-file or secret-management mechanism.
Validate the complete setup
Check each layer independently
- Check the Node process status with your chosen supervisor.
- Request the backend directly from the server:
curl -i http://127.0.0.1:3000/. - Run
sudo apache2ctl configtestand correct every syntax error. - Reload Apache, then request the public hostname with
curl -i. - Test a known redirect and confirm its
Locationheader uses the public host and path. - Open the application’s WebSocket feature and inspect the browser network panel for a successful protocol upgrade.
Read the right logs
When Apache returns an error, inspect the Apache error log at the same time as the Node process log. A proxy connection-refused message usually means Node is stopped, listening on another port, or bound to an inaccessible address. A successful HTTP response followed by a WebSocket disconnect usually indicates a route, Upgrade handling, path, or application-level handshake problem. The Apache error log is the first place to look for module-loading and proxy-connection diagnostics.
Troubleshooting by symptom
Apache reports a syntax error
- Run
apache2ctl configtestagain to capture the exact file and line. - Check quote characters, closing
</VirtualHost>tags, and directive spelling. - Confirm that every directive’s module is enabled and available in this Apache build.
- Only reload after the test succeeds.
The public request shows Apache’s default page
- Confirm DNS resolves to this server and that the request’s hostname matches
ServerName. - Make sure the intended site is enabled and another virtual host is not winning the match.
- Reload Apache after enabling or editing the site.
Apache returns 502 or 503
- Run the direct
curlrequest against127.0.0.1:3000. - Compare the configured port with the Node startup configuration.
- Check whether Node is listening on loopback IPv4 while Apache is attempting a different address.
- Read the Apache error log and the Node supervisor log for the same timestamp.
Redirects point to the internal port
- Keep
ProxyPassReversepaired with everyProxyPassmapping. - Check the application’s external URL, host, and protocol settings.
- Remember that
ProxyPassReversechanges response headers, not HTML body links.
WebSockets return 404, 302, or disconnect
- Verify that the client path exactly matches the WebSocket
ProxyPasspath. - On Apache 2.4.47 or newer, use
upgrade=websocketwith the HTTP proxy module. - On Apache 2.4.46 or earlier, enable and use
mod_proxy_wstunnel. - Place the WebSocket mapping before the catch-all
/HTTP mapping. - Check that the Node server actually accepts WebSocket upgrades at that path and is not redirecting them to a login or canonical URL.
- Inspect Apache’s error log while reproducing the failure; a direct Node connection working does not prove the proxied route is correct.
Security and maintenance decisions
Do not create a forward proxy
Leave ProxyRequests Off. Reverse proxying selects fixed backend destinations from your configuration; forward proxying accepts client-supplied destinations and can expose the server to abuse.
Keep the backend private
Use loopback binding when the application is intended to be reached only through Apache. If another local service must connect to Node, choose an explicit private interface and firewall policy rather than exposing the application listener to the public network by default.
Preserve the original host only when required
Start with ProxyPreserveHost Off. Turn it on for a documented application requirement, then test host-based routing, redirects, cookies, and any allow-list logic that depends on the incoming host.
Recommended Free Tools
Keep routes specific
Put specific paths such as /ws/ before a root catch-all. Use matching trailing slashes, pair forward and reverse mappings, and document which Node process owns each port. These small conventions prevent an apparently valid request from being sent to the wrong handler.
Quick Recap
Configuration checklist
- Node answers on the chosen local address and port.
- The public DNS name matches the Apache virtual host.
proxyandproxy_httpare enabled.ProxyRequests Offis present.ProxyPreserveHostis left off unless the application needs the original host.ProxyPassandProxyPassReverseuse the same public and backend paths, including trailing-slash style.- The WebSocket route precedes the HTTP catch-all and uses the syntax appropriate to the Apache version.
apache2ctl configtestsucceeds before every reload.- Direct backend, public HTTP, redirects, and WebSocket upgrades have each been tested.
- Apache and Node logs are available for the next failure.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




