October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk9 min

How to Run Node.js Behind Apache on Ubuntu (Reverse Proxy Guide)

A practical Ubuntu guide to placing Node.js behind Apache with secure loopback binding, ProxyPass and ProxyPassReverse, WebSocket support by Apache version, and a troubleshooting checklist.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run your Node.js application on a private loopback port, then let Apache accept public HTTP(S) traffic and reverse-proxy requests to it. The essential Apache configuration is ProxyRequests Off, a ProxyPass route to Node, and a matching ProxyPassReverse route. Apache remains the public entry point while Node listens on 127.0.0.1, so the application port is not exposed directly.

This guide shows how to configure that layout on Ubuntu, validate it safely, keep the Node process running, support WebSockets on different Apache versions, and diagnose the failures that most often make a proxy appear broken.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How the Node.js–Apache layout works

A browser requests https://example.com/. Apache receives the connection on ports 80 or 443, selects the matching virtual host, and forwards the request to a Node.js server such as http://127.0.0.1:3000/. Node generates the response and Apache relays it to the client.

Node does not need to know that it is behind Apache. It only needs to listen on the local port named in the proxy rule. Apache handles the public hostname, TLS termination if configured, access logging, and the hand-off to Node. This separation also lets you change the Node port without exposing a new public listener.

The Apache HTTP Server documentation makes an important distinction: It is not necessary to turn ProxyRequests on in order to configure a reverse proxy. ProxyRequests On enables forward-proxy behavior and should not be used for this setup.

Before you configure Apache

Confirm the application and port

Start the Node application manually and verify that it answers on its intended port. Replace the example port with the one your app actually uses.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
node server.js

From the Ubuntu host, test the backend directly:

curl -i http://127.0.0.1:3000/

You should receive an HTTP response from Node before involving Apache. If this request fails, fix the application, its environment variables, or its listening port first; a proxy cannot repair a backend that is not accepting connections.

Bind the application to loopback

For a single-host deployment, configure Node to listen on 127.0.0.1 (or another private interface) rather than a public address. Apache can reach the loopback listener, while clients on the network cannot connect to the Node port directly. If your application currently binds to all interfaces, change its host setting and restart it, then confirm the listener with your system’s socket tools.

Have a DNS name ready

The virtual host below uses example.com. Substitute the real hostname that resolves to this Ubuntu server. If you are testing before DNS is available, use a temporary hosts-file entry or the server’s address, but keep the final ServerName explicit.

Install Apache and enable proxy support

On Ubuntu, install Apache if it is not already present:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo apt update
sudo apt install apache2

Apache loads reverse-proxy functionality through modules. Enable the modules required by your routes. A basic HTTP proxy uses the core proxy module and the HTTP proxy handler:

sudo a2enmod proxy
sudo a2enmod proxy_http

If the application uses WebSockets, enable the handler appropriate to the Apache version and configuration described later. If you must rewrite absolute URLs inside HTML response bodies, the optional HTML-proxy module is also required. Module names and package availability can differ between Ubuntu releases, so inspect the loaded set with:

apache2ctl -M

Do not restart Apache until the configuration test succeeds.

Create a reverse-proxy virtual host

Put the site configuration in an enabled virtual-host file. For example:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo nano /etc/apache2/sites-available/example.com.conf

Use this minimal HTTP configuration:

<VirtualHost *:80>
    ServerName example.com

    ProxyRequests Off
    ProxyPreserveHost Off

    ProxyPass "/" "http://127.0.0.1:3000/"
    ProxyPassReverse "/" "http://127.0.0.1:3000/"
</VirtualHost>

Enable the site

sudo a2ensite example.com.conf
sudo apache2ctl configtest

The expected result is Syntax OK. If Apache reports a file, line number, or unknown directive, correct that error before reloading:

sudo systemctl reload apache2

Reloading applies a valid configuration without needlessly dropping existing connections. Use a full restart only when your operational change requires it.

Understand each directive

ProxyRequests Off

