Secure Storage Locations for SSL Certificates and Private Keys on Ubuntu Servers: Best Practices for Nginx


2 views

When working with SSL/TLS on Ubuntu servers, it's crucial to distinguish between different file types:

# Example of common SSL-related files:
- example.com.key       # Private key (MUST be kept secure)
- example.com.crt       # Public certificate
- example.com.pem       # Often contains both cert and private key
- example.com.csr       # Certificate signing request
- example.com.bundle.crt # Certificate chain

Ubuntu follows the Filesystem Hierarchy Standard (FHS) with specific directories for SSL materials:

/etc/ssl/
├── certs/       # For public certificate files (.crt, .pem)
│   └── ca-certificates.crt  # System-wide CA certs
├── private/     # For private keys (.key)
│   └── (protected directory)
└── openssl.cnf  # OpenSSL configuration

Proper file permissions are critical for security:

# Set permissions for private key (readable only by owner)
sudo chmod 600 /etc/ssl/private/example.com.key
sudo chown root:root /etc/ssl/private/example.com.key

# Certificate files can have more relaxed permissions
sudo chmod 644 /etc/ssl/certs/example.com.crt

Here's how to properly reference these files in Nginx:

server {
    listen 443 ssl;
    server_name example.com;
    
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # Additional security settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
}

The /etc/ssl/private directory is typically:

  • Owned by root:root
  • Has 700 permissions (drwx------)
  • Access restricted to privileged users

Public certificates in /etc/ssl/certs are intentionally world-readable because:

  • They contain no sensitive information
  • They need to be accessible by services running as non-root users
  • They're meant to be distributed to clients

For containerized environments or specific security requirements:

# Option 1: Dedicated SSL directory for service
/etc/nginx/ssl/
├── cert.pem
└── key.pem

# Option 2: Using apparmor for additional protection
/etc/apparmor.d/usr.sbin.nginx:
  /etc/ssl/private/* r,
  1. Verify private keys are never stored with certificates
  2. Ensure private keys have 600 permissions
  3. Use separate certificates for different services
  4. Regularly audit file permissions
  5. Consider using encrypted partitions for /etc/ssl/private

When configuring SSL/TLS on Ubuntu servers, the fundamental principle is to maintain strict separation between public certificates and private keys. The certificate (.crt) contains public information and can be safely distributed, while the private key (.key) must remain absolutely confidential.

Ubuntu's FHS-compliant default locations:

/etc/ssl/certs/      # For certificate files (755 permissions)
/etc/ssl/private/    # For private keys (700 permissions)

Example deployment for Nginx:

# Certificate (public)
sudo cp example.com.crt /etc/ssl/certs/
sudo chmod 644 /etc/ssl/certs/example.com.crt

# Private key (secured)
sudo cp example.com.key /etc/ssl/private/
sudo chmod 600 /etc/ssl/private/example.com.key
sudo chown root:root /etc/ssl/private/example.com.key

SSL certificates contain:

  • Public key
  • Domain information
  • Issuer details
  • Validity period

Since these are designed to be public, /etc/ssl/certs/ with 755 permissions is appropriate. The private key in /etc/ssl/private/ has stricter 700 permissions by default in Ubuntu.

For high-security environments:

# Set immutable flag on private key
sudo chattr +i /etc/ssl/private/example.com.key

# Configure AppArmor for Nginx
echo "/etc/ssl/private/* r," >> /etc/apparmor.d/usr.sbin.nginx
sudo systemctl reload apparmor

Proper reference in your Nginx sites:

server {
    listen 443 ssl;
    server_name example.com;
    
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # Rest of your configuration...
}

Regularly check permissions and access:

# Verify permissions
ls -l /etc/ssl/private/ /etc/ssl/certs/

# Monitor access attempts
sudo auditctl -w /etc/ssl/private/ -p rwxa -k ssl_private_access

Remember to test your configuration after changes:

sudo nginx -t
sudo systemctl reload nginx