Creating a Multi-Domain (SAN) Self-Signed SSL Certificate for Apache2 on a Single IP Server


3 views

When running multiple virtual hosts on Apache2 with a single IP address, SSL presents a unique challenge. The SSL/TLS handshake occurs before the HTTP request is processed, which means Apache can't determine which virtual host should handle the request until after the secure connection is established. This creates a chicken-and-egg problem for name-based virtual hosting with SSL.

The solution is to create a certificate that includes all your domains through Subject Alternative Names (SAN). Here's how to generate such a certificate:


# Generate private key
openssl genrsa -out server.key 2048

# Create CSR configuration file (san.cnf)
cat > san.cnf << EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[dn]
C = US
ST = California
L = San Francisco
O = My Company
OU = IT
CN = primary.example.com

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = primary.example.com
DNS.2 = secondary.example.com
DNS.3 = dev.example.com
DNS.4 = *.subdomain.example.com
EOF

# Generate CSR
openssl req -new -key server.key -out server.csr -config san.cnf

# Generate self-signed certificate
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -extensions req_ext -extfile san.cnf

After generating the certificate, configure Apache to use it for all virtual hosts:


<VirtualHost *:443>
    ServerName primary.example.com
    ServerAlias secondary.example.com dev.example.com
    
    SSLEngine on
    SSLCertificateFile /path/to/server.crt
    SSLCertificateKeyFile /path/to/server.key
    
    # Your other configuration here
</VirtualHost>

<VirtualHost *:443>
    ServerName subdomain.example.com
    ServerAlias *.subdomain.example.com
    
    SSLEngine on
    SSLCertificateFile /path/to/server.crt
    SSLCertificateKeyFile /path/to/server.key
    
    # Your other configuration here
</VirtualHost>

1. Browser Warnings: Self-signed certificates will trigger security warnings in browsers. For production use, consider a free certificate from Let's Encrypt.

2. Wildcard Limitations: While *.example.com covers all subdomains, it won't match example.com itself - you need to include both.

3. Certificate Management: Keep track of expiration dates and regenerate certificates before they expire.

After making changes, always test your configuration:


apachectl configtest
systemctl reload apache2

You can verify the certificate contains all your domains with:


openssl x509 -in server.crt -text -noout | grep -A 1 "Subject Alternative Name"

When running multiple virtual hosts on a single IP address with Apache2, traditional SSL certificates present a fundamental challenge. The SSL/TLS handshake occurs before the HTTP Host header is examined, creating what's known as the "SNI limitation" for non-SNI clients. This means we need a single certificate that can validate multiple domains.

The answer lies in using Subject Alternative Name (SAN) extensions in your X.509 certificate. This allows you to specify multiple domain names in a single certificate. Here's how to create one:


# Generate private key
openssl genrsa -out server.key 2048

# Create certificate signing request (CSR)
openssl req -new -key server.key -out server.csr -config san.conf

Create a file named san.conf with this structure:


[req]
default_bits       = 2048
prompt             = no
default_md         = sha256
distinguished_name = req_distinguished_name
req_extensions     = req_ext

[req_distinguished_name]
C  = US
ST = California
L  = San Francisco
O  = My Company
OU = IT Department
CN = primary.example.com

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = primary.example.com
DNS.2 = secondary.example.com
DNS.3 = *.dev.example.com
DNS.4 = test.example.com

Execute these commands to create your certificate:


# Generate the certificate
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -extensions req_ext -extfile san.conf

# Verify the SAN entries
openssl x509 -in server.crt -text -noout | grep -A 1 "Subject Alternative Name"

Configure your Apache virtual hosts to use this certificate:


<VirtualHost *:443>
    ServerName primary.example.com
    SSLEngine on
    SSLCertificateFile /path/to/server.crt
    SSLCertificateKeyFile /path/to/server.key
    # Other configuration...
</VirtualHost>

<VirtualHost *:443>
    ServerName secondary.example.com
    SSLEngine on
    SSLCertificateFile /path/to/server.crt
    SSLCertificateKeyFile /path/to/server.key
    # Other configuration...
</VirtualHost>
  • Modern browsers require certificates with SAN extensions
  • Wildcards (*.example.com) only cover one level of subdomains
  • For production, consider Let's Encrypt with SAN support
  • Always verify your certificate chain with: openssl verify -CAfile server.crt server.crt