SSL for Nginx in Docker: How to Set Up PFX Certificates Correctly
A practical guide for self-hosters: How to convert PFX certificates to PEM and securely set up SSL/TLS for your Nginx container in Docker.
Table of Contents
Introduction
Securing web applications with SSL/TLS is often essential. An encrypted connection via HTTPS not only protects your usersβ data but also builds trust. While services like Letβs Encrypt automate the process, some certificate authorities or internal networks provide certificates in the PFX format (.pfx or .p12).
This format bundles the certificate and private key into a single, password-protected file, which is convenient for Windows servers. However, Nginx, the most popular web server in the Docker ecosystem, prefers the PEM format with separate files.
This article will show you, step-by-step, how to prepare and configure a PFX certificate using OpenSSL for use with an Nginx container.
Glossary: Key SSL Terms
| Term | Description |
|---|---|
| SSL/TLS | Secure Sockets Layer / Transport Layer Security. Protocols for encrypting data transmission over the internet. TLS is the modern successor to SSL. |
| PFX/PKCS#12 | A binary file format that bundles an SSL certificate, intermediate certificates, and the private key into a single, password-protected file. Extensions are often .pfx or .p12. |
| PEM | Privacy Enhanced Mail. A text-based file format that encodes cryptographic information (like certificates or keys) in Base64. Nginx and Apache prefer this format. |
| OpenSSL | A powerful command-line tool for working with SSL/TLS certificates. We will use it for the conversion. |
| Private Key | The private key (.key or .pem). It must be kept secret and is used by the server to decrypt data sent to it. |
| Certificate | The public certificate (.crt or .pem). It is sent from the server to the client (browser) to prove its identity. |
| CA Chain | Certificate Authority Chain. A chain of intermediate certificates that proves the trustworthiness of your certificate up to a root CA. Essential for avoiding browser warnings. |
| Nginx | A high-performance, resource-efficient web server and reverse proxy, commonly used in Docker setups. |
| Docker Compose | A tool for defining and running multi-container Docker applications using a single YAML file. |
Step 1: Prepare the PFX Certificate for Nginx
The conversion of a PFX file can be done entirely with the openssl command-line tool, which is pre-installed on most Linux systems. Execute the following commands in your terminal from the root directory of your Docker project.
1. Create a Directory for SSL Certificates
First, letβs create a clean directory structure. An ssl subdirectory inside your Nginx configuration folder is a good and common place for your certificate files.
mkdir -p nginx/ssl
cd nginx/ssl
2. Copy the PFX File
Copy your PFX file (e.g., certificate.pfx) into this newly created nginx/ssl directory.
3. Extract the Private Key
This command extracts the private key from the PFX file. You will be prompted to enter the password for the PFX file. The result is a PEM file that is still password-protected.
openssl pkcs12 -in certificate.pfx -nocerts -out private-key-encrypted.pem
# Enter your PFX password
4. Extract the Certificate
Next, the public certificate is extracted from the PFX file.
openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.pem
5. Extract the CA Certificate Chain (if present)
Modern certificates often include the chain of intermediate certificates. These should also be extracted to avoid trust issues in browsers.
openssl pkcs12 -in certificate.pfx -cacerts -nokeys -out ca-chain.pem
6. Remove Password Protection from the Private Key
The extracted private key is still protected by a passphrase. To allow Nginx to start automatically without asking for a password, we need to remove this protection.
openssl rsa -in private-key-encrypted.pem -out private-key.pem
7. Clean Up
The encrypted version of the private key is no longer needed and should be removed for security reasons.
rm private-key-encrypted.pem
8. Set Permissions
Protecting the private key is crucial. Ensure that only the owner can read the file. Public certificates can be read by everyone.
chmod 600 private-key.pem
chmod 644 certificate.pem ca-chain.pem
9. Create the Full Certificate Chain (Recommended)
For optimal compatibility with all browsers and easier configuration in Nginx, it is advisable to combine your certificate and the CA chain into a single file. Nginx can then use this fullchain.pem directly.
cat certificate.pem ca-chain.pem > fullchain.pem
After these steps, your nginx/ssl directory should contain the two essential files: private-key.pem and fullchain.pem. We can now adjust the Nginx configuration.
cd ../.. # Back to the root directory
Step 2: Adjust the Nginx Configuration for SSL
Now we need to tell Nginx where to find the certificate files and that the server should listen on the HTTPS port 443.
Create a configuration file, e.g., nginx/nginx.conf. A typical configuration that redirects HTTP requests to HTTPS and uses SSL looks like this:
cd nginx
touch nginx.conf
server {
listen 80;
server_name your-domain.com www.your-domain.com;
# Redirect all HTTP requests to HTTPS with a 301 status code (Permanent)
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name your-domain.com www.your-domain.com;
# Paths to the SSL certificate files INSIDE THE CONTAINER
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/private-key.pem;
# Additional SSL optimizations (Best Practices)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# Add HSTS Header (Strict Transport Security)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
location / {
# A reverse proxy to another application can be placed here
proxy_pass http://my-container:8080;
# Or serve static content
# root /usr/share/nginx/html;
# index index.html index.htm;
}
}
Important Notes on the Configuration:
- Replace
your-domain.comwith your actual domain. - The
ssl_certificateandssl_certificate_keypaths point to the location inside the Docker container, which we will provide via a volume mount in the next step.
Step 3: Docker Compose Setup for Nginx with SSL
To start the Nginx container and use our configuration and certificates, Docker Compose is ideal. Just like in my guides on Paperless-NGX on Synology or setting up a home server, we will use a compose.yaml file in the projectβs root directory.
touch compose.yaml
services:
nginx:
image: nginx:latest
container_name: nginx_webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
# Nginx configuration file
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
# SSL certificates (mount as read-only)
- ./nginx/ssl:/etc/nginx/ssl:ro
# Example for static content
# - ./html:/usr/share/nginx/html:ro
networks:
- web_network
networks:
web_network:
external: true
Explanation of the Volumes:
./nginx/nginx.conf:/etc/nginx/nginx.conf:ro: Binds our local configuration file into the container. The:ro(read-only) suffix is a good security practice, as the container should not be able to modify its configuration../nginx/ssl:/etc/nginx/ssl:ro: Makes our prepared SSL certificates available to Nginx inside the container, also in read-only mode.
After saving the compose.yaml file, you can start the Nginx container with a simple command:
docker compose up -d
Your web server is now accessible via https://your-domain.com, and the connection is securely encrypted. You can check the quality of your SSL configuration with tools like the SSL Labs Server Test.
Conclusion
The manual configuration of SSL certificates for Nginx in Docker is quickly accomplished with the right tools and steps. By correctly converting PFX files to the PEM format and maintaining a clean structure for your configuration and certificates, you create a robust and secure setup for your self-hosted services.
FAQs
Why do I need to remove the password protection from the private key?
Nginx and other web servers run as background services. If the private key is password-protected, the server would wait for password input on every start, making automated operation impossible. Security is instead ensured by strict file permissions (chmod 600) on the host system.
What is the difference between fullchain.pem and certificate.pem?
certificate.pem contains only the certificate for your domain. fullchain.pem also includes the chain of intermediate certificates (CA Chain). Using fullchain.pem is highly recommended as it allows browsers to validate the entire chain of trust, preventing 'Certificate Not Trusted' errors.
Can I automate this process?
Yes, the OpenSSL commands shown here can easily be packed into a shell script. If you frequently receive certificates in this format, a script can reduce the process to a single command.
Does this also work with other reverse proxies like Traefik or Caddy?
Yes, the process of converting certificates from PFX to PEM is universal. Traefik and Caddy also require PEM-formatted certificates (key and certificate files). However, the specific configuration of where the certificates are stored and referenced will differ depending on the proxy.
What happens when my certificate expires?
You will need to repeat the process with the new PFX file to update the certificate files (private-key.pem, fullchain.pem). Afterward, restart the Nginx container to load the new certificates. A `docker compose restart nginx` is usually sufficient.