Saturday, September 7, 2019

Web host set-up with fresh Ubuntu 18.04 Install - apache2 as webserver with nginx as proxy

Install Apache2

First install Apache2, PHP-FPM, and FastCGI Apache module
$ sudo apt update && sudo apt upgrade
$ sudo apt-get install apache2 php-fpm
$ wget
$ sudo dpkg -i libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb
Configure Apache2 to use PHP-FPM.  First change Apache port number to 8080.
$ sudo cp /etc/apache2/ports.conf /etc/apache2/ports.conf.default
$ sudo nano /etc/apache2/ports.conf
Change Listen 80 in the ports.conf file you just opened to Listen 8080. Save file.
Configure hostname.
$ sudo nano /etc/apache2/apache2.conf
Add the following:
ServerName localhost
Open hosts file
$ sudo nano /etc/hosts
Edit as needed: localhost myhostname
Create directory for apache2 logs and change ownership and permissions.
$ sudo mkdir /var/log/apache2
$ sudo chmod 750 /var/log/apache2
$ sudo chown root:adm /var/log/apache2
Apache comes with a default virtual host file called 000-default.conf.  Copy this file for your domain.
$ sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/
Open your-domain.conf file just created.
$ sudo nano /etc/apache2/sites-available/
Change the listening port to 8080
The file contents should look something like this:
<VirtualHost *:8080>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

Disable 000-default.conf and enable the new conf file for your domain as follows:
$ sudo a2dissite 000-default.conf
$ sudo a2ensite
Reload Apache.
$ sudo systemctl reload apache2
Install net-tools if necessary for the netstat command.
$ sudo apt install net-tools
Verify Apache is listening to port 8080.
$ sudo netstat -tlpn
Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 *               LISTEN      2204/systemd-resolv
tcp        0      0    *               LISTEN      21618/sshd
tcp6       0      0 :::8080                 :::*                    LISTEN      7454/apache2
tcp6       0      0 :::22                   :::*                    LISTEN      21618/sshd

Create directory structure:

$ sudo mkdir -p /var/www/
The above creates directories owned by root.  Change ownership so other users can access.
$ sudo chown -R $USER:$USER /var/www/
Modify permissions to ensure that read access is permitted to the general web directory and all of the files and folders it contains.
$ sudo chmod -R 755 /var/www
Set up a temporary web page for testing
$ nano /var/www/
Add the following contents<
    <h1>Welcome to our test page!</h1>

Create New Virtual Host File

Edit the your-domain.conf file created earlier.
$ sudo nano /etc/apache2/sites-available/
Edit the file with the following changes on red.
<VirtualHost *:8080>

        ServerAdmin [email protected]
        ServerAlias *
        DocumentRoot /var/www/    
        <Directory /var/www/>
            AllowOverride All
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

The entry AllowOverride All  enables .htaccess support. Save the file.

Enable the New Virtual Host File

Activate each site as follows (should already be activated):
$ sudo a2ensite
You should get a message that confirms the site was enabled.
Enabling site
To activate the new configuration, you need to run:
  service apache2 reload
