Difference between revisions of "Apache Proxy"

From Michael's Information Zone
Jump to navigation Jump to search
(Created page with "While trying to set an ssl proxy, I ran into an issue where the ssl handshake would not work with the stupid website icon. <pre> Error during SSL Handshake with remote server...")
 
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
==Dockerfile Example==
 +
Sometimes I run the proxy using the default httpd container, other times I use the following centos build. Depending on how I feel that day.
 +
*Running this will allow you to run certbot within the container.
 +
<pre>
 +
FROM centos:latest
 +
RUN yum -y upgrade
 +
RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
 +
RUN yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
 +
RUN yum -y install yum-utils
 +
RUN yum-config-manager --enable remi-php73
 +
RUN yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional
 +
RUN yum -y install \
 +
        http \
 +
        mod_ssl \
 +
        openssl \
 +
        yum install certbot python2-certbot-apache
 +
RUN echo -e "ServerTokens Prod\nServerSignature Off\nLoadModule deflate_module modules/mod_deflate.so" >> /etc/httpd/conf/httpd.conf
 +
RUN :> /etc/httpd/conf.d/welcome.conf
 +
EXPOSE 80 443
 +
CMD /usr/sbin/httpd -DFOREGROUND
 +
</pre>
 +
 +
==Certbot Letsencrypt==
 +
In this case I am trying to use webroot verification to obtain a certificate for a running site behind a proxy. This is all done using docker containers. Still working on the specifics, but one issue I am running into is that SELinux on CentOS 7 doesn't like processes from containers hitting ZFS directories created by Docker. Will need to finish migrating these containers to VMs running on the CentOS 7 host.
 +
<br>
 +
<br>
 +
I digress.
 +
*Make sure you prevent the proxy from proxying the challenge<ref>https://serverfault.com/questions/518355/how-to-exclude-an-url-for-apache-mod-proxy</ref> by adding the following to your vhost for the domain.
 +
<pre>
 +
ProxyPass /.well-known/ !
 +
</pre>
 +
Alternatively
 +
<pre>
 +
<VirtualHost *:80>
 +
<Location "/.well-known/acme-challenge/">
 +
        allow from all
 +
</Location>
 +
RewriteEngine On
 +
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/(.*)$
 +
RewriteCond %{HTTPS} off
 +
RewriteRule ^/(.*)$ https://%{SERVER_NAME}%{REQUEST_URI}
 +
</VirtualHost>
 +
 +
</pre>
 +
<ref>https://certbot.eff.org/docs/using.html#webroot</ref>There are two methods for running certbot with containers.
 +
*The first option is to run a temp container and mounting the letsencrypt and web root directory.
 +
<pre>
 +
sudo docker run --rm --name certbot -v /proxy/sitefiles:/var/www/ -v /proxy/certs/letsencrypt:/etc/letsencrypt \
 +
certbot/certbot certonly --agree-tos -m your@email.com --webroot -w /var/www/ -d your.domain.com
 +
</pre>
 +
*The other method is to run certbot within the live proxy container. This is not ideal as the container would need rw access to relevant directories.
 +
<pre>
 +
docker exec -it proxy certbot certonly --agree-tos -m your@email.com --webroot -w /var/www/html/ -d your.domain.net
 +
</pre>
 +
 +
==SSL Handshake with remote server favicon.ico==
 
While trying to set an ssl proxy, I ran into an issue where the ssl handshake would not work with the stupid website icon.
 
While trying to set an ssl proxy, I ran into an issue where the ssl handshake would not work with the stupid website icon.
 
<pre>
 
<pre>
Line 11: Line 67:
 
SSLProxyCheckPeerExpire off
 
SSLProxyCheckPeerExpire off
 
</pre>
 
</pre>
 +
 +
==Proxy vhost sample==
 +
<pre>
 +
Listen 8080
 +
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_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_express_module modules/mod_proxy_express.so
 +
LoadModule rewrite_module modules/mod_rewrite.so
 +
LoadModule cache_module modules/mod_cache.so
 +
LoadModule cache_disk_module modules/mod_cache_disk.so
 +
LoadModule ssl_module modules/mod_ssl.so
 +
 +
<IfModule cache_disk_module modules>
 +
CacheRoot  "/var/cache/httpd/"
 +
CacheEnable disk /
 +
CacheDirLevels 2
 +
CacheDirLength 1
 +
CacheMaxFileSize 52428800
 +
</IfModule>
 +
 +
<VirtualHost *:8080>
 +
CustomLog logs/access_log combined
 +
ErrorLog logs/error_log
 +
<IfModule proxy_module>
 +
SSLProxyEngine On
 +
SSLProxyVerify none
 +
SSLProxyCheckPeerCN off
 +
SSLProxyCheckPeerName off
 +
SSLProxyCheckPeerExpire off
 +
ProxyPass "/" "https://michaelwiki.geekgalaxy.com/"
 +
ProxyPassReverse "/" "https://michaelwiki.geekgalaxy.com/"
 +
ProxyPreserveHost On
 +
</IfModule>
 +
