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.

SSL for Nginx in Docker: How to Set Up PFX Certificates Correctly hero image

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

TermDescription
SSL/TLSSecure Sockets Layer / Transport Layer Security. Protocols for encrypting data transmission over the internet. TLS is the modern successor to SSL.
PFX/PKCS#12A 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.
PEMPrivacy Enhanced Mail. A text-based file format that encodes cryptographic information (like certificates or keys) in Base64. Nginx and Apache prefer this format.
OpenSSLA powerful command-line tool for working with SSL/TLS certificates. We will use it for the conversion.
Private KeyThe private key (.key or .pem). It must be kept secret and is used by the server to decrypt data sent to it.
CertificateThe public certificate (.crt or .pem). It is sent from the server to the client (browser) to prove its identity.
CA ChainCertificate Authority Chain. A chain of intermediate certificates that proves the trustworthiness of your certificate up to a root CA. Essential for avoiding browser warnings.
NginxA high-performance, resource-efficient web server and reverse proxy, commonly used in Docker setups.
Docker ComposeA 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

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.com with your actual domain.
  • The ssl_certificate and ssl_certificate_key paths 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.

Share this post:

This website uses cookies. These are necessary for the functionality of the website. You can find more information in the privacy policy