_______ ____ ____ __ __ ____ __ ______ ______ /_ __// __// __// /_/ // _ / / / / __ // ____/ / / / __// /_ / __ // _ < / /_ / /_/ // /_ / /_/ /___//___//_/ /_//____//___//_____//_____/ techblog.koponen.se [ / ] [ howto ] [ reviews ] [ webapps ] [ youtube ] [ links ] [ about ] -------------------------------------------------------------------------
techblog.koponen.se [ / ] [ howto ] [ reviews ] [ webapps ] [ youtube ] [ about ] [ links ] -------------------------------------
HOWTO
WWW
INSTALL APACHE HTTPS
Published: 20200929
Tested on:
* Ubuntu Server 20.04.1 on a VMware VM.
* Ubuntu for IoT 20.04.1 (arm64) on a Raspberry Pi 4i Model B 4GB.
-
INDEX
01. Requirements
02. Install Apache and setup an HTTP (unencrypted) website
03. Setup a "Virtual Host"
04. Install a certificate (with Let's Encrypt)
05. Setup an HTTPS (encrypted) website
06. Setup a 301 redirect
07. Setup HSTS
-
Requirements
In this example I'll set it up dual-stack, but just using one of the addresses will work.
In this article I will assume that the following is already setup:
Install Apache and setup an HTTP (unencrypted) website
$ sudo apt -y install apache2
There! Your webserver is finished.
If you surf to it you will be greeted with the "Apache Ubuntu Default
Page" (located in /var/www/html/index.html on your server).
Setup a "Virtual Host"
The strength with Apache (and many other webservers) is it's ability to serve multiple homepages from the same IP-address. These different pages are called "Virtual Hosts". We will setup a specific page (Virtual Host configuration) for our FQDN test.example.com.
Create a dir for your website:
$ sudo mkdir -p /home/www/test.example.com
Create a virtual host configuration for your website:
$ sudo vi /etc/apache2/sites-available/test.example.com.conf
Put this inside the file:
<VirtualHost *:80>
ServerAdmin webmaster@example.com
DocumentRoot /home/www/test.example.com
ServerName test.example.com
CustomLog /var/log/apache2/test.example.com-access.log combined
ErrorLog /var/log/apache2/test.example.com-error.log
<Directory /home/www/test.example.com>
AllowOverride all
Require all granted
</Directory>
</VirtualHost>
Create some content for your website:
$ sudo vi /home/www/test.example.com/index.html
Put this inside the file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>testpage</title>
</head>
<body>
<p>
You've reached test.example.com via http
</p>
</body>
</html>
Activate your site with:
$ sudo a2ensite test.example.com
Enabling site test.example.com.
To activate the new configuration, you need to run:
systemctl reload apache2
$ sudo systemctl reload apache2
$
Your new website should now be working.
If you surf to http://test.example.com/ you will reach your new page.
If you surf to http://[2001:db8::5]/ or http://192.0.2.5/ you will reach
the Apache Ubuntu Default Page.
If you bump into problems, you might get clues with this command:
$ sudo systemctl status apache2
Important! Make sure that there are no collisions (in /etc/hosts) between the machine name and the FQDN of the site you're setting up. I don't recommend using the machine name for a virtual host. If you do anyway, you have to really know what you're doing.
Another common problem is file or dir permissions. The webserver will access the filesystem as a specific user. In the case of Ubuntu this, user is called www-data with UID 33 and is in group www-data with GID 33. The webserver can be joined in other groups as well. If the files you are creating (i.e. the index.html) is not readable or reachable by the webserver, things will not work. You might see something like: "Forbidden You don't have permission to access this resource" on your webpage.
Install a certificate (with Let's Encrypt)
You don't have to use Let's Encrypt.
You can use manually installed keys and certificates (i.e. bought from an
SSL Certificate vendor).
You could also create your own CA
Install certbot
$ sudo apt -y install certbot python3-certbot-apache
Run certbot to generate a certificate for your website.
Certbot will contact the Let's Encrypt servers and temporarily do some changes to apache. This is in order to verify that you are the owner (in control) of the FQDN test.example.com.
Yes, this can be abused by someone in between you and your ISP.
If you really care about security over https you need to look into
certificate pinning, or maybe skip http/https altogether.
Anyhow, let's continue:
$ sudo certbot certonly --apache -d test.example.com -m webmaster@example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator apache, Installer apache
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: a
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for test.example.com
Enabled Apache rewrite module
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/test.example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/test.example.com/privkey.pem
Your cert will expire on 2020-12-27. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
$
If you're using IPv6-only, the command above might fail.
If that happens, try running the exact same command again.
It often works, but at the time of writing this, I don't know why.
We are almost done.
We need to setup a small cronjob that automatically renews the certificates:
$ sudo mkdir /scripts
$ sudo vi /scripts/run_certbot.sh
Enter this into /scripts/run_certbot.sh
#!/bin/sh
certbot renew
Make sure that the script works:
$ sudo chmod 0700 /scripts/run_certbot.sh
$ sudo /scripts/run_certbot.sh
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/test.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certs are not due for renewal yet:
/etc/letsencrypt/live/test.example.com/fullchain.pem expires on 2020-12-27 (skipped)
No renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$
Enable the script on crontab:
$ sudo crontab -e
Enter this at the bottom on the crontab file you just opened:
0 */12 * * * /scripts/run_certbot.sh
Save the file and verify that your script is now in the crontab:
$ sudo crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
0 */12 * * * /scripts/run_certbot.sh
$
We now have the certificate files we need to setup HTTPS.
Setup an HTTPS (encrypted) website
Enable the SSL module:
$ sudo a2enmod ssl
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
systemctl restart apache2
$ sudo systemctl restart apache2
$
From the perspective of the network and the webserver (Apache), the http website and the https website are two different websites. They respond on different TCP ports and they can be configured to be very different. You can have the same content and the even point to the same dir; but as we will see soon: it is beneficiary to have two separate dirs.
Create a dir for your https website:
$ sudo mkdir -p /home/wwws/test.example.com
Create a virtual host configuration for your website:
$ sudo vi /etc/apache2/sites-available/test.example.com-ssl.conf
Put this inside the file:
<VirtualHost *:443>
ServerAdmin webmaster@example.com
DocumentRoot /home/wwws/test.example.com
ServerName test.example.com
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCertificateFile /etc/letsencrypt/live/test.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/test.example.com/privkey.pem
SSLCACertificateFile /etc/letsencrypt/live/test.example.com/fullchain.pem
CustomLog /var/log/apache2/test.example.com-ssl-access.log combined
ErrorLog /var/log/apache2/test.example.com-ssl-error.log
<Directory /home/wwws/test.example.com>
AllowOverride all
Require all granted
</Directory>
</VirtualHost>
Create some content for your website:
$ sudo vi /home/wwws/test.example.com/index.html
Put this inside the file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>testpage</title>
</head>
<body>
<p>
You've reached test.example.com via https
</p>
</body>
</html>
Activate your site with:
$ sudo a2ensite test.example.com-ssl.conf
Enabling site test.example.com-ssl.
To activate the new configuration, you need to run:
systemctl reload apache2
$ sudo systemctl reload apache2
$
Your new website should now be working.
If you surf to https://test.example.com/ you will reach your new page. You can press the little padlock next to the url and view your certificate.
If you surf to https://[2001:db8::5]/ or https://192.0.2.5/ you will be
greated with a broken cert page.
This is because your virtual host of the https page is setup for
test.example.com. If you surf to the server using a different address
the server will try to respond, but it will respond with what it has.
In this case with the certificate of test.example.com and the content
you've setup for this page. The certificate simply doesn't match the
address you used.
Setup a 301 redirect.
It can be confusing to have both an http site and an https site at the same time. But we haven't wasted our time setting up both. The http site is a good way to setup a permanent redirection to our https site.
This means that anyone who tries to reach our http homepage will always be redirected to the right one.
So we will add a small file to our http page, that will tell all web browsers and search engine crawlers where they can find our real page.
We will add a so called "301 redirect" aka permanent redirection.
First we enable the rewrite engine module:
$ sudo a2enmod rewrite
Enabling module rewrite.
To activate the new configuration, you need to run:
systemctl restart apache2
$ sudo systemctl restart apache2
$
Then we add/edit a small file:
$ sudo vi /home/www/test.example.com/.htaccess
Put this inside the file:
RewriteEngine on
Redirect 301 / https://test.example.com/
Done!
The redirect is now in place.
Setup HSTS
We will also add HSTS (HTTP Strict Transport Security) to the https site.
This is a small configuration, that inserts a header of information, into the web traffic of your https page. This header tells all visitors to not accept unencrypted http traffic, but to only accept encrypted https traffic. This setting will be cached into all the visitors' web browsers.
The benefit of this is to mitigate (prevent) downgrade attacks.
In this type of attack, a malicious hacker tries to poison the web traffic, to trick the users to allow unencrypted http web traffic together with your encrypted https page. This way they can snoop and attack the users.
So, let's add the HSTS header!
First we enable the headers module:
$ sudo a2enmod headers
Enabling module headers.
To activate the new configuration, you need to run:
systemctl restart apache2
$ sudo systemctl restart apache2
$
Then we add/edit a small file:
$ sudo vi /home/wwws/test.example.com/.htaccess
Put this inside the file:
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Do note the max-age value. In this case I've set it to 1 year.
If you give it a low value (like an hour or a day), it will be easy to fix mistakes (if you are uncertain if https is for you). But when you're doing something critical (and most encryption projects are critical) you want this value to be high. If the value is low, a malicious hacker can just wait out your max-age value and then change the HSTS settings and perform a downgrade attack.
Done!
After you've surfed to your https page, it will have stored this setting. So future attempts to visit the http page will just not work, your browser will recognize the cached HSTS settings of your page and just go to the https page instead.