This disables forward-proxy mode. A reverse proxy accepts a request for your site and sends it to a predetermined backend. Leaving forward-proxy mode enabled can turn a server into an unintended open proxy, so keep this directive explicitly off.

ProxyPass

ProxyPass "/" "http://127.0.0.1:3000/" maps the public URL path on the left to the Node URL on the right. In this example, every path under the virtual host is sent to port 3000.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep trailing slashes consistent. If the first argument ends with /, the second should end with / as well, and the same rule applies when neither has one. Mismatched slashes can produce backend paths that are missing or duplicating a separator.

ProxyPassReverse

This directive adjusts redirect-related response headers from Node so that a backend URL does not leak into the client-facing response. Apache documents that it rewrites the Location, Content-Location, and URI headers; it does not rewrite HTML bodies.

ProxyPreserveHost

The default is Off, and that is the normal choice. With it off, Apache sends the backend-oriented host information. Turn it on only when the application specifically needs the original public Host header, such as a backend that performs its own name-based virtual-host selection or host validation. Changing it can affect URL generation, cookies, and host checks, so make the choice deliberately.

Test the proxy from the client side

After the reload, request the public hostname rather than the Node port:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -i http://example.com/

Compare this response with the direct backend test. A successful proxy normally preserves the application status and body while Apache supplies the public connection. Test a known application route as well as the root path, because a route-specific framework or static-file rule can fail even when / works.

If Apache serves its default page, the wrong virtual host is enabled or the request’s hostname does not match ServerName. If Apache returns a 502 or 503, inspect whether Node is running on the exact address and port in ProxyPass.

Keep Node running after logout or reboot

A shell-launched process is not a reliable production service. A typical systemd unit runs the application as a non-root user, restarts it after failure, and starts it during normal multi-user boot. Adapt paths, usernames, and the entry point to your application:

[Unit]
Description=Node.js application
After=network.target

[Service]
Type=simple
User=nodeapp
WorkingDirectory=/srv/example-app
Environment=NODE_ENV=production
ExecStart=/usr/bin/node /srv/example-app/server.js
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Save it as /etc/systemd/system/example-app.service, then apply it:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo systemctl daemon-reload
sudo systemctl enable --now example-app
sudo systemctl status example-app

Check the service log when Apache reports a gateway error:

sudo journalctl -u example-app -e

The unit is an operational pattern rather than an Apache requirement. Its paths and executable location must match the Node installation on your Ubuntu release.

Serve HTTPS without changing the Node port

Keep the Node listener on its private HTTP port and terminate TLS at Apache. The usual arrangement is an HTTP virtual host that redirects to HTTPS and an HTTPS virtual host containing the same proxy mapping plus the certificate directives supplied by your certificate setup. The reverse-proxy rules remain:

ProxyRequests Off
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"

If your application constructs absolute links, make sure it knows the externally used scheme and host through the framework’s trusted-proxy settings. Do not enable ProxyPreserveHost merely because HTTPS is terminated at Apache; enable it only when the backend’s host handling requires it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Handle WebSockets correctly

WebSocket connections begin as HTTP requests and then switch protocols. A normal HTTP proxy rule may serve the initial request but fail during the upgrade unless Apache is configured for it.

Apache 2.4.47 and newer

Apache’s documentation marks mod_proxy_wstunnel as deprecated for newer releases because protocol upgrades can be handled by mod_proxy_http. Add a WebSocket route using the upgrade=websocket parameter:

ProxyPass "/ws/" "http://127.0.0.1:3000/ws/" upgrade=websocket

Keep the path slashes paired. The WebSocket endpoint in this example is /ws/; change it to the path used by the application.

Apache 2.4.46 and earlier

Older Apache versions use mod_proxy_wstunnel for WebSocket tunneling. Enable that module and use a ws:// backend mapping for the WebSocket path, while retaining the ordinary HTTP mapping for other requests.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When HTTP and WebSocket routes overlap

Order matters. Put the WebSocket ProxyPass before the broader HTTP rule so the specific upgrade route is selected first:

