Advanced Deployment Hints
Custom Apache Configuration
Configuring Apache for HAProxy ProxyProtocol
Objective: Prevent SSL handshake failures when traffic is routed through HAProxy using the Proxy Protocol. Without this configuration, Apache interprets the incoming plain-text Proxy Protocol header as a malformed SSL record, which drops the connection and generates an SSL error.
Step 1: Access the Container Open an interactive bash shell inside your running Apache container.
docker exec -it apache bash
Step 2: Edit the Configuration File Open the target configuration file using vim.
vim /usr/local/apache2/conf-volume/httpd.conf.default
Step 3: Enable the RemoteIP Module
Apache requires mod_remoteip to parse the incoming Proxy Protocol headers. Search for the following line and remove the # at the beginning to load the module:
LoadModule remoteip_module modules/mod_remoteip.so
Step 4: Configure the Proxy Protocol Add the following directive to instruct Apache to accept the Proxy Protocol. This consumes the Proxy Protocol header before initiating the SSL handshake, preventing the SSL error.
RemoteIPProxyProtocol On
Warning
If your Apache server is accessible from any network, port, or container other than your HAProxy instance, you must also add the RemoteIPTrustedProxy [HAPROXY_IP] directive. Without this IP restriction, any direct connection can easily spoof client IP addresses by sending arbitrary Proxy Protocol headers. See here for more information.
Step 5: Configure Exceptions for Internal Container Traffic Objective: Prevent Apache from rejecting direct connections from other containers on the same Docker network that do not pass through HAProxy and therefore do not carry a Proxy Protocol header.
When RemoteIPProxyProtocol On is set globally, Apache expects every incoming connection to begin with a PROXY header. Containers communicating directly with Apache (e.g. via /etc/hosts entries) bypass HAProxy and will cause an EOF error since no PROXY header is prepended.
The RemoteIPProxyProtocolExceptions directive whitelists specific IP ranges from this requirement.
Step 5.1: Identify the Docker network subnet
docker network inspect tg-ems | grep Subnet
This will output something like "Subnet": "10.10.0.0/24". The target network is fixed to 10.10.0.0/24 in this deployment.
Step 5.2: Add the exception directive
In the same configuration file edited above (httpd.conf.default), add the following line directly below RemoteIPProxyProtocol On:
RemoteIPProxyProtocol On
RemoteIPProxyProtocolExceptions 10.10.0.0/24
This allows containers within the Docker network to connect to Apache directly without a PROXY header, while HAProxy-routed traffic continues to be processed normally.
Step 5.3 (Optional): Pin the Subnet IP If the Docker network subnet ever changes (e.g. after manually recreating the network), this directive must be updated to reflect the new subnet.
To pin the subnet, create a docker-compose.override.yml in /home/groupios with the following content (adjust the subnet to match your environment):
networks:
tg-ems:
external: false
name: tg-ems
ipam:
config:
- subnet: 10.10.0.0/24
Then update the COMPOSE_FILE variable in /home/groupios/.env to include the override file first, as shown in the following example:
COMPOSE_FILE='docker-compose.override.yml:docker-compose.common.yml:docker-compose.prod.yml:docker-compose.manager.yml:docker-compose.ciphermail.yml'
The order matters - docker-compose.override.yml must appear before the other files.
Note
Changing to a different subnet requires you to recreate the Docker network, and therefore, requires the connected containers to be stopped.
We thus recommend only pinning the currently used subnet. Alternatively, the network can be recreated using docker compose down followed by docker compose up -d --force-recreate in the /home/groupios directory.
Step 6: Apply the Changes To apply the updated default configuration, exit the Apache container and restart the core-api container.
exit
docker restart core-api