Passing system variable to Apache stopped working - apache

We rebooted one of our servers over the weekend and now Apache won't pass through the host name - not sure whats wrong. Here's my config:
LoadModule headers_module modules/mod_headers.so
LoadModule env_module modules/mod_env.so
<IfModule headers_module>
<IfModule env_module>
PassEnv HOSTNAME
Header always set X-Host-Name "%{HOSTNAME}e"
</IfModule>
</IfModule>
I am running as a user other than root. I am able to execute sudo -u websrv "printenv" and the value for HOSTNAME appears appropriately.
Not sure whats going on

Related

Docker container running apache always exposing port 80

I have a Docker image that runs Apache, and I have configured Apache (through httpd.conf) to listen on port 8080.
Listen 8080
When I build my image and run it, I'm able to successfully connect to my website via port 8080, so all seems well at this point.
docker build -t my/apache:8080 .
docker run --name "MyWebsite" -p 8080:8080 -v ~/dir:/mnt/dir -d -t my/apache:8080
However, when I list my running containers using docker ps, I see that port 80 has also been exposed for some reason.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23c4e1f0ea66 my/apache:8080 "/docker-entrypoint.…" 12 minutes ago Up 12 minutes 80/tcp, 0.0.0.0:8080->8080/tcp MyWebsite
When I shell on to the running container and search for instances of "Listen 80", nothing shows up other than the instance of "Listen 8080" that I added to httpd.conf.
docker exec -it 23c4e1f0ea66 /bin/bash
grep -ri "Listen 80"
My Dockerfile contains only one EXPOSE declaration - EXPOSE 8080. However, I don't believe this actually exposes the port anyway, and is intended more as a way of documenting which port should be exposed when running a container that utilizes the image.
How can I find out when is exposing port 80, and crucially, how can I stop it from being exposed?
Dockerfile
FROM httpd:2.4
COPY httpd.conf /usr/local/apache2/conf/
COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["apache"]
### Apache (proxies to MapProxy).
EXPOSE 8080
Entrypoint script
#!/bin/bash
set -e
if [ "$1" = 'apache' ]; then
echo "Starting Apache"
httpd-foreground
fi
exec "$#"
HTTP config
ServerRoot "/usr/local/apache2"
Listen 8080
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
<IfModule !mpm_prefork_module>
</IfModule>
<IfModule mpm_prefork_module>
</IfModule>
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
<IfModule unixd_module>
User daemon
Group daemon
</IfModule>
ServerAdmin applicationdelivery#landmark.co.uk
ServerName mapproxy.gcs.lmkcloud.net:8080
DocumentRoot "/usr/local/apache2/htdocs"
ErrorLog /proc/self/fd/2
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog /proc/self/fd/1 common
</IfModule>
<IfModule mime_module>
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
</IfModule>
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
ProxyPreserveHost On
ProxyPass / http://example.com:8001/ retry=1 acquire=3000 timeout=20 Keepalive=On
ProxyPassReverse / http://example.com:8001/
Port 80 is exposed by the parent Dockerfile for httpd:2.4 image -
https://github.com/docker-library/httpd/blob/75e85910d1d9954ea0709960c61517376fc9b254/2.4/Dockerfile
A EXPOSE statement inside Dockerfile is going to give you an output eventually in docker ps. However, that's exposed only to the container network & will not allow communication via the defined ports to containers outside of the same network or to the host machine. To allow this to happen you need to publish the ports.
Example -
docker run -dit --expose 8008 httpd:2.4
Output -
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d628b537aded httpd:2.4 "httpd-foreground" 3 seconds ago Up 2 seconds 80/tcp, 8008/tcp objective_dewdney
This exposes the container port. Argument --expose is equal to a statement using EXPOSEin Dockerfile.
Let's try to publish the port now -
docker run -dit -p 8009 httpd:2.4
Output -
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2c8c93a78e97 httpd:2.4 "httpd-foreground" 2 seconds ago Up 2 seconds 80/tcp, 0.0.0.0:32768->8009/tcp keen_swirles
See the 0.0.0.0:32768, it's now published to the host machine with a random ephemeral port i.e 32768. You can publish it on a specific host port as well.
Example -
docker run -dit -p 8009:8009 httpd:2.4
Output -
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1023df9822e5 httpd:2.4 "httpd-foreground" 2 seconds ago Up 2 seconds 80/tcp, 0.0.0.0:8009->8009/tcp fervent_almeida
In a nutshell, there is no way right now to unexpose the port 80 from parent Dockerfile. You can certainly expose more ports.
It's an open issue -
https://github.com/moby/moby/issues/2210
https://github.com/moby/moby/issues/3465
Adding #BMitch comment to the answer which I believe is spot on since containers can communicate with each other in the same network irrespective of port exposed -
As per #BMitch -
EXPOSE is only documentation/metadata. It doesn't change how
containers communicate with each other. docker ps is just letting you
know a port the image creator documented could be published but hasn't
been (since there's no host side of the map). There's nothing to
change here unless you have code or users that insist this
documentation matches your environment. For that, you'd have to
rebuild the upstream image.
There is a hint on how to do this at the DockerHub page. An alternative config file must be obtained and added to the container via the Dockerfile.
First get a copy of the config file:
docker run --rm httpd:2.4 cat /usr/local/apache2/conf/httpd.conf > my-httpd.conf
Then edit the my-httpd.conf file and modify the port:
Listen 8080
Finally add to the Dockerfile the instruction to copy it:
COPY ./my-httpd.conf /usr/local/apache2/conf/httpd.conf

apache httpd 2.4.37 forward proxy not working

I have build apache httpd 2.4.37 from source in redhat and installed in home directory [/home/test/httpd-2.4.37]. as I don't have root access to install from yum. The server is running, I want to use this server only as a forward proxy.
I have the following modules in /home/test/httpd-2.4.37/conf/httpd.conf and the files in /home/test/httpd-2.4.37/modules
LoadModule proxy_module modules/mod_proxy.so LoadModule
proxy_connect_module modules/mod_proxy_connect.so LoadModule
proxy_ftp_module modules/mod_proxy_ftp.so LoadModule
proxy_http_module modules/mod_proxy_http.so LoadModule
proxy_fcgi_module modules/mod_proxy_fcgi.so LoadModule
proxy_scgi_module modules/mod_proxy_scgi.so LoadModule
proxy_uwsgi_module modules/mod_proxy_uwsgi.so LoadModule
proxy_fdpass_module modules/mod_proxy_fdpass.so LoadModule
proxy_wstunnel_module modules/mod_proxy_wstunnel.so LoadModule
proxy_ajp_module modules/mod_proxy_ajp.so LoadModule
proxy_balancer_module modules/mod_proxy_balancer.so
I have added below configuration at end of /home/test/httpd-2.4.37/conf/httpd.conf file.
Listen 127.0.0.1:8090
ProxyRequests On
ProxyVia On
ProxyPreserveHost Off
<Proxy "*">
Order deny,allow
Allow from all
</Proxy>
ErrorLog "/home/test/httpd-2.4.37/logs/proxy-error.log"
CustomLog "/home/test/httpd-2.4.37/logs/proxy-access.log" common
forward proxy is not working , when I call from a another machine using this proxy, I am getting connection refused as response.
no log is getting updated /home/test/httpd-2.4.37/logs/proxy-error.log & /home/test/httpd-2.4.37/logs/proxy-access.log
My primary objective is to tunnel ssh request over thru proxy. I have added the below change at the end of httpd.conf file. Proxy is working and forwarding the request to the destination.
Listen 8090
<VirtualHost *:8090>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} !^CONNECT [NC]
RewriteRule ^/(.*)$ - [F,L]
ProxyRequests On
ProxyBadHeader Ignore
ProxyVia On
AllowCONNECT 22 64
<Proxy "*">
Order deny,allow
Require ip 10
</Proxy>
ErrorLog "/home/test/httpd-2.4.37/logs/proxy-error.log"
CustomLog "/home/test/httpd-2.4.37/logs/proxy-access.log" common
</VirtualHost>

