How to Configure Apache as a Reverse Proxy with mod_proxy on Ubuntu
Apache HTTP Server provides a flexible reverse proxy framework through the mod_proxy module family. When configured appropriately, Apache can operate in front of one or several backend applications, forward requests from clients, terminate SSL/TLS connections, balance traffic between multiple servers, and provide an additional layer of security and control between users and application infrastructure.
This tutorial explains how to configure Apache as a reverse proxy on Ubuntu with the mod_proxy module family. You will install Apache, activate the required proxy modules, configure basic forwarding with ProxyPass and ProxyPassReverse, retain client information by using forwarded headers, distribute requests among multiple backend systems with mod_proxy_balancer, set up SSL termination at the proxy layer, strengthen the configuration, and troubleshoot common mod_proxy problems in production environments.
Key Takeaways
- Apache’s
mod_proxymodule family enables Apache HTTP Server to work as a reverse proxy, forward requests to backend applications, terminate SSL/TLS connections, distribute traffic among several servers, and centralize request processing through one frontend layer. - A reverse proxy is positioned between clients and backend application servers, allowing Apache to present one public endpoint while internal services, ports, and infrastructure remain inaccessible directly from the internet.
- Apache reverse proxy configurations are frequently used to place Node.js, Python, Java, or PHP applications behind a stable frontend server that manages HTTPS, routing, logging, and access control for the backend services.
- The
ProxyPassandProxyPassReversedirectives form the foundation of an Apache reverse proxy configuration by forwarding requests to backend services and correctly adjusting redirects and response headers returned by those applications. - Forwarded headers including
X-Forwarded-For,X-Forwarded-Host, andX-Forwarded-Protohelp backend applications retain information about the original client IP address, requested hostname, and connection protocol after traffic passes through Apache. - Apache separates reverse proxy functionality into modules such as
mod_proxy_http,mod_proxy_balancer,mod_proxy_wstunnel, andmod_proxy_fcgi, making it possible to activate only the capabilities required for a deployment. - The
mod_proxy_balancermodule distributes requests among multiple backend servers, improving scalability and availability while supporting different balancing algorithms and sticky sessions for stateful applications. - Terminating SSL at the Apache proxy layer simplifies certificate administration because Apache can manage encrypted HTTPS connections from clients while forwarding requests to backend applications through HTTP or HTTPS.
- Reverse proxies should be hardened carefully. Important measures include disabling forward proxy functionality with
ProxyRequests Off, protecting administrative interfaces, minimizing server information disclosure, and choosing suitable timeout values. - Typical
mod_proxyproblems such as502 Bad Gateway,503 Service Unavailable, SSL verification errors, and missing module errors can usually be investigated through Apache logs, direct backend connectivity tests, and configuration validation withapache2ctl configtest.
Prerequisites
Before starting, make sure you have an Ubuntu server using a currently supported release such as Ubuntu 22.04 or Ubuntu 24.04. The system should also have a non-root account with sudo privileges and an active firewall.
If the server has not yet been prepared, configure a non-root administrative user with sudo privileges and enable an appropriate firewall. If Apache administration on Ubuntu is unfamiliar, it is also useful to understand the standard Apache installation and service-management process before proceeding.
What Is a Reverse Proxy and Why Use mod_proxy?
A reverse proxy is a server positioned between clients and one or more backend application servers. When a client requests a resource, the connection first reaches the reverse proxy. Apache evaluates the configured routing rules, generally through ProxyPass and ProxyPassReverse directives inside a VirtualHost, chooses the appropriate backend, forwards the request, and then sends the backend response to the client as though Apache had produced the response itself.
This arrangement differs from a forward proxy. A forward proxy represents clients when they access external internet resources, whereas a reverse proxy represents applications. Clients normally see only the hostname, IP address, and TLS certificate of the proxy. Backend hostnames, internal ports, and the physical server layout remain hidden. Because these layers are separated, backend services can be replaced, expanded, upgraded, or patched without requiring clients to understand how the internal infrastructure is organized.
Modern application environments commonly use this architecture because application servers such as Node.js services, Python WSGI applications, and Java servlet containers are designed to process application traffic efficiently but are not always intended to serve as the public network edge. Apache manages the public client connection, applies policies at the boundary, and delegates application processing to specialized backend services.
Why Use a Reverse Proxy?
Reverse proxies allow organizations to centralize functionality that would otherwise need to be configured repeatedly on every application instance. TLS settings, request logging, rate limits, and access restrictions can be managed at the proxy layer instead of being duplicated across individual applications. This can simplify administration, improve security consistency, and make scaling easier as traffic increases.
Separating Frontend and Backend Services
Backend applications are often bound to loopback addresses such as 127.0.0.1 or private network interfaces that cannot be accessed directly from the public internet. This is usually intentional. An application process may not be hardened sufficiently for direct exposure, or multiple services may run on one server without each requiring a separate public port.
Apache connects these layers by listening on standard ports such as 80 and 443, while backend applications listen on other ports. For example, Apache can accept public requests while a Node.js API listens locally on 127.0.0.1:3000. Path-based routing can forward requests under /api/ to that application while Apache handles static content directly. Users can therefore access one domain and certificate while application processes remain outside the public network.
This architecture can also simplify application updates. A new version of a backend can be deployed on another port, the proxy destination can be changed, or a blue-green deployment can be implemented without requiring users to change URLs or DNS records. Several applications can also share one public hostname and be routed according to paths or subdomains configured in Apache.
SSL/TLS Termination
Encrypted communication is important, but maintaining individual certificates on every backend system creates repeated administrative work and increases the possibility of expired or incorrectly configured certificates. With SSL termination, the client establishes an HTTPS connection with Apache. Apache decrypts that connection with the configured site certificate before passing the request to the backend.
Apache can forward the decrypted request to backends through HTTP when those systems are located on a trusted private network. Alternatively, it can establish another encrypted connection to an HTTPS backend with SSLProxyEngine On and the related SSLProxy* directives. Plain HTTP is frequently used when the backend runs on the same host or trusted network segment, while HTTPS can be used when internal communication must also remain encrypted.
When TLS is managed centrally at the proxy, certificate renewal, cipher configuration, and HTTP Strict Transport Security can be controlled from one location. Application frameworks can use ordinary HTTP internally without duplicating TLS configuration, which can be particularly helpful for containerized or short-lived backend processes that would otherwise require separate certificate distribution.
Load Balancing
A single backend system can eventually become a performance limitation. Apache addresses this through mod_proxy_balancer, which defines a group of backend members and distributes requests among them. Modules such as mod_lbmethod_byrequests, mod_lbmethod_bytraffic, and mod_lbmethod_bybusyness determine whether balancing is based on request count, transferred data, or current backend activity.
Sticky sessions can be used when application session information is stored locally rather than in shared storage. Apache can continue routing a particular client to the same backend for the duration of the session. If one backend stops responding or is marked as unavailable, traffic can be sent to healthy members, improving service availability without taking the complete application offline.
Proxy-based balancing also provides a straightforward approach to horizontal scaling. An additional application instance can be started, registered as another BalancerMember, and begin receiving requests without changing the public URL used by clients.
Caching and Performance Optimization
Some requests do not need to reach a backend application every time. Content that changes infrequently, including images, stylesheets, and public API responses with suitable cache lifetimes, can be cached by Apache through modules such as mod_cache and mod_cache_disk. Apache can follow HTTP caching headers and administrator-defined rules. Serving cached responses from the frontend layer reduces CPU and I/O usage on backend systems while improving response times for repeat requests.
Apache is not primarily designed as a dedicated caching proxy, but edge caching can still be useful in environments where Apache already handles TLS and static content. Response compression through mod_deflate provides another optimization. Apache can compress responses before transmitting them across the network, which reduces data transfer for clients without requiring every backend application to implement compression independently.
How mod_proxy Fits into the Apache Module Ecosystem
Apache provides reverse proxy functionality through a modular family built around mod_proxy. The core module supplies shared proxy infrastructure, including connection management, common directives, and extension hooks used by protocol-specific modules. The mod_proxy module must be enabled for reverse proxy functionality, while companion modules provide additional capabilities.
The mod_proxy_http module handles HTTP and HTTPS backend communication and is usually one of the first proxy modules activated. mod_proxy_balancer introduces load balancing through BalancerMember directives and <Proxy balancer://name> configuration blocks. mod_proxy_wstunnel handles WebSocket upgrade connections for real-time applications, while mod_proxy_fcgi forwards requests to FastCGI services such as PHP-FPM.
Other modules expand the proxy system for specialized use cases. mod_proxy_ajp communicates with Java application servers through the AJP protocol. mod_proxy_hcheck can perform backend health checks so unavailable servers are removed from rotation. mod_proxy_html can rewrite links contained in HTML responses when internal backend URLs differ from the public URL structure.
Several important directives are shared across these modules. ProxyPass connects an incoming URL path to a backend URL. ProxyPassReverse adjusts response headers so redirects refer to the public hostname instead of internal backend addresses. ProxyRequests Off disables forward-proxy functionality. Leaving forward proxying enabled unintentionally can create an open proxy and represents a serious security problem.
Because functionality is divided into modules, administrators can load only the features required by a particular system. A single Apache installation can terminate TLS, proxy REST API requests, balance traffic across a cluster, and upgrade WebSocket connections without loading unrelated protocol support. On Ubuntu and Debian systems, modules can be activated with a2enmod. Apache should then be restarted or reloaded, and the loaded proxy modules can be checked before configuring VirtualHost rules.
Understanding the mod_proxy Module Family
Apache reverse proxy support is not contained in one independent module. Instead, several related modules cooperate to handle different protocols, backend communication methods, and proxy capabilities. This modular structure makes Apache flexible enough to support many different web server architectures.
The central component is mod_proxy. It provides the underlying framework used for request forwarding, connection management, and proxy infrastructure. However, mod_proxy by itself cannot handle every type of application traffic. Protocol-specific modules perform the actual communication between the proxy and backend services.
This separation means an administrator can activate only the components needed for a deployment. A simple HTTP reverse proxy may require only mod_proxy and mod_proxy_http, whereas an environment using WebSockets, PHP-FPM, or load balancing can require several additional modules.
Each module adds a specific capability to the Apache proxy framework.
The Core mod_proxy Module
The base mod_proxy module provides Apache’s primary proxy engine. It contains the general mechanisms needed to pass requests between clients and backend servers, including proxy connection management, routing, shared directives, worker definitions, and communication flow between Apache and backend systems.
The core module also provides important directives including:
ProxyPassProxyPassReverseProxyRequests<Proxy>BalancerMember
Although mod_proxy supplies the common infrastructure, it does not handle ordinary HTTP proxy communication by itself. Additional protocol handlers are required according to the type of backend being used.
mod_proxy_http
mod_proxy_http is the proxy submodule used most frequently. It enables Apache to forward ordinary HTTP and HTTPS traffic to application servers.
In typical reverse proxy environments, it can handle communication between Apache and applications such as:
- Node.js applications
- Python web frameworks
- Internal Apache or Nginx servers
- Java application servers
- Containerized web applications
For example, when Apache forwards requests to an application listening at:
http://127.0.0.1:3000
the backend communication is performed through mod_proxy_http.
This module supports ordinary HTTP request and response processing, persistent backend connections, chunked transfer encoding, header forwarding, and HTTP protocol negotiation.
A common configuration looks like this:
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
Because HTTP and HTTPS are used by most modern web applications, mod_proxy_http is normally the first protocol-specific proxy module that administrators enable.
mod_proxy_balancer
The mod_proxy_balancer module adds load-balancing functionality to Apache’s proxy framework. Rather than sending every request to one backend server, Apache can divide incoming traffic among multiple backend nodes.
This capability is especially useful in high-availability environments or horizontally scaled architectures where several application instances process requests at the same time.
Apache provides several balancing methods, including:
- Request-count balancing with
byrequests - Traffic-volume balancing with
bytraffic - Pending-request balancing with
bybusyness
The module also supports session persistence, often called sticky sessions. With this configuration, subsequent requests from one client can continue to be routed to the same backend server.
A basic load-balanced configuration can look like this:
<Proxy "balancer://mycluster">
BalancerMember http://10.0.0.11:8080
BalancerMember http://10.0.0.12:8080
</Proxy>
ProxyPass / balancer://mycluster/
Internally, mod_proxy_balancer operates together with protocol modules such as mod_proxy_http, because the balancing module itself does not implement HTTP communication.
mod_proxy_wstunnel
Many modern applications use WebSockets for persistent real-time communication. Traditional HTTP proxy behavior alone is not sufficient for every WebSocket upgrade because a WebSocket connection changes from the ordinary HTTP request-response model to a persistent bidirectional connection.
mod_proxy_wstunnel enables Apache to proxy WebSocket connections with the ws:// and wss:// protocols. Apache 2.4.47 and newer can also process WebSocket upgrades through mod_proxy_http by using upgrade parameters, although mod_proxy_wstunnel continues to be commonly used.
Typical WebSocket use cases include:
- Real-time dashboards
- Chat applications
- Live notification systems
- Multiplayer game servers
- Streaming applications
When a client requests a WebSocket connection, Apache identifies the protocol upgrade and tunnels the persistent connection to the backend application.
A common WebSocket proxy configuration is:
ProxyPass /socket ws://127.0.0.1:3000/socket
ProxyPassReverse /socket ws://127.0.0.1:3000/socket
Without suitable WebSocket proxy support, Apache can return protocol-upgrade errors or fail to keep the WebSocket session open.
mod_proxy_fcgi
The mod_proxy_fcgi module lets Apache communicate with FastCGI backend services. This is particularly relevant for PHP installations that use PHP-FPM instead of the older embedded mod_php processing method.
PHP-FPM is widely used on modern Linux systems because it separates PHP execution from the Apache process, improving scalability, resource isolation, and operational flexibility.
Instead of forwarding HTTP requests, mod_proxy_fcgi sends FastCGI requests to FastCGI workers.
A typical PHP-FPM integration is:
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
</FilesMatch>
This configuration instructs Apache to send PHP requests through a Unix socket to the PHP-FPM service.
Although mod_proxy_fcgi is not generally used for standard HTTP reverse proxying, it remains part of the wider mod_proxy family and is commonly used in Apache-based PHP environments.
Comparing Common mod_proxy Submodules
The following table summarizes the main Apache proxy modules and their typical purposes:
| Module | Protocol Support | Common Use Case | Notes |
|---|---|---|---|
mod_proxy |
Core proxy framework | Base proxy infrastructure | Required for all proxy functionality |
mod_proxy_http |
HTTP, HTTPS | Reverse proxying web applications | Most frequently used proxy module |
mod_proxy_balancer |
Load-balancing framework | Distributing traffic across backend servers | Works together with protocol modules |
mod_proxy_wstunnel |
WebSocket (ws://, wss://) |
Proxying real-time applications | Handles protocol upgrades |
mod_proxy_fcgi |
FastCGI | PHP-FPM and FastCGI services | Common in PHP deployments |
For many current Ubuntu reverse proxy deployments, at least the following modules are typically enabled:
mod_proxy
mod_proxy_http
mod_headers
Other modules can be activated according to application requirements and the architecture of the deployment.
Step 1: Installing Apache and Verifying mod_proxy Availability
Before Apache can be configured as a reverse proxy, install Apache HTTP Server and confirm that the required proxy modules are available. On Ubuntu, the mod_proxy module family is included with the standard Apache package, although individual modules might not be enabled automatically.
Installing Apache on Ubuntu
Ubuntu provides Apache HTTP Server through the apache2 package. Start by refreshing the package index:
sudo apt update
Next, install Apache:
sudo apt install apache2
After installation, Ubuntu normally starts the Apache service automatically and enables it to launch during system boot.
Check the service status with:
sudo systemctl status apache2
If Apache started successfully, the output should resemble the following:
● apache2.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-05-19 06:59:03 UTC; 16s ago
Docs: https://httpd.apache.org/docs/2.4/
Main PID: 3083 (apache2)
Tasks: 55 (limit: 2318)
Memory: 5.1M (peak: 5.3M)
CPU: 51ms
CGroup: /system.slice/apache2.service
├─3083 /usr/sbin/apache2 -k start
├─3086 /usr/sbin/apache2 -k start
└─3087 /usr/sbin/apache2 -k start
You can also confirm that Apache responds locally with curl:
curl http://localhost
If Apache is operating correctly, the command returns the default Apache HTML page.
Understanding Apache Modules on Ubuntu
Apache follows a modular design. Features are supplied through separate modules instead of being compiled directly into one large server binary. Reverse proxy functionality is implemented through the mod_proxy family, which contains separate modules for different proxy protocols and features.
On Ubuntu, Apache modules are primarily managed through two directories:
/etc/apache2/mods-available/
This directory contains the module definitions installed on the system.
Modules that are enabled are linked into:
/etc/apache2/mods-enabled/
This directory structure lets administrators enable and disable Apache functionality without manually changing the main server configuration file.
Most proxy modules are provided as dynamically loadable shared modules. They can therefore remain disabled until required, reducing unnecessary functionality in the active Apache process.
Verifying Available Proxy Modules
Before activating reverse proxy features, verify that the required proxy modules are installed.
List available proxy-related modules with:
ls /etc/apache2/mods-available/ | grep proxy
The output should contain entries similar to:
proxy.conf
proxy.load
proxy_http.load
proxy_balancer.load
proxy_wstunnel.load
proxy_fcgi.load
This confirms that the relevant module files exist and can be activated.
Each file corresponds to part of the Apache proxy framework:
proxy.loadloads the mainmod_proxyframework.proxy_http.loadenables HTTP and HTTPS proxy communication.proxy_balancer.loadprovides load-balancing functionality.proxy_wstunnel.loadenables WebSocket proxy connections.proxy_fcgi.loadprovides FastCGI backend support, including PHP-FPM.
Every installation does not need every module, but confirming their availability establishes that the server can support later configuration steps.
Checking Which Modules Are Currently Loaded
A module can exist on disk without being enabled in the active Apache configuration.
Display all loaded modules with:
apache2ctl -M
To show only proxy modules, run:
apache2ctl -M | grep proxy
If proxy modules have already been activated, the output can resemble:
proxy_module (shared)
proxy_http_module (shared)
If no proxy modules are listed, they have not yet been enabled. The next step activates the required modules.
Verifying Apache Configuration Syntax
Before changing Apache configuration files, verify that the current configuration has valid syntax.
Run:
sudo apache2ctl configtest
If Apache detects no syntax problems, it returns:
Syntax OK
Running configtest before and after configuration changes is useful because Apache will refuse to reload an invalid configuration. Checking syntax early reduces avoidable downtime and simplifies troubleshooting.
Step 2: Enabling mod_proxy and Required Submodules
Once the proxy modules have been confirmed as available, activate the components required for reverse proxy operation. Ubuntu normally manages Apache modules with the a2enmod utility, which creates symbolic links from mods-available to mods-enabled.
Because Apache separates proxy functionality into several modules, enabling only the core mod_proxy component is usually not enough. Protocol-specific modules must also be enabled so Apache can communicate with backend systems.
For a standard HTTP reverse proxy, the minimum modules are:
mod_proxymod_proxy_http
Other modules may be required according to the deployment, including modules for load balancing, WebSockets, SSL proxying, or HTTP header manipulation.
Enabling the Core Proxy Modules
Activate the basic proxy framework and HTTP proxy module:
sudo a2enmod proxy
sudo a2enmod proxy_http
The proxy module provides the main proxy infrastructure, while proxy_http lets Apache forward HTTP and HTTPS requests to application servers.
After these commands run, symbolic links for the enabled module configuration files are created under:
/etc/apache2/mods-enabled/
Confirm that the links exist:
ls /etc/apache2/mods-enabled/ | grep proxy
The directory should now contain entries similar to:
proxy.conf
proxy.load
proxy_http.load
Enabling Additional Common Proxy Modules
Many reverse proxy configurations use additional Apache modules beyond the basic HTTP proxy components.
For example, mod_headers is commonly used to pass information about the client and manipulate request headers:
sudo a2enmod headers
If load balancing will be used, enable the balancing framework and request-based balancing method:
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
proxy_balancer supplies the balancing framework, while lbmethod_byrequests activates Apache’s request-count balancing algorithm.
For WebSocket support, enable:
sudo a2enmod proxy_wstunnel
If Apache will terminate SSL/TLS connections or communicate with HTTPS backends, also enable the SSL module:
sudo a2enmod ssl
Activating modules that will be used later can simplify subsequent configuration, particularly in testing environments.
Understanding What a2enmod Does
The a2enmod utility does not directly rewrite Apache’s primary configuration file. Instead, it activates modules by placing symbolic links in mods-enabled that point to module files located in mods-available.
For example, activating mod_proxy creates links similar to:
/etc/apache2/mods-enabled/proxy.load
/etc/apache2/mods-enabled/proxy.conf
This modular structure makes Apache easier to administer because individual features can be enabled and disabled independently without manually maintaining one large configuration file.
A module can later be disabled with a2dismod:
sudo a2dismod proxy_wstunnel
Do not disable a module that is still referenced by active VirtualHost configurations, because Apache may be unable to start when required directives are unavailable.
Verifying Loaded Modules
After activating the necessary modules, verify that Apache loads them successfully.
Run:
apache2ctl -M | grep proxy
The output should resemble:
proxy_module (shared)
proxy_http_module (shared)
proxy_balancer_module (shared)
proxy_wstunnel_module (shared)
Check the headers module as well:
apache2ctl -M | grep headers
The expected output is:
headers_module (shared)
Checking loaded modules at this stage helps prevent errors later when Apache encounters directives belonging to modules that have not been activated.
Restarting Apache After Enabling Modules
Restart Apache after activating new modules so they become available:
sudo systemctl restart apache2
Verify that Apache restarted correctly:
sudo systemctl status apache2
If Apache encounters a configuration or module-loading problem during startup, the service status usually contains a brief explanation. More detailed information is written to:
/var/log/apache2/error.log
Before continuing, validate the configuration again:
sudo apache2ctl configtest
With a valid configuration, Apache returns:
Syntax OK
Apache is now prepared for reverse proxy configuration.
Step 3: Configuring a Basic Reverse Proxy with ProxyPass
With the required modules active, Apache can now be configured as a reverse proxy. In a basic setup, Apache receives client requests and forwards them to an application server running either locally or on another machine in the internal network.
The main directives responsible for this behavior are ProxyPass and ProxyPassReverse.
In this example, Apache accepts public requests on port 80 and sends them to a backend application at:
http://127.0.0.1:3000
This configuration pattern is commonly used for applications based on Node.js, Django, Flask, Express, Spring Boot, and similar application frameworks where the application server itself should not be exposed directly to the public internet.
Understanding Reverse Proxy Request Flow
Before configuring the proxy, it helps to understand how traffic passes through the frontend layer.
In a reverse proxy setup:
- A client sends a request to Apache.
- Apache receives the request on behalf of the backend application.
- Apache forwards the request internally to the backend server.
- The backend application processes the request and generates a response.
- Apache returns that response to the client.
The client does not establish a direct connection to the backend application server.
This allows Apache to provide a stable public-facing layer while backend services remain isolated from direct internet exposure.
Disabling Forward Proxying
One of the most important security requirements in a reverse proxy setup is ensuring that forward proxy functionality remains disabled.
Apache can function as either:
- A reverse proxy
- A forward proxy
A forward proxy accepts requests from clients and retrieves arbitrary external resources for them. Unless that behavior is deliberately required, it should remain disabled because an unrestricted forward proxy can be abused by third parties.
To ensure that Apache is used only as a reverse proxy, configure:
ProxyRequests Off
This directive can be placed inside the relevant VirtualHost or an appropriate proxy configuration file.
Do not enable ProxyRequests unless a controlled forward proxy is intentionally being configured.
Understanding ProxyPass
The ProxyPass directive tells Apache to send requests for a particular frontend URL path to a backend server.
The general syntax is:
ProxyPass <frontend-path> <backend-url>
For example:
ProxyPass / http://127.0.0.1:3000/
This sends every request below / to the application running on port 3000.
If a client requests:
http://your-server-ip/about
Apache internally forwards that request to:
http://127.0.0.1:3000/about
The backend processes the request normally, after which Apache passes the response to the client.
Trailing slashes in ProxyPass mappings are significant because they influence how frontend and backend paths are combined. Inconsistent slash placement can lead to unexpected URL mapping behavior.
Understanding ProxyPassReverse
ProxyPassReverse modifies certain response headers returned by a backend before Apache sends them to the client.
This is necessary because backend applications can generate redirects or response headers containing internal URLs instead of the public URL exposed by the proxy.
For example, a backend might return:
Location: http://127.0.0.1:3000/login
Without ProxyPassReverse, the internal backend address could be sent directly to the client, potentially breaking routing and revealing internal infrastructure information.
Add:
ProxyPassReverse / http://127.0.0.1:3000/
Apache can then rewrite matching backend-generated response headers so clients continue using the public proxy address.
For this reason, ProxyPass and ProxyPassReverse are generally configured together.
Creating a Basic Reverse Proxy VirtualHost
Apache uses VirtualHost blocks to route incoming traffic. On Ubuntu, site configurations are normally stored in:
/etc/apache2/sites-available/
Create a new configuration file:
sudo nano /etc/apache2/sites-available/reverse-proxy.conf
Add the following configuration:
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog ${APACHE_LOG_DIR}/reverse-proxy-error.log
CustomLog ${APACHE_LOG_DIR}/reverse-proxy-access.log combined
</VirtualHost>
This configuration performs several functions:
- Apache accepts HTTP requests on port
80. - Forward proxy functionality remains disabled.
- Incoming traffic is passed to the backend application.
- Backend-generated redirects are rewritten appropriately.
- Separate access and error logs are maintained for troubleshooting.
ProxyPreserveHost On causes Apache to pass the original client Host header to the backend instead of replacing it with the backend hostname. Many applications use the original host value for routing, redirects, multi-tenant configuration, or framework behavior.
Enabling the VirtualHost Configuration
After saving the configuration, enable the site:
sudo a2ensite reverse-proxy.conf
If the standard Apache site remains active, it can optionally be disabled to avoid conflicts:
sudo a2dissite 000-default.conf
Validate the configuration before restarting Apache:
sudo apache2ctl configtest
A valid configuration returns:
Syntax OK
Restart Apache:
sudo systemctl restart apache2
Testing the Reverse Proxy
After Apache restarts, test the configuration by visiting:
http://your-server-ip
or:
http://your-domain.com
If the backend application is running, its content should be delivered through Apache rather than being accessed directly from the backend port.
The proxy can also be tested with:
curl -I http://your-server-ip
The returned headers should show that Apache handled the frontend request while the backend application supplied the content.
Apache is now operating as a basic reverse proxy.
Step 4: Forwarding Client Information with Proxy Headers
In a reverse proxy architecture, backend applications do not communicate directly with clients. Requests first reach Apache and are then passed to the application server. Consequently, the backend can see the proxy server as the source of every request unless Apache forwards information about the original client through HTTP headers.
If these headers are not handled properly, backend applications can record the wrong client IP addresses, generate incorrect redirects, fail to recognize HTTPS connections, or apply security policies incorrectly.
Apache can preserve useful details from the original request, including:
- The client’s IP address
- The hostname requested by the client
- The original protocol, either
HTTPorHTTPS - Custom metadata headers
These values are normally passed through proxy headers or forwarded headers.
Why Forwarded Headers Matter
A typical reverse proxy request follows this path:
Client ---> Apache Reverse Proxy ---> Backend Application
From the backend application’s perspective, the TCP connection originates from Apache rather than directly from the user’s browser. Without forwarded information, the backend can therefore interpret:
- Apache’s IP address as the client address
- An internal hostname as the public hostname
- HTTP as the connection protocol even when the original user connected through HTTPS
This can create several production issues.
For example:
- Application logs may contain only the proxy address.
- Rate-limiting mechanisms can fail because all requests appear to originate from a single system.
- Authentication logic may incorrectly determine request origins.
- Redirects can point to internal addresses.
- Secure cookies can fail when the application cannot identify the original HTTPS connection.
Forwarded headers preserve the original request context and allow backend applications to behave correctly behind the proxy.
Preserving the Original Host Header
During proxying, Apache can replace the incoming Host header with the backend hostname. Some applications depend on the public Host value for domain routing, multi-tenant logic, configuration, or URL generation.
To retain the hostname originally requested by the client, use:
ProxyPreserveHost On
For example, when a client requests:
https://app.example.com
Apache can preserve that host value instead of passing the internal backend address:
127.0.0.1:3000
This is particularly useful for:
- Applications using virtual-host routing
- Frameworks generating absolute URLs
- Multi-domain deployments
- OAuth and authentication callbacks
- Applications operating behind an HTTPS proxy
For many modern reverse proxy deployments, ProxyPreserveHost On is appropriate unless the backend application specifically expects a different host value.
Forwarding the Original Client IP Address
X-Forwarded-For is one of the most commonly used proxy headers.
It provides the original client IP address so backend applications can distinguish the actual request source from the proxy server.
Apache can automatically add forwarding headers with:
ProxyAddHeaders On
This setting is already enabled by default in many Apache configurations, but declaring it explicitly makes the intended behavior clearer.
Apache can then add headers similar to:
X-Forwarded-For: 203.0.113.25
X-Forwarded-Host: app.example.com
X-Forwarded-Server: proxy-server
The backend can inspect X-Forwarded-For to determine the original client address.
When traffic passes through several proxies or content-delivery layers, this header can contain a comma-separated chain of addresses representing each proxy hop.
Forwarding HTTPS and Protocol Information
Backend applications frequently need to determine whether the user originally connected through HTTP or HTTPS.
This affects behavior such as:
- Secure cookies
- Redirect generation
- Authentication
- CSRF protection
- URL generation
If Apache terminates HTTPS and then communicates with a backend through HTTP, the backend only sees the internal HTTP connection unless the original protocol is forwarded separately.
A common solution is to send X-Forwarded-Proto:
RequestHeader set X-Forwarded-Proto "https"
This tells the application that the public client connection used HTTPS even when the internal proxy connection uses HTTP.
The value can also be selected dynamically:
RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
This forwards either http or https according to the protocol used by the incoming request.
Because RequestHeader belongs to mod_headers, make sure that module is enabled:
sudo a2enmod headers
Setting Custom Proxy Headers
Apache also supports custom headers that can be passed to backend services.
For example:
RequestHeader set X-Proxy-Server "Apache-Reverse-Proxy"
Custom request headers can be useful for:
- Identifying internal services
- Debugging and tracing requests
- Application-specific routing
- API gateway integration
- Security metadata
Headers can also be removed:
RequestHeader unset X-Unwanted-Header
This provides detailed control over the request information sent to backend applications.
Complete VirtualHost Example with Forwarded Headers
The following example combines several common reverse proxy header settings:
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
ProxyAddHeaders On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
ErrorLog ${APACHE_LOG_DIR}/reverse-proxy-error.log
CustomLog ${APACHE_LOG_DIR}/reverse-proxy-access.log combined
</VirtualHost>
This allows the backend application to receive:
- The hostname originally requested by the client
- The original client IP address
- The original request protocol
- Correctly rewritten redirect information
Together, these settings allow applications to retain the necessary client context while operating behind Apache.
Applying the Configuration Changes
After changing the VirtualHost, validate the Apache configuration:
sudo apache2ctl configtest
If the syntax is valid, reload Apache:
sudo systemctl reload apache2
A reload applies the updated configuration without performing a complete web server restart.
Verifying Forwarded Headers
Forwarded headers can be verified through the backend application or by inspecting the headers received by a diagnostic endpoint.
Many application frameworks provide access to incoming request headers. A temporary backend that echoes request headers can also be used to verify that Apache passes the expected information.
A properly forwarded request can contain:
X-Forwarded-For: 203.0.113.25
X-Forwarded-Host: example.com
X-Forwarded-Proto: https
The reverse proxy now preserves the original request context for the backend application.
Step 5: Configuring Load Balancing with mod_proxy_balancer
Apache can distribute incoming traffic among several backend servers with mod_proxy_balancer. This can improve scalability and availability while preventing one application server from handling every request.
In a load-balanced architecture, Apache is positioned in front of multiple backend application instances and selects a destination according to a configured balancing algorithm.
Enabling the Load Balancing Modules
Activate the required modules before creating a balancer:
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
proxy_balancer provides the core balancing framework, while lbmethod_byrequests supplies request-based distribution.
Reload Apache:
sudo systemctl reload apache2
Defining Backend Servers with BalancerMember
Apache organizes backend systems into a logical pool by using a <Proxy> block. Individual servers are registered through BalancerMember.
For example:
<Proxy "balancer://mycluster">
BalancerMember http://127.0.0.1:3001
BalancerMember http://127.0.0.1:3002
</Proxy>
Here, balancer://mycluster identifies the backend pool, while every BalancerMember entry represents one application server.
Apache can then distribute requests among those members automatically.
Configuring the Load Balancing Method
Apache provides several balancing algorithms. Common options are:
| Method | Description |
|---|---|
byrequests |
Distributes traffic according to request count |
bytraffic |
Balances based on the amount of data transferred |
bybusyness |
Sends requests toward the least busy backend |
For many environments, byrequests provides a straightforward balancing strategy.
The method can be configured with ProxySet:
ProxySet lbmethod=byrequests
Configuring Sticky Sessions
Some applications keep session information locally on an individual backend server. In that situation, repeated requests from one client need to continue reaching the same node. This behavior is known as session persistence or sticky sessions.
Apache supports this with the stickysession setting.
For example:
<Proxy "balancer://mycluster">
BalancerMember http://127.0.0.1:3001 route=node1
BalancerMember http://127.0.0.1:3002 route=node2
ProxySet lbmethod=byrequests stickysession=ROUTEID
</Proxy>
Each backend receives a route identifier. The application must then create a cookie containing the corresponding route value so Apache can continue directing that client’s requests to the appropriate server.
Sticky sessions are particularly relevant when session data is not stored in a shared system accessible to every backend node.
Complete Load Balancer Configuration Example
The following configuration uses Apache as a reverse proxy load balancer for two backend applications:
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
<Proxy "balancer://mycluster">
BalancerMember http://127.0.0.1:3001
BalancerMember http://127.0.0.1:3002
ProxySet lbmethod=byrequests
</Proxy>
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
ErrorLog ${APACHE_LOG_DIR}/balancer-error.log
CustomLog ${APACHE_LOG_DIR}/balancer-access.log combined
</VirtualHost>
Apache accepts requests on port 80 and distributes them between the two application servers.
Testing the Load Balancer
After saving the configuration, validate Apache syntax:
sudo apache2ctl configtest
If the configuration is valid, reload Apache:
sudo systemctl reload apache2
Send several requests to the proxy:
curl http://your-server-ip
If the backend applications return distinguishable responses, repeated requests should demonstrate that Apache is distributing traffic between the servers.
Apache can now balance incoming requests across multiple backends with mod_proxy_balancer.
Step 6: Enabling SSL Termination at the Proxy Layer
In many production environments, Apache handles HTTPS at the reverse proxy rather than requiring every backend application server to maintain separate SSL/TLS configuration. This design is commonly described as SSL termination or TLS offloading.
The client establishes an encrypted HTTPS connection with Apache. Apache decrypts the incoming traffic and then forwards requests internally through either HTTP or HTTPS.
Centralizing TLS at the proxy reduces duplicated configuration, simplifies certificate management, and allows HTTPS policies to be enforced consistently.
Enabling the SSL Module
Before creating an HTTPS VirtualHost, enable Apache’s SSL module:
sudo a2enmod ssl
Reload Apache:
sudo systemctl reload apache2
Obtaining an SSL Certificate
HTTPS requires a valid SSL certificate and its associated private key. A self-signed certificate can be used for local development or testing.
Production environments normally use a certificate issued by Let’s Encrypt or another trusted certificate authority.
Ubuntu installations commonly store certificates in directories such as:
/etc/ssl/certs/
Private keys are commonly stored under:
/etc/ssl/private/
When Let’s Encrypt and Certbot are used, certificate files are typically located below /etc/letsencrypt/live/your-domain/.
Configuring HTTPS Reverse Proxying
Create or edit the HTTPS site configuration:
sudo nano /etc/apache2/sites-available/reverse-proxy-ssl.conf
Add a configuration similar to:
<VirtualHost *:443>
ServerName example.com
SSLEngine On
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
ProxyRequests Off
ProxyPreserveHost On
ProxyAddHeaders On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
RequestHeader set X-Forwarded-Proto "https"
ErrorLog ${APACHE_LOG_DIR}/ssl-proxy-error.log
CustomLog ${APACHE_LOG_DIR}/ssl-proxy-access.log combined
</VirtualHost>
With this configuration, Apache accepts HTTPS connections on port 443, decrypts them, and passes requests to the application listening on port 3000.
X-Forwarded-Proto informs the backend application that the original client request used HTTPS.
Proxying to HTTPS Backends
Some backend application servers also use HTTPS. Apache must establish a separate encrypted connection when forwarding requests to such servers.
Enable HTTPS backend proxying with:
SSLProxyEngine On
Requests can then be sent to an HTTPS backend:
ProxyPass / https://127.0.0.1:8443/
ProxyPassReverse / https://127.0.0.1:8443/
Without SSLProxyEngine On, Apache will not establish HTTPS proxy connections to backend servers.
Configuring Backend Certificate Verification
When communicating with HTTPS backends, Apache can verify their certificates to prevent connections to untrusted systems.
Certificate verification is controlled through settings such as:
SSLProxyVerify require
SSLProxyCheckPeerName On
SSLProxyCheckPeerExpire On
These directives tell Apache to:
- Require a trusted backend certificate.
- Verify the backend hostname.
- Check that the certificate has not expired.
In internal testing environments that use self-signed certificates, verification is sometimes disabled temporarily:
SSLProxyVerify none
SSLProxyCheckPeerName Off
Disabling certificate verification reduces connection security and should generally be avoided in production.
Redirecting HTTP Traffic to HTTPS
Production reverse proxies commonly redirect ordinary HTTP traffic to HTTPS.
A separate HTTP VirtualHost can perform the redirect:
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
This ensures clients use encrypted HTTPS connections.
Enabling the HTTPS Site
Enable the HTTPS configuration:
sudo a2ensite reverse-proxy-ssl.conf
Check the configuration:
sudo apache2ctl configtest
If the syntax is valid, reload Apache:
sudo systemctl reload apache2
Testing HTTPS Proxying
Test the HTTPS reverse proxy by visiting:
https://your-domain.com
The SSL connection can also be checked with:
curl -I https://your-domain.com
If the configuration is correct, Apache terminates the HTTPS client connection and forwards the request successfully to the backend.
Apache is now handling encrypted client connections at the reverse proxy layer.
Step 7: Security Hardening for the Proxy Configuration
After configuring Apache as a reverse proxy, the proxy layer should be secured carefully. An incorrectly configured reverse proxy can reveal internal systems, permit unintended proxy behavior, or unnecessarily increase the attack surface.
Ensure Forward Proxying Is Disabled
Disabling forward proxy operation is one of the most important security requirements.
Always make sure the following directive is configured:
ProxyRequests Off
If forward proxying is unintentionally enabled, outside users may be able to relay arbitrary traffic through the server. Open proxies are commonly abused for spam, malicious routing, and anonymity.
For ordinary reverse proxy installations, ProxyRequests Off should be defined globally or within every proxy-enabled VirtualHost.
Restrict Proxy Access with <Proxy> Blocks
Apache supports access-control rules for proxied resources through <Proxy> and <ProxyMatch> containers.
For example:
<Proxy "*">
Require all denied
</Proxy>
This blocks access to forward proxy destinations unless they are specifically allowed.
Access to selected backend paths or internal services can also be restricted:
<Proxy "http://127.0.0.1:3000/admin">
Require ip 192.168.1.0/24
</Proxy>
Such restrictions are especially important when a reverse proxy exposes internal application functionality.
Hide Backend and Server Information
Apache and backend applications can expose unnecessary technology information through headers such as:
Server: Apache/2.4.58
X-Powered-By: Express
These headers can disclose software versions or backend technologies that can be useful during reconnaissance.
Server information can be reduced by configuring:
ServerTokens Prod
ServerSignature Off
Backend-specific headers can also be removed with mod_headers:
Header unset X-Powered-By
ServerTokens Prod
ServerSignature Off
Headers generated directly by a backend may require additional configuration within that application.
Reducing these details limits the amount of infrastructure information exposed publicly.
Configure Timeouts Carefully
Unsuitable timeout values can leave Apache resources occupied by stalled backend connections or contribute to resource-exhaustion problems.
Relevant settings include:
ProxyTimeout 30
Timeout 60
ProxyTimeout controls how long Apache waits for backend responses, while Timeout affects general request processing.
Reasonable values prevent unresponsive backend connections from consuming worker resources indefinitely.
Apply Rate Limiting When Necessary
Internet-facing reverse proxies can benefit from rate limiting to reduce abusive traffic and denial-of-service attempts.
Apache has several traffic-control modules, including:
mod_ratelimitmod_evasivemod_qos
For example, mod_ratelimit can restrict response bandwidth for selected locations or content types.
Advanced rate-limiting configuration is a separate topic, but some form of request throttling can be useful for publicly exposed services.
Restrict Access to Administrative Interfaces
Administrative endpoints such as Balancer Manager should not be exposed publicly without restrictions.
For example:
<Location "/balancer-manager">
SetHandler balancer-manager
Require local
</Location>
If remote administrative access is needed, limit it through IP-based rules or authentication.
An unrestricted management interface can reveal backend infrastructure details and provide access to balancing controls.
Test for Open Proxy Behavior
After configuring the reverse proxy, verify that Apache is not operating as an unintended forward proxy.
A simple test can be performed with:
curl -x http://your-server-ip:80 http://example.com
If Apache rejects the request, it is not functioning as an open proxy.
If the request unexpectedly succeeds, immediately check that:
ProxyRequests Offis configured.- No overly permissive
<Proxy>rules exist. - No unintended forward proxy configuration is active.
Keep Apache and Modules Updated
Because a reverse proxy is normally located at the network edge, keeping Apache and its modules current is important.
Regularly update installed packages with:
sudo apt update
sudo apt upgrade
Security updates can address problems involving:
- HTTP request parsing
- TLS weaknesses
- Request smuggling
- Denial-of-service vulnerabilities
- Module-specific security flaws
Applying security updates promptly reduces exposure to publicly documented vulnerabilities.
Validate Configuration Changes
After making security-related modifications, check Apache syntax:
sudo apache2ctl configtest
If the syntax is valid, reload Apache:
sudo systemctl reload apache2
The reverse proxy configuration is now better protected and more suitable for production use.
Troubleshooting Common mod_proxy Errors
Small configuration mistakes can prevent Apache from communicating properly with backend applications. Incorrect backend addresses, unavailable modules, SSL verification problems, and header errors can all lead to proxy failures.
When diagnosing Apache reverse proxy issues, first examine the error log:
/var/log/apache2/error.log
Monitor the file continuously with:
sudo tail -f /var/log/apache2/error.log
Configuration validation is also important before reloading Apache:
sudo apache2ctl configtest
If Apache returns:
Syntax OK
the configuration is syntactically valid.
The following sections describe several common mod_proxy problems.
502 Bad Gateway
A 502 Bad Gateway response usually means Apache could not communicate successfully with the configured backend application server.
Common causes include:
- The backend application is stopped.
- The backend is listening on a different port.
- A firewall is blocking the connection.
- The
ProxyPassdestination is incorrect. - The backend crashes or exceeds a timeout.
For example, if Apache forwards requests to:
ProxyPass / http://127.0.0.1:3000/
but no service is listening on port 3000, Apache returns a 502 response.
Check whether a service is listening:
sudo ss -tulpn | grep 3000
Test the backend directly:
curl http://127.0.0.1:3000
If the backend does not respond locally, the problem is with the application or its configuration rather than the Apache proxy.
The Apache log can contain an entry such as:
AH01114: HTTP: failed to make connection to backend
This normally indicates a connection failure between Apache and the backend service.
503 Service Unavailable
A 503 Service Unavailable error frequently appears in environments using mod_proxy_balancer.
It generally means Apache considers all configured workers unavailable.
Possible causes include:
- All backend servers are offline.
- Health checks are failing.
BalancerMemberdefinitions are incorrect.- Backend requests are timing out.
- DNS resolution is failing.
For example:
<Proxy "balancer://mycluster">
BalancerMember http://127.0.0.1:3001
BalancerMember http://127.0.0.1:3002
</Proxy>
Test each backend directly:
curl http://127.0.0.1:3001
curl http://127.0.0.1:3002
When a backend is unavailable, Apache can temporarily mark it as unusable until it recovers.
The error log can include:
AH01170: balancer://mycluster: All workers are in error state
This indicates that Apache could not find a usable backend server for the request.
SSL Handshake Failures to HTTPS Backends
When Apache proxies requests to HTTPS backends, the TLS negotiation can fail.
Common causes include:
- Invalid or expired backend certificates
- Self-signed certificates
- Hostname mismatches
- Missing
SSLProxyEngine On - Certificate verification failures
For example:
SSLProxyEngine On
ProxyPass / https://127.0.0.1:8443/
When certificate verification fails, Apache may log an error such as:
AH02039: Certificate Verification: Error
For temporary internal testing with self-signed certificates, verification is sometimes disabled:
SSLProxyVerify none
SSLProxyCheckPeerName Off
Certificate verification should remain enabled in production whenever possible.
Test the HTTPS backend directly with:
curl -k https://127.0.0.1:8443
Header Forwarding Not Working Correctly
Backend applications can fail to recognize the original client address, hostname, or HTTPS status when forwarding headers are missing or configured incorrectly.
Typical symptoms include:
- The application records the proxy address instead of the client address.
- Redirect URLs are incorrect.
- Secure cookies do not work as expected.
- The application fails to detect HTTPS.
Verify that the appropriate directives are configured:
ProxyPreserveHost On
ProxyAddHeaders On
RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
Also ensure mod_headers is enabled:
sudo a2enmod headers
Forwarded values can be inspected from the backend application or through a diagnostic endpoint that displays request headers.
Module Not Found or Unknown Directive Errors
Apache reports directive-related errors when the module that provides a configuration directive has not been enabled.
A common example is:
Invalid command 'ProxyPass'
or:
Invalid command 'RequestHeader'
These messages usually indicate that the corresponding proxy or headers module is disabled.
Enable the necessary modules:
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod headers
Reload Apache:
sudo systemctl reload apache2
Loaded modules can be checked with:
apache2ctl -M
Diagnosing Backend Connectivity Problems
If Apache cannot connect to a backend, verify:
- The backend service is running.
- The configured IP address and port are correct.
- No firewall rule blocks the required connection.
- The backend is listening on the expected network interface.
Useful diagnostic commands include:
ss -tulpn
curl http://127.0.0.1:3000
Testing the backend without the proxy helps determine whether the problem belongs to Apache or to the backend application itself.
Reload Apache After Configuration Changes
After correcting configuration problems, validate and reload Apache:
sudo apache2ctl configtest
sudo systemctl reload apache2
Using reload instead of a full restart applies configuration updates without completely interrupting active connections.
At this stage, Apache has been configured as a reverse proxy through the mod_proxy module family with forwarded headers, load balancing, SSL termination, WebSocket proxy support, and basic security hardening.
Frequently Asked Questions
1. What Is the Difference Between ProxyPass and ProxyPassReverse?
ProxyPass maps incoming frontend request URLs to a backend URL. ProxyPassReverse adjusts response headers such as Location, Content-Location, and URI so redirects generated by the backend refer to the public frontend URL instead of exposing the internal backend address.
2. Do I Need ProxyRequests On to Use Apache as a Reverse Proxy?
No. ProxyRequests On enables forward proxy functionality, allowing clients to route arbitrary external requests through Apache. A reverse proxy should normally use ProxyRequests Off and define explicit backend mappings through ProxyPass. Enabling ProxyRequests On without appropriate restrictions can create an open proxy.
3. Which mod_proxy Submodule Is Required for HTTP and HTTPS Backend Connections?
mod_proxy_http is required for proxying HTTP and HTTPS application traffic. The core mod_proxy module alone is not sufficient. When Apache connects to an HTTPS backend, mod_ssl and SSLProxyEngine On are also required.
4. How Do I Enable mod_proxy on Ubuntu or Debian?
Run sudo a2enmod proxy proxy_http and then restart Apache with sudo systemctl restart apache2. For load balancing, also activate proxy_balancer and a balancing module such as lbmethod_byrequests.
5. How Does Apache mod_proxy Compare with Nginx as a Reverse Proxy?
Apache mod_proxy integrates directly with existing Apache configurations and benefits from Apache’s extensive module system. Nginx uses an event-driven, non-blocking architecture and is often selected for reverse proxy environments requiring very high concurrency. On systems that already use Apache, mod_proxy provides reverse proxy functionality without requiring an additional web server process.
6. Can Apache mod_proxy Handle WebSocket Connections?
Yes. The mod_proxy_wstunnel module supports WebSocket proxying. ProxyPass directives can use the ws:// or wss:// schemes to send WebSocket traffic to backend applications. The required proxy modules must be enabled for this configuration.
7. What Causes a 502 Bad Gateway Error When Using mod_proxy?
A 502 response normally indicates that Apache could not communicate successfully with the backend application or received an invalid backend response. Common causes include a stopped backend process, an incorrect backend port in ProxyPass, firewall restrictions between Apache and the backend, or a timeout. Examine Apache’s error.log and test the backend directly with tools such as curl or nc.
8. How Do I Pass the Original Client IP Address to the Backend?
Enable ProxyAddHeaders On and ProxyPreserveHost On in the relevant VirtualHost. Apache can then add headers such as X-Forwarded-For and X-Forwarded-Host. When TLS is terminated by Apache, also provide X-Forwarded-Proto through RequestHeader so the backend can identify the original HTTPS connection.
Conclusion
This tutorial demonstrated how to configure Apache as a reverse proxy on Ubuntu with the mod_proxy module family. Apache was installed and the required proxy modules were enabled. Request forwarding was configured through ProxyPass and ProxyPassReverse, original client information was preserved with forwarded headers, traffic was distributed among several application servers with mod_proxy_balancer, and SSL termination was configured at the frontend proxy. Security-hardening measures and common approaches for diagnosing mod_proxy errors were also covered.
This foundation can be extended with more advanced configurations, including path-based routing across multiple applications, WebSocket proxying with mod_proxy_wstunnel, and backend health checks through mod_proxy_hcheck. Additional technical details are available in the Apache mod_proxy documentation.


