How to define fall-back certificate in Nginx if the primary one does not exist?

I have run into this same issue. I am deploying a docker cluster to production for which I want auto-generated SSL certificates. When SSL certs are in place, I want to force all traffic to redirect to https. It's not super glamorous, but this is the solution I came up with.

My nginx server has 2 config files: app.conf and tlsapp.conf


server {
    listen 80;
    location /.well-known/acme-challenge/ {
        allow all;
        root /var/www/public;


server {
    listen 80;
    location / {
        return 301$request_uri;

server {
    listen 443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    include /etc/nginx/opt/options-ssl-nginx.conf;
    ssl_dhparam /etc/nginx/opt/ssl-dhparams.pem;
    root /var/www/public;
    index index.php;
    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

I then deploy my nginx container from a custom image.


FROM nginx:alpine

COPY docker-config/nginx/conf.d/app.conf /etc/nginx/conf.d/app.conf
COPY docker-config/nginx/conf.d/tlsapp.conf /etc/nginx/conf.d/tlsapp.bkp
COPY docker-config/nginx/opt/ /etc/nginx/opt/
COPY docker-config/nginx/ /

RUN chmod 775 /

CMD ["/"]
CMD ["nginx", "-g", "daemon off;"]

Lastly, my custom nginx image has a custom entrypoint in it. Basically all this entrypoint does is check to see if the ssl certificates have been created yet. If they have, it enables the tlsapp config and disables the config that was only in place to bootstrap in the certificates with certbot.

#!/usr/bin/env sh

set -e

if [ -d "/etc/letsencrypt/live" ]; then
    mv /etc/nginx/conf.d/app.conf /etc/nginx/conf.d/app.bkp
    mv /etc/nginx/conf.d/tlsapp.bkp /etc/nginx/conf.d/tlsapp.conf

exec "[email protected]"

This set up allows my nginx container to start in a new production environment when ssl certs haven't been generated. It provides certbot just enough access to generate the certificates into a shared persistent volume. Then all I have to do is redeploy the nginx container and it will start up, see the certificates, and enable my site's actual config that forces all traffic through https.

I don't love this setup cause it requires an awkward redeploy for a new production env and can be problematic if your set up is more complex than one app against one nginx server, but it works.