Skip to content

SSL, Certbot, HTTP/2 and Proxy

Move to Nextcloud - SSL, Certbot, HTTP/2 and Proxy

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.

sudo a2enmod ssl
sudo systemctl restart apache2

Now, Nextcloud should available via https://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.

sudo apt install curl
# Before activating HTTP/2
curl -sI https://my.domainname.cloud -o/dev/null -w '%{http_version}\n'
1.1

# After activation HTTP/2
curl -sI https://my.domainname.cloud -o/dev/null -w '%{http_version}\n'
2