Apache: Difference between revisions

From Lolly's Wiki
Jump to navigationJump to search
No edit summary
Line 132: Line 132:
=== Serving mp4 media files ===
=== Serving mp4 media files ===
If your media files are on a network filesystem like CIFS or NFS you should disable memory mapping (EnableMMAP Off) to avoid corrupted data at the client side and allow seeking inside the video.
If your media files are on a network filesystem like CIFS or NFS you should disable memory mapping (EnableMMAP Off) to avoid corrupted data at the client side and allow seeking inside the video.
<source lang=Apache config files>
<source lang=apache>
<Directory /var/www/media-files>
<Directory /var/www/media-files>
         Options -Indexes
         Options -Indexes
Line 148: Line 148:
=== SSL configuration ===
=== SSL configuration ===
/etc/apache2/mods-available/ssl.conf
/etc/apache2/mods-available/ssl.conf
<source lang=Apache config files>
<source lang=apache>
<IfModule mod_ssl.c>
<IfModule mod_ssl.c>
...
...
Line 157: Line 157:
</source>
</source>


<source lang=Apache config files>
<source lang=apache>
<VirtualHost ssl.server.de:443>
<VirtualHost ssl.server.de:443>
     # ...
     # ...
Line 221: Line 221:
===SSLLabs A+ with all 100%===
===SSLLabs A+ with all 100%===
'''If you consider to take this snippet be warned. Old clients have no chance to reach the server.'''
'''If you consider to take this snippet be warned. Old clients have no chance to reach the server.'''
<source lang=Apache config files>
<source lang=apache>
<VirtualHost ssl.server.de:443>
<VirtualHost ssl.server.de:443>
   ...
   ...
Line 253: Line 253:
==Client certificates==
==Client certificates==


<source lang=Apache config files>
<source lang=apache>
   #
   #
   ## <ClientCertificate>
   ## <ClientCertificate>