Allow port 8080 in the firewall if needed
$ sudo ufw allow 8080
Restart Apache.
$ sudo systemctl restart apache2
The sites are configured.  Verify that you can reach the site (
If you can't reach the site, try running the following.
$ sudo apache2ctl -S
Verify the information is correct.

Next configure support for PHP and FastCGI.

The module mod_fastcgi depends on mod_action.  Enable mod_action:
$ sudo a2enmod actions
Backup the existing fastcgi conf file:
$ sudo cp /etc/apache2/mods-enabled/fastcgi.conf /etc/apache2/mods-enabled/fastcgi.conf.default
Edit the file:
$ sudo nano /etc/apache2/mods-enabled/fastcgi.conf
Replace the contents of the file with the following:
<IfModule mod_fastcgi.c>
  AddHandler fastcgi-script .fcgi
  FastCgiIpcDir /var/lib/apache2/fastcgi
  AddType application/x-httpd-fastphp .php
  Action application/x-httpd-fastphp /php-fcgi
  Alias /php-fcgi /usr/lib/cgi-bin/php-fcgi
  FastCgiExternalServer /usr/lib/cgi-bin/php-fcgi -socket /run/php/php7.2-fpm.sock -pass-header Authorization
  <Directory /usr/lib/cgi-bin>
    Require all granted
Save the file and check the configuration
$ sudo apachectl -t
If the syntac is OK, reload apache.
$ sudo systemctl reload apache2
Verify php is working.  Create a info.php file.
$ echo "<?php phpinfo(); ?>" | sudo tee /var/www/
Go to http://your_ip:8080\info.php.  Near the top, Server API should say FPM/FastCGI. Find SERVER_SOFTWARE.  It should say is Apache on Ubuntu.

Install nginx

$ sudo apt install nginx
Delete default symlink no longer needed.
$ sudo rm /etc/nginx/sites-enabled/default
Create a virtual host file.
$ sudo nano /etc/nginx/sites-available/
Populate as follows:
server {
    listen 80;

    root /var/www/;
    index index.php index.html index.htm;

    server_name *;
    location / {
        try_files $uri $uri/ /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        include snippets/fastcgi-php.conf;
Enable the site by creating a symbolic link to the sites-enabled directory.
$ sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
Test the Nginx configuration.
$ sudo nginx -t
If the test is OK, restart nginx.
$ sudo systemctl reload nginx
Open the browser and try to access the info.php file.
Once the info.php file is opened find SERVER_SOFTWARE on the page.  It should identify nginx as the server. Also find DOCUMENT_ROOT. Verify the document root is correct.

Proxy nginx domain names to apache

Create nginx virtual host for forwarding requests to apache.
$ sudo nano /etc/nginx/sites-available/apache
Populate file with the following.
server {
    listen 80;
    server_name *;

    location / {
        proxy_pass http://your_ip:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
Save the file, then enable it by creating a symbolic link.
$ sudo ln -s /etc/nginx/sites-available/apache /etc/nginx/sites-enabled/apache
If you get a file already exists error try this.
$ cd /etc/nginx/sites-enabled/apache
$ sudo ln -s /etc/nginx/sites-available/apache
Test the configuration
$ sudo nginx -t
If no errors reload nginx
$ sudo systemctl reload nginx
Go to 
Review the php info.  Verify DOCUMENT_ROOT is correct for the apache root.  Verify SERVER_SOFTWARE is apache. Variables HTTP_X_REAL_IP and HTTP_X_FORWARDED_FOR were added by nginx and contain your ip address.

Configure Apache to set the rewrite values for proxy

The apache module mod\_rpaf rewrites values REMOTE_ADDR, HTTPS and HTTP_PORT to the values provided by a reverse proxy. Install the following.
$ sudo apt install unzip build-essential apache2-dev
Download the latest stable rpaf release, unzip, and install the module.
$ cd /tmp
$ wget
$ unzip
$ cd mod_rpaf-stable
$ make
$ sudo make install
$ sudo apt install libtool.bin
$ libtool --finish /usr/lib/apache2/modules
Create file in the mods-available directory which will load mod_rpaf
$ sudo nano /etc/apache2/mods-available/rpaf.load
Populate the file with the following
LoadModule rpaf_module /usr/lib/apache2/modules/
Save the file.  Create a configuration file in the same directory
$ sudo nano /etc/apache2/mods-available/rpaf.conf
Populate as follows:
    <IfModule mod_rpaf.c>
        RPAF_Enable             On
        RPAF_Header             X-Real-Ip
        RPAF_ProxyIPs           your_ip 
        RPAF_SetHostName        On
        RPAF_SetHTTPS           On
        RPAF_SetPort            On
Save the file. Enable the module
$ sudo a2enmod rpaf
Test the configuration
$ sudo apachectl -t
If no errors reload apache2
$ sudo systemctl reload apache2; 
Return to the browser and go to The REMOTE_ADDR variable should now be your local computer’s public ip address.

Secure Website

You can secure your website with a free Let's Encrypt Certificate.

Install certbot

Add the PPA and install certbot (install software-properties-common if necessary)
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt update
Install certbot packages:
$ sudo apt install python-certbot-nginx 

Configure letsencrypt.conf

When installing certificate Let's Encrypt places a temporary file in the path htttp:// If it doesn't receive a proper response the certificate is rejected.  Here are steps needed to pass the challenge.

Copy the file created earlier in the /etc/nginx/sites-available/ directory to a new file for ssl.
$ sudo cp /etc/nginx/sites-available/ /etc/nginx/conf.d/
Edit the new file.
$ sudo nano /etc/nginx/conf.d/
Make changes as shown:
server {
    listen 80;

    root /var/www/;
    index index.php index.html index.htm;

    server_name *;
    location / {
        try_files $uri $uri/ /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        include snippets/fastcgi-php.conf;
    location ~ /.well-known/acme-challenge {
        allow all;
When let's encrypt issues the certificate it will add 443 ssl data to the existing service block of the /etc/nginx/conf.d/ file.

SSL installation 

Check syntax:
$ sudo nginx -t
If OK, reload nginx
$ sudo systemctl reload nginx
Make sure the https port 443 is included in your firewall configuration. See Install Firewall (ufw).

Install certificate:

If the dry-run passes you can issue the certificate
$ sudo certbot --nginx -d -d
Answer any prompts and wait for the confirmation that the certificate has been issued.  If you have problems getting the certificate issue, try visiting the website
Since we are using the webroot plugin we need to reload the nginx server at renewal.  To do this, append --renew-hook "systemctl reload nginx" to the /etc/cron.d/certbot file:
$ sudo nano /etc/cron.d/certbot
There is a one-line string of text.  Append so it looks like this
$ 0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"
The Let's Encrypt Certificate is only valid for 90 days.  However the certbot installation includes a cron script that auto renews the certificate 30 days before expiration.  The script is located at /etc/cron.d.

You can test the renewal process by running the following command again:
$ sudo certbot renew --dry-run