Apache websocket connection:upgrade replaced by keep-alive

I am trying to figure out a mind-numbing apache issue where requests are going through two layers of apache reverse proxies before hitting upstream services. Most traffic seems to make it through fine. The notable exception is websockets.
In particular, this is a test request
curl -i -H 'Connection: Upgrade' -H 'Upgrade: websocket' localhost:80/test.html
When proxying requests from port 80 to port 8080, I notice (using tcpdump and Wireshark) that the Upgrade header has been removed and Connection: Keep-Alive has been set instead. Moreover, any attempts I have made at resetting the Connection header to Upgrade and Upgrade: websocket have been impotent.
Note that the upstream service needs Connection: Upgrade and Upgrade: websocket to initiate the websocket (I get a 404 error without those headers).
Why is Apache forcing Connection: Keep-Alive when proxying to itself? Is there any way to force it to pass along Connection / Upgrade headers or set those values manually? RequestHeader and friends have unfortunately not been helpful. Without Connection and Upgrade making it through the reverse proxy, the upstream service pukes and throws a 404/Not found at the websocket endpoint.
ServerRoot "/usr/local/apache2"
Listen 80
Listen 8080
LogLevel rewrite:trace8
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule xml2enc_module modules/mod_xml2enc.so
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule auth_mellon_module modules/mod_auth_mellon.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule ssl_module modules/mod_ssl.so
<IfModule unixd_module>
User daemon
Group daemon
</IfModule>
<VirtualHost *:80>
LogLevel rewrite:trace8
ServerName localhost
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://localhost:8080/$1 [P,L]
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
ProxyRequests Off
</VirtualHost>
<VirtualHost *:8080>
LogLevel rewrite:trace8
ServerName localhost
UseCanonicalName On
RewriteEngine On
ProxyPass / http://proxy-debug:8080/
ProxyPassReverse / http://proxy-debug:8080/
ProxyRequests Off
</VirtualHost>
ServerAdmin you#example.com
ErrorLog /proc/self/fd/2
DocumentRoot "/"
I do not completely understand how this works, but the nuggets of wisdom I have gleaned and the solution I have devised are as follows:
Apache does not understand websockets in one sense (i.e. when it is talking to itself). As a result, you need to use mod_rewrite and set the protocol to ws:// in order to forward websockets upstream (it seems that no amount of setting headers will help you here).
If you set the protocol to ws://, then Apache will set the appropriate headers (Connection: Upgrade and Upgrade: websocket) when proxying requests upstream. However, for some reason, it does not seem to do this when proxying requests to itself / another VirtualHost.
You can see a blurb in VirtualHost *:80 (copied below) that tries to discern whether a websocket is in order and then change the protocol accordingly. This will not work for VirtualHost *:8080 (see the above bullet). Other methods are necessary.
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://localhost:8080/$1 [P,L]
Put all of this together, and you have to communicate to VirtualHost *:8080 that a websocket connection is needed upstream. Luckily, we are in control of VirtualHost *:80 and can discern this information / pass it along. We must do so without touching the Connection or Upgrade headers, since Apache does weird things with them. The protocol may be traceable, but I am not sure how to do that. As a result, I use a bogus, internal, custom header for the transmission. Probably best to name it in such a way that collisions are unlikely.
In VirtualHost *:80, we add a block like:
SetEnvIf Upgrade ^websocket$ websock=true
RequestHeader set X-Is-Websocket %{websock}e
And then we read that header in VirtualHost *:8080, changing the protocol if necessary:
SetEnvIf X-Is-Websocket ^true$ websock=true
RequestHeader unset X-Is-Websocket
# change protocol if necessary
RewriteCond %{ENV:websock} =true
RewriteRule /(.*) ws://proxy-debug:8080/$1 [P,L]
RewriteCond %{ENV:websock} !=true
RewriteRule /(.*) http://proxy-debug:8080/$1 [P,L]
Hope it helps! :)