ProxyPass "/ws/" "http://127.0.0.1:3000/ws/" upgrade=websocket
ProxyPass "/" "http://127.0.0.1:3000/"
ProxyPassReverse "/" "http://127.0.0.1:3000/"

Apache’s ProxyWebsocketFallbackToProxyHttp setting defaults to On; it controls whether the WebSocket tunnel module hands eligible requests to the HTTP proxy implementation. If a connection unexpectedly falls back or fails to upgrade, check the Apache version, loaded modules, route order, and the error log.

Verify an upgrade failure

Test the normal HTTP endpoint first, then test the WebSocket client through the public hostname. A direct connection to Node succeeding while the proxied connection fails indicates a proxy or upgrade mismatch. Look at the Apache error log at the same time as the client attempt:

sudo tail -f /var/log/apache2/error.log

Common clues include a request sent to the broad HTTP rule, an unavailable proxy module, a backend connection refusal, or a redirect from the WebSocket path. Fix the first error in the log and retest rather than adding unrelated directives.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Absolute URLs and HTML rewriting

ProxyPassReverse changes redirect headers, not links embedded in an HTML response. If Node emits absolute backend URLs in page markup, browsers may try to load the private host or port. Avoid generating those URLs when possible by configuring the application with its public origin. If body rewriting is unavoidable, use Apache’s HTML-proxy functionality and understand that it adds parsing and maintenance complexity; it is separate from ProxyPassReverse.

Use a subpath instead of the whole site

You can publish only one application under a path such as /app/:

ProxyPass "/app/" "http://127.0.0.1:3000/app/"
ProxyPassReverse "/app/" "http://127.0.0.1:3000/app/"

The paired trailing slashes are significant. The Node application must also understand that it is mounted below /app/ if it generates relative routes, static-file paths, redirects, or cookies. A framework configured for the root path can appear to load while its assets still request / instead of /app/.

Diagnose common failures

Symptom Likely cause What to check
Apache shows its default page The intended virtual host is not selected. Confirm ServerName, DNS or hosts-file resolution, and a2ensite; run apache2ctl -S to inspect virtual-host selection.
502 Bad Gateway Apache cannot connect to Node. Run curl http://127.0.0.1:3000/, verify the service is active, and compare the configured address and port.
404 only on some paths A path mapping or slash mismatch is altering the backend URL. Compare both ProxyPass arguments and inspect the application’s route prefix.
Redirect points to a private port The backend emitted an absolute redirect that was not rewritten as expected. Check ProxyPassReverse and the application’s public-origin settings.
WebSocket handshake fails Wrong Apache-version method, missing module, or a broad HTTP rule matched first. Use upgrade=websocket on 2.4.47+, the tunnel module on older versions, and place the specific route before /.
Host-based application behavior is wrong The backend received a different Host header. Leave ProxyPreserveHost Off unless the app requires the public host; if it does, enable it intentionally and retest redirects and cookies.
Configuration reload fails A syntax error or unavailable directive/module. Run sudo apache2ctl configtest and fix the reported line before reloading.

Production checklist

  • Node answers on the expected loopback address and port before Apache is tested.
  • The application process is supervised by systemd or another process manager and runs as a non-root user.
  • ProxyRequests Off is present.
  • ProxyPass and ProxyPassReverse use matching trailing-slash conventions.
  • ProxyPreserveHost remains off unless the backend has a documented need for the original host.
  • WebSocket routes use the method appropriate to the installed Apache version and appear before overlapping HTTP routes.
  • apache2ctl configtest returns Syntax OK before every reload.
  • Apache’s error log and the Node service log are available when testing failures.
  • Absolute URLs in HTML are handled by application configuration or an explicitly configured HTML-rewriting module.

What to remember

The reliable pattern is intentionally small: Node listens privately, Apache is the public listener, and a virtual host maps requests with ProxyPass plus ProxyPassReverse. Keep forward-proxy mode disabled, preserve the Host header only for a demonstrated requirement, and treat WebSockets as a version-specific upgrade problem. Validate syntax before reloads and use both Apache and Node logs to locate the first failing hop.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.