How to use Apache as Reverse Proxy on Centos 7 with selinux

Introduction

In addition to being a “basic” 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 “gateway” server.

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 proxied 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.

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.

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 is the sole source of all content.

More is here.

Typical implemetation is below:

In this tutorial, we will set up Apache as a basic reverse proxy using the mod_proxy 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’s Encrypt for ours conections from outside world, but not to backend.

Installation

For a minimum HTTP server instalation install apache itself:

yum install httpd -y

Make sure, that the “/etc/hosts” file contain references for the loopback address and the hostname

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.3.3 edge-proxy-e edge-proxy-e.gonscak.sk

Turn on the HTTP server, and make sure it starts automatically on reboot. Next, add http port to the firewalld.

systemctl start httpd.service
systemctl enable httpd.service 
firewall-cmd --add-service=http --permanent
firewall-cmd --reload

Now, we can test our apache test web page on http address. This page is there fer testing and informational purposes:

http://edge-proxy-e.gonscak.sk

If you see the test page above, then your server is now correctly installed.

Example – Reverse Proxying a Single Backend Server

Create a first configuration file for our test backend server (I assume, that you already have one).

vim /etc/httpd/conf.d/test-vhost.conf

<VirtualHost *:80>
    ServerName edge-proxy-e.gonscak.sk
    ProxyPreserveHost On
    ProxyPass / http://media.gonscak.sk/
    ProxyPassReverse / http://media.gonscak.sk/
</VirtualHost>

There are three directives here:

  • ProxyPreserveHost makes Apache pass the original Host header to the backend server. This is useful, as it makes the backend server aware of the address used to access the application.
  • ProxyPass is the main proxy configuration directive. In this case, it specifies that everything under the root URL (/) should be mapped to the backend server at the given address. For example, if Apache gets a request for /example, it will connect to http://media.gonscak.sk/example and return the response to the original client.
  • ProxyPassReverse should have the same configuration as ProxyPass. 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’s browser will be redirected to the proxy address and not the backend server address, which would not work as intended.

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:

apachectl configtest
apachectl graceful

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 “edge” server with Apache.

Enabling SSL support, set certificates from LetsEcnrypt

First, we must install package mod_ssl for Apache to support SSL:

yum install mod_ssl.x86_64

Now, we must open port 443 for Apache in firewall:

firewall-cmd --add-service=https --permanent
firewall-cmd --reload

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:

    SSLEngine on
    	SSLCertificateFile /etc/pki/tls/certs/newclient.crt
    	SSLCertificateKeyFile /etc/pki/tls/private/newclient.key
    	SSLCACertificateFile /etc/pki/tls/certs/ca.crt
    Header always set Strict-Transport-Security "max-age=15768000"

SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite          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

SSLHonorCipherOrder     on
SSLCompression          off

Next, I create an empty directory for DocumentRoot. There will be no content:

mkdir -p /var/www/vhosts/sk.gonscak.media

I edit config file for “/etc/httpd/conf.d/test-vhost.conf” and add virtualhost for ssl. And add link for log files.

<VirtualHost *:80>
    ServerAdmin webmaster@gonscak.sk
    ServerName edge-proxy-e.gonscak.sk
    AddDefaultCharset UTF-8
    RedirectPermanent / https://edge-proxy-e.gonscak.sk/
</VirtualHost>

<VirtualHost *:443>
    ServerAdmin webmaster@gonscak.sk
    DocumentRoot "/var/www/vhosts/sk.gonscak.media"
    AddDefaultCharset UTF-8
    ServerName edge-proxy-e.gonscak.sk

    ErrorLog /var/log/httpd/sk.gonscak.media-error_log
    CustomLog /var/log/httpd/sk.gonscak.media-access_log common
    Include	/etc/httpd/conf.d/modern-ssl-template.txt

  <IfModule mod_proxy.c>
   ProxyRequests Off
   ProxyPass /.well-known/ !
   ProxyPass / http://media.gonscak.sk/
   ProxyPassReverse / http://media.gonscak.sk/
   SSLProxyEngine Off
   ProxyPreserveHost Off
  </IfModule>
</VirtualHost>

Now, I hide some information, which world can get from our Apache server. Add this directives to Apache configuration. Detailes can be read here.

vim /etc/httpd/conf/httpd.conf
ServerSignature Off
ServerTokens Prod

Some nice explanations of Proxy and WordPress behind it is here: https://community.pivotal.io/s/article/Purpose-of-the-X-Forwarded-Proto-HTTP-Header

 

Selinux problem

If we have enabled selinux (check like this):

# sestatus

SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 31

And we see some problems in our error log and the page is not loaded:

[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

We can see this error at log:

sealert -a /var/log/audit/audit.log

Just allow selinux policy to Apache to can network connect via setsebool:

setsebool -P httpd_can_network_connect on

And that is.

Total Page Visits: 115207 - Today Page Visits: 56

How to install Nextcloud v 13 on Centos 7 with php 7

At first, please update your centos. Every command I used, is used as root user 😉

yum -y update

Installing database server MariaDB

Next, we install and create empty database for our nextcloud. Then we start it and enable for autostart after boot.
If you wish, you can skip installations of MariaDB and you can use built-in SQLite. Then you can continue with installing apache web server.

yum -y install mariadb mariadb-server
...
systemctl start mariadb
systemctl enable mariadb

Now, we run post installation script to finish setting up mariaDB server:

mysql_secure_installation
...
Enter current password for root (enter for none): ENTER
Set root password? [Y/n] Y
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y

Now, we can create a database for nextcloud.

mysql -u root -p
...
CREATE DATABASE nextcloud;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextclouduser'@'localhost' IDENTIFIED BY 'YOURPASSWORD';
FLUSH PRIVILEGES;
exit;

Installing Apache Web Server with ssl (letsencrypt)

Now, we install Apache web server, and we start it and enable for autostart after boot:

yum install httpd -y
systemctl start httpd.service
systemctl enable httpd.service

Now, we install ssl for apache and allow https and httpd (for redirect) service for firewall:

yum -y install epel-release
yum -y install httpd mod_ssl
...
firewall-cmd --zone=public --permanent --add-service=https
firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --reload
systemctl restart httpd.service
systemctl status httpd

Now we can access our server via http://our.server.sk or self-signed certificate on https://our.server.sk

If we want signed certificate from letsencrypt, we can do it with next commands. Certboot will ask some questions, so answer them.

yum -y install python-certbot-apache
certbot --apache -d our.server.sk

If we are good, we can see:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.com/fullchain.pem.
...

Then, we must edit our ssl.conf or our  virtual-host to see this certificates. And we can test our page with this.

https://www.ssllabs.com/ssltest/analyze.html?d=our.server.sk&latest

Install PHP 7

The creators of nextcloud recommends at minimal PHP 7.0.
Now we must add some additional repositories for php v. 7:

yum install https://$(rpm -E '%{?centos:centos}%{!?centos:rhel}%{rhel}').iuscommunity.org/ius-release.rpm
yum install yum-plugin-replace
yum repolist # show enabled repositories
yum repolist disabled #show disabled repositories

And we can install php 7.0:

yum install php70u php70u-dom php70u-mbstring php70u-gd php70u-pdo php70u-json php70u-xml php70u-zip php70u-curl php70u-mcrypt php70u-pear setroubleshoot-server bzip2 php70u-mysqlnd.x86_64 php70u-ldap.x86_64 unzip php70u-pecl-apcu.x86_64 mod_php70u.x86_64 php70u-opcache.x86_64 php70u-pecl-memcached.x86_64 php70u-process.x86_64

Check in:

php --ini |grep Loaded
Loaded Configuration File:         /etc/php.ini
php -v
PHP 7.0.27 (cli) (built: Apr 15 2017 07:09:11) ( NTS )
Copyright (c) 1997-2017 The PHP Group

In my case, I will use nextcloud as my backup device, so I increase the default upload limit to 200MB.

sed -i "s/post_max_size = 8M/post_max_size = 200M/" /etc/php.ini
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 200M/" /etc/php.ini

Restart web server:

systemctl restart httpd

Installing Nextcloud

At first, I install wget tool for download and unzip:

 yum -y install wget unzip

Now we can download nextcloud (at this time the latest version is 11.0.3). And extract it from archive to final destination. Then we change ownership of this directory:

wget https://download.nextcloud.com/server/releases/nextcloud-13.0.0.zip
...
unzip nextcloud_konfs/nextcloud-13.0.0.zip -d /var/www/html/
...
chown -R apache:apache /var/www/html/nextcloud/

If you have enabled SELinux, refer to nextcloud admin manual, you can run into permissions problems. Run these commands as root to adjust permissions:

semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/data(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/config(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/apps(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/.htaccess'
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/.user.ini'
restorecon -Rv '/var/www/html/nextcloud/'

And finally, we can access our nextcloud and set up administrators password via our web: https://you-ip/nextcloud
Now you must complete the installation via web interface. Set Administrator’s password and locate to MariaDB with used credentials:

Database user: nextclouduser
Database password: YOURPASSWORD
Database name: nextcloud
host: localhost

In my case, I must create a DATA folder under out nextcloud, mount nfs backend for this data and set permissions.

mkdir /var/www/html/nextcloud/data
chown apache:apache data/ -R
setsebool -P httpd_use_nfs 1
semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html/nextcloud/data(/.*)?'
restorecon -Rv '/var/www/html/nextcloud/'

Now create an nextcloud configuration file fort apache:

vim /etc/httpd/conf.d/nextcloud.conf
<Directory /var/www/html/nextcloud/>
 Options +FollowSymlinks
 AllowOverride All

<IfModule mod_dav.c>
 Dav off
 </IfModule>

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^/$ /index.php/login
 SetEnv HOME /var/www/html/nextcloud
 SetEnv HTTP_HOME /var/www/html/nextcloud
</Directory>

#####################################################
<VirtualHost _default_:80>
ServerName our.server.sk RewriteEngine On RewriteCond %{REQUEST_URI} ^/$ RewriteRule ^/$ /index.php/login LogLevel warn RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI}[END,NE,R=permanent] </VirtualHost> #################################################### <VirtualHost _default_:443> DocumentRoot "/var/www/html/nextcloud" ServerName our.server.sk RewriteEngine On RewriteCond %{REQUEST_URI} ^/$ RewriteRule ^/$ /index.php/login ErrorLog logs/ssl_error_log TransferLog logs/ssl_access_log LogLevel warn SSLEngine on SSLProtocol all -SSLv2 SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA SSLCertificateFile /var/lib/acme/live/our.server.sk/cert SSLCertificateKeyFile /var/lib/acme/live/our.server.sk/privkey SSLCertificateChainFile /var/lib/acme/live/our.server.sk/chain </VirtualHost>

For nicer access, I created a permanent rewrite rule for my  Nextcloud root folder.

Now restart apache and add permisions for apache, to sen emails and work with LDAP:

systemctl restart httpd.service
setsebool -P httpd_can_sendmail on
setsebool -P httpd_can_connect_ldap on

Enable updates via the web interface

To enable updates via the web interface, you may need this to enable writing to the directories:

setsebool httpd_unified on

When the update is completed, disable write access:

setsebool -P httpd_unified off
Total Page Visits: 115207 - Today Page Visits: 56