SSL, Certbot, HTTP/2 and Proxy
Move to Nextcloud - SSL, Certbot, HTTP/2 and Proxy
Project Link: Nextcloud
using SSL, Certbot and HTTP/2 without a Reverse Proxy
It took a time to wrap my head around this topic. In general, it is recommend to use a SSL certificate to encrypt the communication between Nextcloud and the client (App, Browser, Davclient, etc). The SSL Certificate can be created by yourself (self signed) or by services like Certbot.
In addition, Nextcloud advise to use HTTP/2
HTTP/2 has huge speed improvements over HTTP with multiple request. Most browsers already support HTTP/2 over TLS (HTTPS)
And to make it even more complicated, this all can be done with and without a Proxy.
SSL self signed
A self signed SSL Certificate can be used, if the Nextcloud instance is only used internally or for testing purpose and so on. Run the following to create a self signed certificate and fill out the fields.
sudo apt install openssl
openssl req -newkey rsa:4096 -nodes -keyout MyKeyFile.key -x509 -days 365 -out MyCertificateFile.csr
After creation of the needed files, adapt the /etc/apache2/sites-available/nextcloud.conf
file like this.
<VirtualHost *:443> # <-- 443 is not Standard port for SSL secrured HTTP connections a.k.a. HTTPS
ServerName YourHostLocalName
Alias / "/var/www/html/nextcloud/"
DocumentRoot "/var/www/html/nextcloud/"
<Directory /var/www/html/nextcloud/>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
ErrorLog /var/log/apache2/nextcloud.info-error_log
CustomLog /var/log/apache2/nextcloud.info-access_log common
<IfModule mod_headers.c>
Header always add Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>
# SSL Settings
SSLEngine on
SSLCertificateFile /path/to/MyCertificateFile.csr
SSLCertificateKeyFile /path/to/MyKeyFile.key
</VirtualHost>
Save the file, activate the SSL module and restart Apache web server.
Now, Nextcloud should available via http
s://YourHostName
SSL via Certbot
Self signed certificates throwing an error in your browser like This connection is not save
and so on. That is because the certificate is not verified by a Certificate Authority (CA). One CA, for example is, Let's Encrypt. They providing a certificate management program called Certbot. To create a SSL certificate via Cerbot, do the following.
At first, adapt the /etc/apache2/sites-available/nextcloud.conf
. Remove the self signed SSL entries and change ServerName to a external (Sub-)Domainname.
ServerName my.domainname.cloud # <-- external name
Alias / "/var/www/html/nextcloud/"
DocumentRoot "/var/www/html/nextcloud/"
<Directory /var/www/html/nextcloud/>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
ErrorLog /var/log/apache2/nextcloud.info-error_log
CustomLog /var/log/apache2/nextcloud.info-access_log common
<IfModule mod_headers.c>
Header always add Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>
Install Certbot and request SSL certificate.
sudo apt install certbot python3-certbot-apache
sudo certbot --apache
# At first start, provide your E-Mail Address and accept the Terms of Service
# choose the domain for which HTTPS should be activated
....
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: my.domainname.cloud
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):
....
# Optional: choose 2 in the next step to automatic forward requests via http://my.domainname.cloud to https://my.domainname.cloud
Certbot adds the following lines to the *.conf
files#.
SSLCertificateFile /path/to/CertFile/fullchain.pem
SSLCertificateKeyFile /path/to/KeyFile/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
In order to get the best security (check Qualys SSL Labs for more information), edit the protocol part of /etc/letsencrypt/options-ssl-apache.conf
like this.
....
# original approach
SSLProtocol all -SSLv3
# adapted approach
SSLProtocol +TLSv1.2 +TLSv1.3
....
If Certbot is not used, the same adaption can be done in /etc/apache2/mods-available/ssl.conf
.
HTTP/2
To activate HTTP/2 in Apache webserver, the http2
module must be loaded. Also web site, in this case, must be secured via SSL. In Addition, PHP have to be replace by PHP-FPM.
# install the needed packages
sudo apt install php8.0-fpm
# acticate PHP-FPM
sudo a2enmod proxy_fcgi setenvif
# deactivate PHP
sudo a2dismod php8.0
# deactivate Apache prefork module, which is not working with http/2
sudo a2dismod mpm_prefork
# activate http/2
sudo a2enmod mpm_event
sudo a2enmod http2
Add Protocols h2 h2c http/1.1
+ H2Direct On
to the /etc/apache2/sites-available/nextcloud.conf
<VirtualHost *:443>
ServerName YourHostName
Alias / "/var/www/html/nextcloud/"
DocumentRoot "/var/www/html/nextcloud/"
Protocols h2 h2c http/1.1
H2Direct On
<Directory /var/www/html/nextcloud/>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
ErrorLog /var/log/apache2/nextcloud.info-error_log
CustomLog /var/log/apache2/nextcloud.info-access_log common
<IfModule mod_headers.c>
Header always add Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>
SSLEngine on
SSLCertificateFile /path/to/MyCertificateFile.csr
SSLCertificateKeyFile /path/to/MyKeyFile.key
</VirtualHost>
using SSL, Certbot and HTTP/2 with a Reverse Proxy
All described above is working if the host/server running Nextcloud is connected directly to the internet, e.g. the only hosted service from the home network. If one is hosting more than one web site / service a Proxy is needed (or many forwarded ports, which is not save).
A Proxy simple does the following
- Browser: connecting to site https://my.domainname.cloud
- DNS routes Browser to external IP
- Router forwards request to internal Network
- Proxy notices the requested site and forwards it to a host1 in the local Network
- ....
- Browser: connecting to site https://anothersite.domainname.cloud
- Internet Router DNS Magic like above
- Proxy notices the requested site and forwards it to a host2 in the local Network
-----------------
|Internal Host 1|
---------- -------- ------- <==> -----------------
|Internet| <==> |Router| <==> |Proxy|
---------- -------- ------- <==> -----------------
|Internal Host 2|
-----------------
The benefit is, that only one port has to be opened in the router, e.g. port 443 to the Proxy host. In addition, the Proxy host can provide via Certbot SSL certificates for all web sites / services. Only one installation of Certbot is needed in that case.
To get all this work together, the following must be done.
# Activate the Proxy modules in Apache web server
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_ajp
sudo a2enmod rewrite
sudo a2enmod deflate
sudo a2enmod headers
sudo a2enmod proxy_balancer
sudo a2enmod proxy_connect
sudo a2enmod proxy_html
sudo a2enmod ssl
With this Setup, it would be possible to routing http://my.domainname.cloud
requests from the internet to http://localhost1
within the local Network by creating the following file at the Proxy host (assuming DynDNS and port forwarding already in place).
# file /etc/apache2/sites-enabled/mydomainnamecloud.conf
<VirtualHost *:80>
ServerName my.domainname.cloud
ProxyPreserveHost On
DocumentRoot /var/www/html
ProxyPass /.well-known !
ProxyPass / http://localhost1
ProxyPassReverse / http://localhost1
</VirtualHost>
Creating SSL Certificate by using Certbot at the Proxy host would lead to another file called /etc/apache2/sites-enabled/mydomainnamecloud-le-ssl.conf
, which then includes the SSL Certificate settings.
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName my.domainname.cloud
ProxyPreserveHost On
DocumentRoot /var/www/html
ProxyPass /.well-known !
ProxyPass / http://localhost1
ProxyPassReverse / http://localhost1
SSLCertificateFile /etc/letsencrypt/live/my.domainname.cloud/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/my.domainname.cloud /privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
But this Setup would lead the client (e.g. browser) to use HTTP 1.1. To use HTTP/2 do the following at the Proxy host.
# Activate http/2 modules
sudo a2enmod http2
sudo a2enmod proxy_http2
# install PHP-FPM, activate the needed modules and deactivate PHP module (if activated)
sudo apt install php8.0-fpm
sudo a2enmod proxy_fcgi setenvif
sudo a2dismod php8.0
# deactivate Apache prefork module, which is not working with http/2
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
Add the Protocols h2 h2c http/1.1
+ H2Direct On
lines into the SSL conf for the web site at the Proxy host and adapt the ProxyPass
and ProxyPassReverse
lines like this.
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName my.domainname.cloud
Protocols h2 h2c http/1.1
H2Direct On
ProxyPreserveHost On
DocumentRoot /var/www/html
ProxyPass /.well-known !
ProxyPass / h2c://localhost1
ProxyPassReverse / http://localhost1
SSLCertificateFile /path/to/CertFile/fullchain.pem
SSLCertificateKeyFile /path/to/KeyFile/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
In this case web site is reachable at http://localhost1
in the local Network. To use HTTP/2 add also the line Protocols h2 h2c http/1.1
to /etc/apache2/sites-enabled/localhost1.conf
.
ServerName localhost1
Alias / "/var/www/html/nextcloud/"
DocumentRoot "/var/www/html/nextcloud/"
Protocols h2 h2c http/1.1
<Directory /var/www/html/nextcloud/>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
ErrorLog /var/log/apache2/nextcloud.info-error_log
CustomLog /var/log/apache2/nextcloud.info-access_log common
<IfModule mod_headers.c>
Header always add Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>
Finally check with curl
if HTTP/2 is used.