Apache 2.4 SSL_ERROR_RX_RECORD_TOO_LONG – Fix with Certbot on Ubuntu 16.04

apache-2.4certbotubuntu-16.04virtualhost

I have the following setup:

  • Apache 2.4
  • Ubuntu 16.04 LTS
  • letsencrypt / certbot

Now, as soon as I enable the following .conf on the default server, all my configured top level domains receive a SSL_ERROR_RX_RECORD_TOO_LONG error. If I disable this config, everything works as expected.

Because of this fact, I am sure, apache listens to the correct ports, to the correct IPs, and letsencrypt/certbot is correctly setup.

<VirtualHost _default_:443>
    DocumentRoot "/var/www/html"
    <Directory "/var/www/html">
            Require all denied
    </Directory>
</VirtualHost>

Changing this to

<VirtualHost _default_:443>
    DocumentRoot "/var/www/html"
    <Directory "/var/www/html">
            Require all granted
    </Directory>
</VirtualHost>

has not solved the problem.

apache2ctl -S 

shows the expected results, 001-default-ssl.conf and 001-default.conf are the defaults for port 80 and port 443.

openssl s_client -connect workingdomain.tld:443

prints:

CONNECTED(00000003)
139991513372312:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:794:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 305 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1515852550
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

Again, as soon as I disable this config, every domain configured with certbot/letsencrypt works as expected.

I don't get this, since I am basically blocking only the default server, all my other domains should be unaffected by this setting.

Best Answer

You have to point to your SSL certificate -

<VirtualHost _default_:443>
    ServerName example.com
    ServerAlias www.example.com
    ServerAdmin webmaster@example.com
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
    CustomLog ${APACHE_LOG_DIR}/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    DocumentRoot /var/www-example.com
    <directory /var/www-example.com>
        Options All
                AllowOverride All
                Require all granted
    </directory>
    ErrorLog ${APACHE_LOG_DIR}/ssl-example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/ssl-example.com-access.log combined
</VirtualHost>

If you want to serve multiple domains, you can still do so at least for modern browsers that understand SNI/etc.

First, obtain separate letsencrypt certs for each domain. If you have multple hostnames (ie, both www.example.com and example.com) they can share, as long as the actual domain is the same.

letsencrypt certonly -d example1.com -d www.example1.com -d mail.example1.com
letsencrypt certonly -d example2.com -d www.example2.com -d mail.example2.com

This will give you 2 sets of certs, under the /etc/letsencrypt/live/DOMAIN/ directories.

When you create your vhost configs, instead of specifying the _default_:443 use the actual IP of the host and point to the appropriate certificate files.

<VirtualHost 10.0.1.2:443>
    ServerName example1.com
    ServerAlias www.example1.com
    ServerAdmin webmaster@example1.com
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example1.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example1.com/privkey.pem
    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
    CustomLog ${APACHE_LOG_DIR}/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    DocumentRoot /var/www-example1.com
    <directory /var/www-example1.com>
        Options All
                AllowOverride All
                Require all granted
    </directory>
    ErrorLog ${APACHE_LOG_DIR}/ssl-example1.com-error.log
    CustomLog ${APACHE_LOG_DIR}/ssl-example1.com-access.log combined
</VirtualHost>
<VirtualHost 10.0.1.2:443>
    ServerName example2.com
    ServerAlias www.example2.com
    ServerAdmin webmaster@example2.com
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example2.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example2.com/privkey.pem
    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
    CustomLog ${APACHE_LOG_DIR}/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    DocumentRoot /var/www-example2.com
    <directory /var/www-example2.com>
        Options All
                AllowOverride All
                Require all granted
    </directory>
    ErrorLog ${APACHE_LOG_DIR}/ssl-example2.com-error.log
    CustomLog ${APACHE_LOG_DIR}/ssl-example2.com-access.log combined
</VirtualHost>

I don't collect form info, etc. on my sites, but I do want everything to run HTTPS so I set up vhost configs to redirect non-HTTPS requests to the HTTPS side, with a non-named catch-all that redirects to example1.com -

<VirtualHost *:80>
  RewriteEngine on
  RewriteRule ^/(.*)$ https://example1.com/$1 [R,L]
</VirtualHost>
<VirtualHost *:80>
  ServerName example1.com
  ServerAlias www.example1.com
  RewriteEngine on
  RewriteRule ^/(.*)$ https://example1.com/$1 [R,L]
</VirtualHost>
<VirtualHost *:80>
  ServerName example2.com
  ServerAlias www.example2.com
  RewriteEngine on
  RewriteRule ^/(.*)$ https://example2.com/$1 [R,L]
</VirtualHost>