{"id":401,"date":"2018-09-19T13:49:19","date_gmt":"2018-09-19T11:49:19","guid":{"rendered":"https:\/\/www.gonscak.sk\/?p=401"},"modified":"2020-08-25T12:33:54","modified_gmt":"2020-08-25T10:33:54","slug":"how-to-use-apache-as-reverse-proxy-on-centos-7-with-selinux","status":"publish","type":"post","link":"https:\/\/www.gonscak.sk\/?p=401","title":{"rendered":"How to use Apache as Reverse Proxy on Centos 7 with selinux"},"content":{"rendered":"<h4>Introduction<\/h4>\n<p>In addition to being a &#8220;basic&#8221; web server, and providing static and dynamic content to end-users, Apache httpd (as well as most other web servers) can also act as a reverse proxy server, also-known-as a &#8220;gateway&#8221; server.<\/p>\n<p>In such scenarios, httpd itself does not generate or host the data, but rather the content is obtained by one or several backend servers, which normally have no direct connection to the external network. As httpd receives a request from a client, the request itself is <em>proxied<\/em> to one of these backend servers, which then handles the request, generates the content and then sends this content back to httpd, which then generates the actual HTTP response back to the client.<\/p>\n<p>There are numerous reasons for such an implementation, but generally the typical rationales are due to security, high-availability, load-balancing and centralized authentication\/authorization.<\/p>\n<p>It is critical in these implementations that the layout, design and architecture of the backend infrastructure (those servers which actually handle the requests) are insulated and protected from the outside; as far as the client is concerned, the reverse proxy server <em>is<\/em> the sole source of all content.<\/p>\n<p>More is <a href=\"https:\/\/httpd.apache.org\/docs\/2.4\/howto\/reverse_proxy.html\">here<\/a>.<\/p>\n<p>Typical implemetation is below:<\/p>\n<p><a href=\"https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/reverse-proxy-arch.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-404 size-medium\" src=\"https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/reverse-proxy-arch-268x300.png\" alt=\"\" width=\"268\" height=\"300\" srcset=\"https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/reverse-proxy-arch-268x300.png 268w, https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/reverse-proxy-arch.png 297w\" sizes=\"auto, (max-width: 268px) 100vw, 268px\" \/><\/a>In this tutorial, we will set up Apache as a basic reverse proxy using the <strong><em>mod_proxy <\/em><\/strong>extension to redirect incoming connections to one or several backend servers running on the same network. This Apache Proxy Server also creates and manages security (ssl engine, https). Conection to the backend servers from this Proxy Server is not encrypted (only http). Next, we will use https (ssl certificates from Let&#8217;s Encrypt for ours conections from outside world, but not to backend.<\/p>\n<h4>Installation<\/h4>\n<p>For a minimum HTTP server instalation install apache itself:<\/p>\n<pre>yum install httpd -y<\/pre>\n<p>Make sure, that the &#8220;\/etc\/hosts&#8221; file contain references for the loopback address and the hostname<\/p>\n<pre>127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\n192.168.3.3 edge-proxy-e edge-proxy-e.gonscak.sk<\/pre>\n<p>Turn on the HTTP server, and make sure it starts automatically on reboot. Next, add http port to the firewalld.<\/p>\n<pre>systemctl start httpd.service\nsystemctl enable httpd.service \nfirewall-cmd --add-service=http --permanent\nfirewall-cmd --reload<\/pre>\n<p>Now, we can test our apache test web page on http address. This page is there fer testing and informational purposes:<\/p>\n<pre>http:\/\/edge-proxy-e.gonscak.sk<\/pre>\n<p><a href=\"https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/default_apache.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-415 size-medium\" src=\"https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/default_apache-300x90.png\" alt=\"\" width=\"300\" height=\"90\" srcset=\"https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/default_apache-300x90.png 300w, https:\/\/www.gonscak.sk\/wp-content\/uploads\/2018\/09\/default_apache.png 715w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>If you see the test page above, then your server is now correctly installed.<\/p>\n<h4>Example &#8211; Reverse Proxying a Single Backend Server<\/h4>\n<p>Create a first configuration file for our test backend server (I assume, that you already have one).<\/p>\n<pre>vim \/etc\/httpd\/conf.d\/test-vhost.conf\n\n&lt;VirtualHost *:80&gt;\n    ServerName edge-proxy-e.gonscak.sk\n    ProxyPreserveHost On\n    ProxyPass \/ http:\/\/media.gonscak.sk\/\n    ProxyPassReverse \/ http:\/\/media.gonscak.sk\/\n&lt;\/VirtualHost&gt;<\/pre>\n<p>There are three directives here:<\/p>\n<ul>\n<li><code>ProxyPreserveHost<\/code> makes Apache pass the original <code>Host<\/code> header to the backend server. This is useful, as it makes the backend server aware of the address used to access the application.<\/li>\n<li><code>ProxyPass<\/code> is the main proxy configuration directive. In this case, it specifies that everything under the root URL (<code>\/<\/code>) should be mapped to the backend server at the given address. For example, if Apache gets a request for <code>\/example<\/code>, it will connect to <code>http:\/\/<span class=\"highlight\">media.gonscak.sk<\/span>\/example<\/code> and return the response to the original client.<\/li>\n<li><code>ProxyPassReverse<\/code> should have the same configuration as <code>ProxyPass<\/code>. It tells Apache to modify the response headers from backend server. This makes sure that if the backend server returns a location redirect header, the client&#8217;s browser will be redirected to the proxy address and not the backend server address, which would not work as intended.<\/li>\n<\/ul>\n<p>Now, we can test out configuration with the first command below. It runs a configuration file syntax test and report OK or error. And with second command we gracefully restarts Apache httpd daemon. If the daemon is not running, it is not started. Currently open connections are not aborted:<\/p>\n<pre>apachectl configtest\napachectl graceful<\/pre>\n<p>And now, if everything is OK, we can open out web page now (http:\/\/192.168.3.3). We now not see the default page of apache, but the content of backend server media.gonscak.sk. We are not connected directly to the media.gonscak.sk, but only to the &#8220;edge&#8221; server with Apache.<\/p>\n<h4>Enabling SSL support, set certificates from LetsEcnrypt<\/h4>\n<p>First, we must install package mod_ssl for Apache to support SSL:<\/p>\n<pre>yum install mod_ssl.x86_64<\/pre>\n<p>Now, we must open port 443 for Apache in firewall:<\/p>\n<pre>firewall-cmd --add-service=https --permanent\nfirewall-cmd --reload<\/pre>\n<p>Now, we create o text file, where we set up some directives for vhost. And then we can simple change som SSL directives for all vhosts in Apache. I use some Mozilla recommendations via https:\/\/mozilla.github.io\/server-side-tls\/ssl-config-generator:<\/p>\n<pre>    SSLEngine on\n    \tSSLCertificateFile \/etc\/pki\/tls\/certs\/newclient.crt\n    \tSSLCertificateKeyFile \/etc\/pki\/tls\/private\/newclient.key\n    \tSSLCACertificateFile \/etc\/pki\/tls\/certs\/ca.crt\n    Header always set Strict-Transport-Security \"max-age=15768000\"\n\nSSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1\nSSLCipherSuite          ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\n\nSSLHonorCipherOrder     on\nSSLCompression          off<\/pre>\n<p>Next, I create an empty directory for DocumentRoot. There will be no content:<\/p>\n<pre>mkdir -p \/var\/www\/vhosts\/sk.gonscak.media<\/pre>\n<p>I edit config file for &#8220;\/etc\/httpd\/conf.d\/test-vhost.conf&#8221; and add virtualhost for ssl. And add link for log files.<\/p>\n<pre>&lt;VirtualHost *:80&gt;\n    ServerAdmin webmaster@gonscak.sk\n    ServerName edge-proxy-e.gonscak.sk\n    AddDefaultCharset UTF-8\n\u00a0   RedirectPermanent \/ https:\/\/edge-proxy-e.gonscak.sk\/\n&lt;\/VirtualHost&gt;\n\n&lt;VirtualHost *:443&gt;\n    ServerAdmin webmaster@gonscak.sk\n    DocumentRoot \"\/var\/www\/vhosts\/sk.gonscak.media\"\n    AddDefaultCharset UTF-8\n    ServerName edge-proxy-e.gonscak.sk\n\n    ErrorLog \/var\/log\/httpd\/sk.gonscak.media-error_log\n    CustomLog \/var\/log\/httpd\/sk.gonscak.media-access_log common\n    Include\t\/etc\/httpd\/conf.d\/modern-ssl-template.txt\n\n  &lt;IfModule mod_proxy.c&gt;\n   ProxyRequests Off\n   ProxyPass \/.well-known\/ !\n   ProxyPass \/ http:\/\/media.gonscak.sk\/\n   ProxyPassReverse \/ http:\/\/media.gonscak.sk\/\n   SSLProxyEngine Off\n   ProxyPreserveHost Off\n  &lt;\/IfModule&gt;\n&lt;\/VirtualHost&gt;\n<\/pre>\n<p>Now, I hide some information, which world can get from our Apache server. Add this directives to Apache configuration. Detailes can be <a href=\"https:\/\/www.if-not-true-then-false.com\/2009\/howto-hide-and-modify-apache-server-information-serversignature-and-servertokens-and-hide-php-version-x-powered-by\/\">read here.<\/a><\/p>\n<pre>vim \/etc\/httpd\/conf\/httpd.conf\nServerSignature Off\nServerTokens Prod<\/pre>\n<p>Some nice explanations of Proxy and WordPress behind it is here: <a href=\"https:\/\/community.pivotal.io\/s\/article\/Purpose-of-the-X-Forwarded-Proto-HTTP-Header\">https:\/\/community.pivotal.io\/s\/article\/Purpose-of-the-X-Forwarded-Proto-HTTP-Header<\/a><\/p>\n<p>\u00a0<\/p>\n\n\n<h2 class=\"wp-block-heading\">Selinux problem<\/h2>\n\n\n\n<p>If we have enabled selinux (check like this):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># sestatus\n\nSELinux status: enabled\nSELinuxfs mount: \/sys\/fs\/selinux\nSELinux root directory: \/etc\/selinux\nLoaded policy name: targeted\nCurrent mode: enforcing\nMode from config file: enforcing\nPolicy MLS status: enabled\nPolicy deny_unknown status: allowed\nMemory protection checking: actual (secure)\nMax kernel policy version: 31<\/pre>\n\n\n\n<p>And we see some problems in our error log and the page is not loaded:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[Tue Aug 25 12:25:37.344072 2020] [proxy_http:error] [client xxx:xxx] AH01114: HTTP: failed to make connection to backend: 192.168.88.5<\/pre>\n\n\n\n<p>We can see this error at log:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sealert -a \/var\/log\/audit\/audit.log<\/pre>\n\n\n\n<p>Just allow selinux policy to Apache to can network connect via setsebool:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">setsebool -P httpd_can_network_connect on<\/pre>\n\n\n\n<p>And that is.<\/p>\n ","protected":false},"excerpt":{"rendered":"<p>Introduction In addition to being a &#8220;basic&#8221; web server, and providing static and dynamic content to end-users, Apache httpd (as well as most other web servers) can also act as a reverse proxy server, also-known-as a &#8220;gateway&#8221; server. In such scenarios, httpd itself does not generate or host the data, but rather the content is &hellip; <a href=\"https:\/\/www.gonscak.sk\/?p=401\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">How to use Apache as Reverse Proxy on Centos 7 with selinux<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[95,102,99,100,93,101],"class_list":["post-401","post","type-post","status-publish","format-standard","hentry","category-centos","tag-apache","tag-letsecnrypt","tag-proxy","tag-reverse","tag-ssl","tag-vhost"],"_links":{"self":[{"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=\/wp\/v2\/posts\/401","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=401"}],"version-history":[{"count":24,"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=\/wp\/v2\/posts\/401\/revisions"}],"predecessor-version":[{"id":624,"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=\/wp\/v2\/posts\/401\/revisions\/624"}],"wp:attachment":[{"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=401"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=401"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gonscak.sk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=401"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}