Apache https reverse proxy with Tomcat

Well, I looked everywhere I could, but if some know where I could find a solution, sorry for asking once again the question.
We are looking to implement this solution :
HTTP client -> Apache 2.4 Reverse Proxy -> HTTP Server => Works OK
HTTPS client -> Apache 2.4 Reverse Proxy -> HTTPS Server => Works OK
But, when the HTTPS server replies with a "302" redirection header, the server name in the header is not translated to the client-side known server name. So, the client fail to connect, due to a DNS error.
We can't add the backend server name in the DNS, so we need that solution to work.
Important notice: the same works in HTTP. It means that when the server reply is a "302" redirection header in HTTP, there's no problem. It works even if the target of the redirection is a HTTPS link. So what is not working is redirecting from HTTPS to HTTPS.
The backend webserver is Tomcat.
The problem is: in HTTPS header, the redirection URL is "https://[backendname]/something.html" but we expect it to be "https://[servername]/something.html"
We've checked that we have no error in log file (error level set to "debug").
Here is our virtual site configuration:
<VirtualHost [reverse proxy IP]:443>
SSLEngine on
SSLProxyEngine on
SSLCertificateFile D:/Apache24/ssl/certs/servername.cer
SSLCertificateKeyFile D:/Apache24/ssl/private/servername.key
ServerName [servername]
ProxyPass / https://[backendname]:443/
ProxyPassReverseCookiePath / https://[backendname]:443/
ProxyPassReverse / https://[backendname]:443/
SetOutputFilter proxy-html
ProxyHTMLEnable On
ProxyHTMLURLMap https://[backendname] https://[servername]
ErrorLog D:/Apache24/logs/custom/[servername]_error.log
CustomLog D:/Apache24/logs/custom/[servername]_access.log combined
SetEnv nokeepalive ssl-unclean-shutdown
</VirtualHost>
Problem related Apache activated modules:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule xml2enc_module modules/mod_xml2enc.so
So, any help to make this work will be greatly appreciated.
Thanks.
Here is the working solution, as suggested by Michael Akerman
disable caching
write new instruction: ProxyPassReverse https://[backend]/
Thanks for your help

ProxyPass with trailing slash returns 404

Consider the following configuration :
ProxyPass /myapp http://localhost:8080/myapp
ProxyPassReverse /myapp http://localhost:8080/myapp
Now requests that are made to http://www.example.com/myapp/foo/bar will be routed to my app with the expected results to the browser. However a request made to http://www.example.com/myapp/foo/bar/ will return a 404.
I observe the same results when I update the ProxyPass and ProxyPassReverse directives with the trailing forward slash.
I know that my Controller in my Spring app is set up to handle this URL pattern as calls made to http://localhost:8080/myapp/foo/bar/ work as expected.
I am using Apache 2.4 and Tomcat7. I have the following modules loaded:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule proxy_http_module modules/mod_proxy_http.so