Line 284: Line 284:
# ls  /var/log/apache2/*.log | xargs -n 1 echo -f | xargs apachetop
# ls  /var/log/apache2/*.log | xargs -n 1 echo -f | xargs apachetop
</source>
</source>
lollypop@lollybook:~/Kunden/NDR/SMS$ vi /tmp/bli
lollypop@lollybook:~/Kunden/NDR/SMS$ vi /tmp/bli
lollypop@lollybook:~/Kunden/NDR/SMS$ cat /tmp/bli
[[Category:Webserver]]
== Create certificate ==
===Simple script===
<syntaxhighlight lang=bash>
#!/bin/bash
BASE_SUBJECT='/C=DE/ST=Hamburg/L=Hamburg/O=MyOrg/OU=IT'
BASEDIR=/etc/apache2
DAYS=$[ 5 * 365 ]
KEY_DIR=${BASEDIR}/ssl.key
CRT_DIR=${BASEDIR}/ssl.crt
if [ $# -eq 0 ]
then
  printf "usage: $0 <webserver-name> [<alias1> <alias2>...]\n"
  exit 1
fi 
CN=$1
declare -a subject_alt_names;
for i in ${*}
do
  subject_alt_names=( ${subject_alt_names[*]} "DNS:${i}")
done
echo ${subject_alt_names[*]}
SHORT=${CN%%.*}
KEY=${KEY_DIR}/${SHORT}.key
CRT=${CRT_DIR}/${SHORT}.crt
OLD_IFS=${IFS}
IFS=","
openssl req \
-new \
-days ${DAYS} \
-newkey rsa:4096bits \
-sha512 \
-x509 \
-nodes \
-out ${CRT} \
-keyout ${KEY} \
-subj "${BASE_SUBJECT}/CN=${CN}" \
-reqexts SAN \
-extensions SAN \
-config <(
          cat /etc/ssl/openssl.cnf
          printf "[ext]\nbasicConstraints=CA:FALSE,pathlen:0\n[SAN]\n%s\n" \
            "${subject_alt_names:+subjectAltName = ${subject_alt_names[*]}}"
        )
IFS=${OLD_IFS}
printf "Put this in your Apache config:\n\n\tSSLCertificateFile    %s\n\tSSLCertificateKeyFile %s\n\n" "${CRT}" "${KEY}"
</syntaxhighlight>
===Adjust the OpenSSL default values===
Set the country, etc. to values that match your needs:
<syntaxhighlight lang=bash>
# vi /etc/ssl/openssl.cnf
</syntaxhighlight>
===Generate key===
<syntaxhighlight lang=bash>
# openssl ecparam -genkey -name secp256r1 | openssl ec -aes256 -out server.de.ec-key
read EC key
using curve name prime256v1 instead of secp256r1
writing EC key
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
</syntaxhighlight>
If you don't need a password protected encrypted key file, you can remove the encryption like this:
<syntaxhighlight lang=bash>
# openssl ec -in server.de.ec-key -out server.de.ec-key
read EC key
Enter PEM pass phrase:
writing EC key
</syntaxhighlight>
===Issue certificate===
<syntaxhighlight lang=bash>
# openssl req -new -x509 -sha256 -key server.de.ec-key -out server.de-wildcard.pem -days 1825 -nodes
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [DE]:
State or Province Name (full name) [Hamburg]:
Locality Name (eg, city) [Hamburg]:
Organization Name (eg, company) [My Site]:
Organizational Unit Name (eg, section) [Sub]:
Common Name (e.g. server FQDN or YOUR name) []:*.server.de
Email Address [ssl@server.de]:
</syntaxhighlight>
===View certificate===
<syntaxhighlight lang=bash>
# openssl x509 -text -noout -in server.de-wildcard.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: ... (0x...)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C=DE, ST=Hamburg, L=Hamburg, O=My Site, OU=Sub, CN=*.server.de/emailAddress=ssl@server.de
        Validity
            Not Before: Apr 16 09:35:02 2015 GMT
            Not After : Apr 14 09:35:02 2020 GMT
        Subject: C=DE, ST=Hamburg, L=Hamburg, O=My Site, OU=Sub, CN=*.server.de/emailAddress=ssl@server.de
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    ...
                ASN1 OID: prime256v1
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                ...
            X509v3 Authority Key Identifier:
                keyid:...
            X509v3 Basic Constraints:
                CA:TRUE
    Signature Algorithm: ecdsa-with-SHA256
        ...
</syntaxhighlight>
==Configuring Apache==
=== Serving mp4 media files ===
If your media files are on a network filesystem like CIFS or NFS you should disable memory mapping (EnableMMAP Off) to avoid corrupted data at the client side and allow seeking inside the video.
<syntaxhighlight lang=apache>
<Directory /var/www/media-files>
        Options -Indexes
        AllowOverride None
        Require all granted
        <IfModule mod_mime>
          AddType video/mp4 .mp4
        </IfModule>
        EnableMMAP Off
</Directory>
</syntaxhighlight>
=== SSL configuration ===
/etc/apache2/mods-available/ssl.conf
<syntaxhighlight lang=apache>
<IfModule mod_ssl.c>
...
        SSLUseStapling On
        SSLStaplingCache      "shmcb:${APACHE_RUN_DIR}/stapling_cache(128000)"
...
</IfModule>
</syntaxhighlight>
<syntaxhighlight lang=apache>
<VirtualHost ssl.server.de:443>
    # ...
 
    SSLEngine On
    # Do this only if you are sure you have no old clients
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    # If you need to support old clients use this instead
    # SSLProtocol all -SSLv2 -SSLv3 -TLSv1
    SSLCompression off
    SSLHonorCipherOrder On
    # Do this only if you are sure you have no old clients
    SSLCipherSuite      HIGH:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!AES256+RSA:!AES128:!ADH:!EXP:!SSLv2:!SSLv3:!MEDIUM:!LOW:!NULL:!aNULL
    # If you need to support old clients use this instead
    # SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:HIGH:!DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4:!SSLv2:!SSLv3
    SSLCertificateFile      /etc/letsencrypt/live/ssl.server.de/fullchain.pem
    SSLCertificateKeyFile  /etc/letsencrypt/live/ssl.server.de/privkey.pem
    SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
    # Generate DH parameters with
    # # openssl dhparam -out /etc/ssl/certs/dhparam_4096.pem 4096
    SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam_4096.pem"
    SSLOpenSSLConfCmd ECDHParameters Automatic
    SSLOpenSSLConfCmd Curves secp521r1:secp384r1:prime256v1
    SetEnvIfNoCase Referer ^https://ssl\.server\.de keep_cookies
    RequestHeader unset Cookie env=!keep_cookies
    <IfModule mod_headers.c>
      # https://kb.sucuri.net/warnings/hardening/headers-x-content-type
      Header set X-Content-Type-Options nosniff
      # https://kb.sucuri.net/warnings/hardening/headers-x-frame-clickjacking
      Header append X-FRAME-OPTIONS "SAMEORIGIN"
      # https://kb.sucuri.net/warnings/hardening/headers-x-xss-protection
      Header set X-XSS-Protection "1; mode=block"
      # Strict Transport Security
      Header always set Strict-Transport-Security "max-age=31556926;"
      # Public Key Pins
      Header always set Public-Key-Pins "max-age=5184000; pin-sha256=\"...\"; pin-sha256=\"...\"; includeSubDomains"
    </IfModule>
   
    <IfModule mod_rewrite.c>
      RewriteEngine On
      # https://kb.sucuri.net/warnings/hardening/http-trace HTTP Trace Method
      RewriteCond %{REQUEST_METHOD} ^TRACE
      RewriteRule .* - [F]
    </IfModule>
</VirtualHost>
</syntaxhighlight>
===SSLLabs A+ with all 100%===
'''If you consider to take this snippet be warned. Old clients have no chance to reach the server.'''
<syntaxhighlight lang=apache>
<VirtualHost ssl.server.de:443>
  ...
  # SSL parameters
  SSLEngine On
  SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
  SSLCipherSuite  DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA
  SSLHonorCipherOrder on
  SSLUseStapling on
  SSLCompression off
  SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
  SSLCertificateFile      /etc/letsencrypt/live/ssl.server.de/fullchain.pem
  SSLCertificateKeyFile  /etc/letsencrypt/live/ssl.server.de/privkey.pem
  SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"
  SSLOpenSSLConfCmd ECDHParameters Automatic
  SSLOpenSSLConfCmd Curves secp521r1:secp384r1:prime256v1
  <IfModule mod_headers.c>
    # Add security and privacy related headers
    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
    Header always set Strict-Transport-Security "max-age=31556926; includeSubDomains; preload"
    Header always set X-Frame-Options SAMEORIGIN
    Header always set X-Content-Type-Options nosniff
    Header set X-XSS-Protection "1; mode=block"
    Header set X-Robots-Tag "none"
    SetEnv modHeadersAvailable true
  </IfModule>
  ...
</VirtualHost>
</syntaxhighlight>
==Client certificates==
<syntaxhighlight lang=apache>
  #
  ## <ClientCertificate>
  #
  SSLVerifyClient none
  SSLCACertificateFile "/var/log/apache2/conf/ca.crt"
  SSLCARevocationFile  "/var/log/apache2/conf/crl.pem"
  SSLCARevocationCheck chain
  CustomLog "/var/log/apache2/logs/ssl_user.log" \
          "%t %h Serial=%{SSL_CLIENT_M_SERIAL}x User=%{SSL_CLIENT_S_DN_CN}x \"%r\" %b"
  <Location />
    SSLVerifyClient      require
    SSLVerifyDepth      10
    SSLOptions          +FakeBasicAuth
    SSLRequireSSL
    SSLRequire      %{SSL_CLIENT_S_DN_O}  eq "Your Organization" \
                and %{SSL_CLIENT_S_DN_OU} in {"AllowedOU1","AllowedOU2"}
  </Location>
  #
  ## </ClientCertificate>
  #
</syntaxhighlight>
==ApacheTop==
Top of all sites on your host:
<syntaxhighlight lang=bash>
# ls  /var/log/apache2/*.log | xargs -n 1 echo -f | xargs apachetop
</syntaxhighlight>

Revision as of 14:49, 25 November 2021


Create certificate

Simple script

#!/bin/bash

BASE_SUBJECT='/C=DE/ST=Hamburg/L=Hamburg/O=MyOrg/OU=IT'
BASEDIR=/etc/apache2
DAYS=$[ 5 * 365 ]
KEY_DIR=${BASEDIR}/ssl.key
CRT_DIR=${BASEDIR}/ssl.crt

if [ $# -eq 0 ]
then
  printf "usage: $0 <webserver-name> [<alias1> <alias2>...]\n"
  exit 1
fi  

CN=$1
declare -a subject_alt_names;
for i in ${*}
do
  subject_alt_names=( ${subject_alt_names[*]} "DNS:${i}")
done
echo ${subject_alt_names[*]}

SHORT=${CN%%.*}
KEY=${KEY_DIR}/${SHORT}.key
CRT=${CRT_DIR}/${SHORT}.crt

OLD_IFS=${IFS}
IFS=","
openssl req \
	-new \
	-days ${DAYS} \
	-newkey rsa:4096bits \
	-sha512 \
	-x509 \
	-nodes \
	-out ${CRT} \
	-keyout ${KEY} \
	-subj "${BASE_SUBJECT}/CN=${CN}" \
	-reqexts SAN \
	-extensions SAN \
	-config <( 
          cat /etc/ssl/openssl.cnf
          printf "[ext]\nbasicConstraints=CA:FALSE,pathlen:0\n[SAN]\n%s\n" \
            "${subject_alt_names:+subjectAltName = ${subject_alt_names[*]}}"
         )
IFS=${OLD_IFS}
printf "Put this in your Apache config:\n\n\tSSLCertificateFile    %s\n\tSSLCertificateKeyFile %s\n\n" "${CRT}" "${KEY}"

Adjust the OpenSSL default values

Set the country, etc. to values that match your needs:

# vi /etc/ssl/openssl.cnf

Generate key

# openssl ecparam -genkey -name secp256r1 | openssl ec -aes256 -out server.de.ec-key
read EC key
using curve name prime256v1 instead of secp256r1
writing EC key
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

If you don't need a password protected encrypted key file, you can remove the encryption like this:

# openssl ec -in server.de.ec-key -out server.de.ec-key
read EC key
Enter PEM pass phrase:
writing EC key

Issue certificate

# openssl req -new -x509 -sha256 -key server.de.ec-key -out server.de-wildcard.pem -days 1825 -nodes

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [DE]:
State or Province Name (full name) [Hamburg]:
Locality Name (eg, city) [Hamburg]:
Organization Name (eg, company) [My Site]:
Organizational Unit Name (eg, section) [Sub]:
Common Name (e.g. server FQDN or YOUR name) []:*.server.de
Email Address [ssl@server.de]:

View certificate

# openssl x509 -text -noout -in server.de-wildcard.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: ... (0x...)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C=DE, ST=Hamburg, L=Hamburg, O=My Site, OU=Sub, CN=*.server.de/emailAddress=ssl@server.de
        Validity
            Not Before: Apr 16 09:35:02 2015 GMT
            Not After : Apr 14 09:35:02 2020 GMT
        Subject: C=DE, ST=Hamburg, L=Hamburg, O=My Site, OU=Sub, CN=*.server.de/emailAddress=ssl@server.de
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    ...
                ASN1 OID: prime256v1
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                ...
            X509v3 Authority Key Identifier: 
                keyid:...

            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: ecdsa-with-SHA256
         ...

Configuring Apache

Serving mp4 media files

If your media files are on a network filesystem like CIFS or NFS you should disable memory mapping (EnableMMAP Off) to avoid corrupted data at the client side and allow seeking inside the video.

<Directory /var/www/media-files>
        Options -Indexes

        AllowOverride None
        Require all granted

        <IfModule mod_mime>
          AddType video/mp4 .mp4
        </IfModule>
        EnableMMAP Off
</Directory>

SSL configuration

/etc/apache2/mods-available/ssl.conf

<IfModule mod_ssl.c>
...
        SSLUseStapling On
        SSLStaplingCache      "shmcb:${APACHE_RUN_DIR}/stapling_cache(128000)"
...
</IfModule>
<VirtualHost ssl.server.de:443>
    # ...
  
    SSLEngine On
    # Do this only if you are sure you have no old clients
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    # If you need to support old clients use this instead
    # SSLProtocol all -SSLv2 -SSLv3 -TLSv1

    SSLCompression off
    SSLHonorCipherOrder On

    # Do this only if you are sure you have no old clients
    SSLCipherSuite      HIGH:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!AES256+RSA:!AES128:!ADH:!EXP:!SSLv2:!SSLv3:!MEDIUM:!LOW:!NULL:!aNULL

    # If you need to support old clients use this instead
    # SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:HIGH:!DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4:!SSLv2:!SSLv3


    SSLCertificateFile      /etc/letsencrypt/live/ssl.server.de/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/ssl.server.de/privkey.pem

    SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire

    # Generate DH parameters with
    # # openssl dhparam -out /etc/ssl/certs/dhparam_4096.pem 4096
    SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam_4096.pem"
    SSLOpenSSLConfCmd ECDHParameters Automatic
    SSLOpenSSLConfCmd Curves secp521r1:secp384r1:prime256v1

    SetEnvIfNoCase Referer ^https://ssl\.server\.de keep_cookies
    RequestHeader unset Cookie env=!keep_cookies

    <IfModule mod_headers.c>
      # https://kb.sucuri.net/warnings/hardening/headers-x-content-type
      Header set X-Content-Type-Options nosniff

      # https://kb.sucuri.net/warnings/hardening/headers-x-frame-clickjacking
      Header append X-FRAME-OPTIONS "SAMEORIGIN"

      # https://kb.sucuri.net/warnings/hardening/headers-x-xss-protection
      Header set X-XSS-Protection "1; mode=block"

      # Strict Transport Security
      Header always set Strict-Transport-Security "max-age=31556926;"

      # Public Key Pins
      Header always set Public-Key-Pins "max-age=5184000; pin-sha256=\"...\"; pin-sha256=\"...\"; includeSubDomains"
    </IfModule>

    
    <IfModule mod_rewrite.c>
      RewriteEngine On

      # https://kb.sucuri.net/warnings/hardening/http-trace HTTP Trace Method 
      RewriteCond %{REQUEST_METHOD} ^TRACE 
      RewriteRule .* - [F]
    </IfModule>
</VirtualHost>

SSLLabs A+ with all 100%

If you consider to take this snippet be warned. Old clients have no chance to reach the server.

<VirtualHost ssl.server.de:443>
  ...
  # SSL parameters
  SSLEngine On
  SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
  SSLCipherSuite  DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA
  SSLHonorCipherOrder on
  SSLUseStapling on
  SSLCompression off
  SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
  SSLCertificateFile      /etc/letsencrypt/live/ssl.server.de/fullchain.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/ssl.server.de/privkey.pem
  SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"
  SSLOpenSSLConfCmd ECDHParameters Automatic
  SSLOpenSSLConfCmd Curves secp521r1:secp384r1:prime256v1
  <IfModule mod_headers.c>
    # Add security and privacy related headers
    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
    Header always set Strict-Transport-Security "max-age=31556926; includeSubDomains; preload"
    Header always set X-Frame-Options SAMEORIGIN
    Header always set X-Content-Type-Options nosniff
    Header set X-XSS-Protection "1; mode=block"
    Header set X-Robots-Tag "none"
    SetEnv modHeadersAvailable true
  </IfModule>
  ...
</VirtualHost>

Client certificates

  #
  ## <ClientCertificate>
  #
  SSLVerifyClient none
  SSLCACertificateFile "/var/log/apache2/conf/ca.crt"
  SSLCARevocationFile  "/var/log/apache2/conf/crl.pem"
  SSLCARevocationCheck chain

  CustomLog "/var/log/apache2/logs/ssl_user.log" \
          "%t %h Serial=%{SSL_CLIENT_M_SERIAL}x User=%{SSL_CLIENT_S_DN_CN}x \"%r\" %b"

  <Location />
    SSLVerifyClient      require
    SSLVerifyDepth       10
    SSLOptions           +FakeBasicAuth
    SSLRequireSSL
    SSLRequire       %{SSL_CLIENT_S_DN_O}  eq "Your Organization" \
                 and %{SSL_CLIENT_S_DN_OU} in {"AllowedOU1","AllowedOU2"}
  </Location>
  #
  ## </ClientCertificate>
  #

ApacheTop

Top of all sites on your host:

# ls  /var/log/apache2/*.log | xargs -n 1 echo -f | xargs apachetop

lollypop@lollybook:~/Kunden/NDR/SMS$ vi /tmp/bli lollypop@lollybook:~/Kunden/NDR/SMS$ vi /tmp/bli lollypop@lollybook:~/Kunden/NDR/SMS$ cat /tmp/bli

Create certificate

Simple script

#!/bin/bash

BASE_SUBJECT='/C=DE/ST=Hamburg/L=Hamburg/O=MyOrg/OU=IT'
BASEDIR=/etc/apache2
DAYS=$[ 5 * 365 ]
KEY_DIR=${BASEDIR}/ssl.key
CRT_DIR=${BASEDIR}/ssl.crt

if [ $# -eq 0 ]
then
  printf "usage: $0 <webserver-name> [<alias1> <alias2>...]\n"
  exit 1
fi  

CN=$1
declare -a subject_alt_names;
for i in ${*}
do
  subject_alt_names=( ${subject_alt_names[*]} "DNS:${i}")
done
echo ${subject_alt_names[*]}

SHORT=${CN%%.*}
KEY=${KEY_DIR}/${SHORT}.key
CRT=${CRT_DIR}/${SHORT}.crt

OLD_IFS=${IFS}
IFS=","
openssl req \
	-new \
	-days ${DAYS} \
	-newkey rsa:4096bits \
	-sha512 \
	-x509 \
	-nodes \
	-out ${CRT} \
	-keyout ${KEY} \
	-subj "${BASE_SUBJECT}/CN=${CN}" \
	-reqexts SAN \
	-extensions SAN \
	-config <( 
          cat /etc/ssl/openssl.cnf
          printf "[ext]\nbasicConstraints=CA:FALSE,pathlen:0\n[SAN]\n%s\n" \
            "${subject_alt_names:+subjectAltName = ${subject_alt_names[*]}}"
         )
IFS=${OLD_IFS}
printf "Put this in your Apache config:\n\n\tSSLCertificateFile    %s\n\tSSLCertificateKeyFile %s\n\n" "${CRT}" "${KEY}"

Adjust the OpenSSL default values

Set the country, etc. to values that match your needs:

# vi /etc/ssl/openssl.cnf

Generate key

# openssl ecparam -genkey -name secp256r1 | openssl ec -aes256 -out server.de.ec-key
read EC key
using curve name prime256v1 instead of secp256r1
writing EC key
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

If you don't need a password protected encrypted key file, you can remove the encryption like this:

# openssl ec -in server.de.ec-key -out server.de.ec-key
read EC key
Enter PEM pass phrase:
writing EC key

Issue certificate

# openssl req -new -x509 -sha256 -key server.de.ec-key -out server.de-wildcard.pem -days 1825 -nodes

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [DE]:
State or Province Name (full name) [Hamburg]:
Locality Name (eg, city) [Hamburg]:
Organization Name (eg, company) [My Site]:
Organizational Unit Name (eg, section) [Sub]:
Common Name (e.g. server FQDN or YOUR name) []:*.server.de
Email Address [ssl@server.de]:

View certificate

# openssl x509 -text -noout -in server.de-wildcard.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: ... (0x...)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C=DE, ST=Hamburg, L=Hamburg, O=My Site, OU=Sub, CN=*.server.de/emailAddress=ssl@server.de
        Validity
            Not Before: Apr 16 09:35:02 2015 GMT
            Not After : Apr 14 09:35:02 2020 GMT
        Subject: C=DE, ST=Hamburg, L=Hamburg, O=My Site, OU=Sub, CN=*.server.de/emailAddress=ssl@server.de
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    ...
                ASN1 OID: prime256v1
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                ...
            X509v3 Authority Key Identifier: 
                keyid:...

            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: ecdsa-with-SHA256
         ...

Configuring Apache

Serving mp4 media files

If your media files are on a network filesystem like CIFS or NFS you should disable memory mapping (EnableMMAP Off) to avoid corrupted data at the client side and allow seeking inside the video.

<Directory /var/www/media-files>
        Options -Indexes

        AllowOverride None
        Require all granted

        <IfModule mod_mime>
          AddType video/mp4 .mp4
        </IfModule>
        EnableMMAP Off
</Directory>

SSL configuration

/etc/apache2/mods-available/ssl.conf

<IfModule mod_ssl.c>
...
        SSLUseStapling On
        SSLStaplingCache      "shmcb:${APACHE_RUN_DIR}/stapling_cache(128000)"
...
</IfModule>
<VirtualHost ssl.server.de:443>
    # ...
  
    SSLEngine On
    # Do this only if you are sure you have no old clients
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    # If you need to support old clients use this instead
    # SSLProtocol all -SSLv2 -SSLv3 -TLSv1

    SSLCompression off
    SSLHonorCipherOrder On

    # Do this only if you are sure you have no old clients
    SSLCipherSuite      HIGH:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!AES256+RSA:!AES128:!ADH:!EXP:!SSLv2:!SSLv3:!MEDIUM:!LOW:!NULL:!aNULL

    # If you need to support old clients use this instead
    # SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:HIGH:!DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4:!SSLv2:!SSLv3


    SSLCertificateFile      /etc/letsencrypt/live/ssl.server.de/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/ssl.server.de/privkey.pem

    SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire

    # Generate DH parameters with
    # # openssl dhparam -out /etc/ssl/certs/dhparam_4096.pem 4096
    SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam_4096.pem"
    SSLOpenSSLConfCmd ECDHParameters Automatic
    SSLOpenSSLConfCmd Curves secp521r1:secp384r1:prime256v1

    SetEnvIfNoCase Referer ^https://ssl\.server\.de keep_cookies
    RequestHeader unset Cookie env=!keep_cookies

    <IfModule mod_headers.c>
      # https://kb.sucuri.net/warnings/hardening/headers-x-content-type
      Header set X-Content-Type-Options nosniff

      # https://kb.sucuri.net/warnings/hardening/headers-x-frame-clickjacking
      Header append X-FRAME-OPTIONS "SAMEORIGIN"

      # https://kb.sucuri.net/warnings/hardening/headers-x-xss-protection
      Header set X-XSS-Protection "1; mode=block"

      # Strict Transport Security
      Header always set Strict-Transport-Security "max-age=31556926;"

      # Public Key Pins
      Header always set Public-Key-Pins "max-age=5184000; pin-sha256=\"...\"; pin-sha256=\"...\"; includeSubDomains"
    </IfModule>

    
    <IfModule mod_rewrite.c>
      RewriteEngine On

      # https://kb.sucuri.net/warnings/hardening/http-trace HTTP Trace Method 
      RewriteCond %{REQUEST_METHOD} ^TRACE 
      RewriteRule .* - [F]
    </IfModule>
</VirtualHost>

SSLLabs A+ with all 100%

If you consider to take this snippet be warned. Old clients have no chance to reach the server.

<VirtualHost ssl.server.de:443>
  ...
  # SSL parameters
  SSLEngine On
  SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
  SSLCipherSuite  DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA
  SSLHonorCipherOrder on
  SSLUseStapling on
  SSLCompression off
  SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
  SSLCertificateFile      /etc/letsencrypt/live/ssl.server.de/fullchain.pem
  SSLCertificateKeyFile   /etc/letsencrypt/live/ssl.server.de/privkey.pem
  SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"
  SSLOpenSSLConfCmd ECDHParameters Automatic
  SSLOpenSSLConfCmd Curves secp521r1:secp384r1:prime256v1
  <IfModule mod_headers.c>
    # Add security and privacy related headers
    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
    Header always set Strict-Transport-Security "max-age=31556926; includeSubDomains; preload"
    Header always set X-Frame-Options SAMEORIGIN
    Header always set X-Content-Type-Options nosniff
    Header set X-XSS-Protection "1; mode=block"
    Header set X-Robots-Tag "none"
    SetEnv modHeadersAvailable true
  </IfModule>
  ...
</VirtualHost>

Client certificates

  #
  ## <ClientCertificate>
  #
  SSLVerifyClient none
  SSLCACertificateFile "/var/log/apache2/conf/ca.crt"
  SSLCARevocationFile  "/var/log/apache2/conf/crl.pem"
  SSLCARevocationCheck chain

  CustomLog "/var/log/apache2/logs/ssl_user.log" \
          "%t %h Serial=%{SSL_CLIENT_M_SERIAL}x User=%{SSL_CLIENT_S_DN_CN}x \"%r\" %b"

  <Location />
    SSLVerifyClient      require
    SSLVerifyDepth       10
    SSLOptions           +FakeBasicAuth
    SSLRequireSSL
    SSLRequire       %{SSL_CLIENT_S_DN_O}  eq "Your Organization" \
                 and %{SSL_CLIENT_S_DN_OU} in {"AllowedOU1","AllowedOU2"}
  </Location>
  #
  ## </ClientCertificate>
  #

ApacheTop

Top of all sites on your host:

# ls  /var/log/apache2/*.log | xargs -n 1 echo -f | xargs apachetop