</VirtualHost>
 +
</pre>
 +
 +
==Use Source IP==
 +
By default the destination server will use the IP of the proxy in it's logs, as well as for processing htaccess files. I found this out during a migration where my htaccess require fields were essentially worthless.<br>
 +
<br>
 +
The key here is to tell the server behind the proxy to use the "X-Forwarded-For" header, set by default by Apache mod_proxy, for logging. Apache will NOT process this source IP without it being set in the log (I didn't see this in the documentation<ref>https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/manual/mod/mod_remoteip.xml</ref>).<br><br>
 +
<ref>https://www.digitalocean.com/community/questions/get-client-public-ip-on-apache-server-used-behind-load-balancer</ref>
 +
#Add "RemoteIPHeader X-Forwarded-For" to your config (either default httpd.conf or your vhost file).
 +
#Edit the LogFormat to match the following. The key is replacing "%h" at the beginning with "%a".
 +
<pre>
 +
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
 +
</pre>
 +
 +
<br>
 +
<br>

Latest revision as of 07:05, 10 October 2019

Dockerfile Example

Sometimes I run the proxy using the default httpd container, other times I use the following centos build. Depending on how I feel that day.

  • Running this will allow you to run certbot within the container.
FROM centos:latest
RUN yum -y upgrade
RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
RUN yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
RUN yum -y install yum-utils
RUN yum-config-manager --enable remi-php73
RUN yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional
RUN yum -y install \
        http \
        mod_ssl \
        openssl \
        yum install certbot python2-certbot-apache
RUN echo -e "ServerTokens Prod\nServerSignature Off\nLoadModule deflate_module modules/mod_deflate.so" >> /etc/httpd/conf/httpd.conf
RUN :> /etc/httpd/conf.d/welcome.conf
EXPOSE 80 443
CMD /usr/sbin/httpd -DFOREGROUND

Certbot Letsencrypt

In this case I am trying to use webroot verification to obtain a certificate for a running site behind a proxy. This is all done using docker containers. Still working on the specifics, but one issue I am running into is that SELinux on CentOS 7 doesn't like processes from containers hitting ZFS directories created by Docker. Will need to finish migrating these containers to VMs running on the CentOS 7 host.

I digress.

  • Make sure you prevent the proxy from proxying the challenge[1] by adding the following to your vhost for the domain.
ProxyPass /.well-known/ !

Alternatively

<VirtualHost *:80>
<Location "/.well-known/acme-challenge/">
        allow from all
</Location>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/(.*)$
RewriteCond %{HTTPS} off
RewriteRule ^/(.*)$ https://%{SERVER_NAME}%{REQUEST_URI}
</VirtualHost>

[2]There are two methods for running certbot with containers.

  • The first option is to run a temp container and mounting the letsencrypt and web root directory.
sudo docker run --rm --name certbot -v /proxy/sitefiles:/var/www/ -v /proxy/certs/letsencrypt:/etc/letsencrypt \
certbot/certbot certonly --agree-tos -m your@email.com --webroot -w /var/www/ -d your.domain.com
  • The other method is to run certbot within the live proxy container. This is not ideal as the container would need rw access to relevant directories.
docker exec -it proxy certbot certonly --agree-tos -m your@email.com --webroot -w /var/www/html/ -d your.domain.net

SSL Handshake with remote server favicon.ico

While trying to set an ssl proxy, I ran into an issue where the ssl handshake would not work with the stupid website icon.

Error during SSL Handshake with remote server returned by /favicon.ico

In this case it was ok to ignore the authenticity of the connection, restricted use case and something that I would normally not do[3]

SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off

Proxy vhost sample

Listen 8080
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_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_express_module modules/mod_proxy_express.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule cache_module modules/mod_cache.so
LoadModule cache_disk_module modules/mod_cache_disk.so
LoadModule ssl_module modules/mod_ssl.so

<IfModule cache_disk_module modules>
CacheRoot   "/var/cache/httpd/"
CacheEnable disk /
CacheDirLevels 2
CacheDirLength 1
CacheMaxFileSize 52428800
</IfModule>

<VirtualHost *:8080>
CustomLog logs/access_log combined
ErrorLog logs/error_log
<IfModule proxy_module>
SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
ProxyPass "/" "https://michaelwiki.geekgalaxy.com/"
ProxyPassReverse "/" "https://michaelwiki.geekgalaxy.com/"
ProxyPreserveHost On
</IfModule>
</VirtualHost>

Use Source IP

By default the destination server will use the IP of the proxy in it's logs, as well as for processing htaccess files. I found this out during a migration where my htaccess require fields were essentially worthless.

The key here is to tell the server behind the proxy to use the "X-Forwarded-For" header, set by default by Apache mod_proxy, for logging. Apache will NOT process this source IP without it being set in the log (I didn't see this in the documentation[4]).

[5]

  1. Add "RemoteIPHeader X-Forwarded-For" to your config (either default httpd.conf or your vhost file).
  2. Edit the LogFormat to match the following. The key is replacing "%h" at the beginning with "%a".
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined