Search code examples
dockernginxdocker-compose

File copied in dockerfile: Not found if in specific location


I have this dockerfile:

FROM nginx

COPY .docker/certificates/fullchain.pem /etc/letsencrypt/live/mydomain.com/fullchain.pem
COPY .docker/certificates/privkey.pem /etc/letsencrypt/live/mydomain.com/privkey.pem
COPY .docker/config/options-ssl-nginx.conf /etc/nginx/options-ssl-nginx.conf
COPY .docker/config/ssl-dhparams.pem /etc/nginx/ssl-dhparams.pem
COPY .docker/config/nginx.conf /etc/nginx/conf.d/default.conf

RUN chmod +r /etc/letsencrypt/live/mydomain.com/fullchain.pem

I have this in my nginx configuration:

server {
    listen 443 ssl default_server;
    server_name _;

    # Why can't this file be found?
    ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
    # ssl_certificate /etc/nginx/fullchain.pem;
    # ssl_certificate_key /etc/nginx/privkey.pem;
    include /etc/nginx/options-ssl-nginx.conf;
    ssl_dhparam /etc/nginx/ssl-dhparams.pem;

    ...
}

Nginx crashes with:

[emerg] 7#7: cannot load certificate "/etc/letsencrypt/live/mydomain.com/fullchain.pem": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/letsencrypt/live/mydomain.com/fullchain.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)

However, if I change the location of fullchain.pem and privkey.pem to, for example, /etc/nginx/fullchaim.pem and /etc/nginx/privkey.pem and update the nginx configuration, it does find the files and works as expected.

Here's the service definition in docker-compose.yml:

  nginx-server:
    container_name: "nginx-server"
    build:
      context: ../../
      dockerfile: .docker/dockerfiles/NginxDockerfile
    restart: on-failure
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - static-content:/home/docker/code/static
      - letsencrypt-data:/etc/letsencrypt
      - certbot-data:/var/www/certbot
    depends_on:
      - api
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    networks:
      - api-network
      - main

# Commented out to verify that the files aren't being deleted by certbot
#  certbot:
#    image: certbot/certbot
#    container_name: "certbot"
#    depends_on:
#      - nginx-server
#    restart: unless-stopped
#    volumes:
#      - letsencrypt-data:/etc/letsencrypt
#      - certbot-data:/var/www/certbot
#    entrypoint: "/bin/sh -c 'sleep 30s && trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

The intention is to use fullchain.pem as an initial certificate until one can be requested from let's encrypt. Note that, at this point, there is no certbot service, and the /etc/letsencrypt/live/mydomain.com directory is not referenced anywhere else at all (only in NginxDockerfile and nginx.conf), so it shouldn't be an issue of another service deleting the files. Rebuilding with --no-cache does not help.

Why can't nginx find the files in this specific location, but can find them if copied to a different location?

EDIT: As suggested, I ended up using a host volume instead. This didn't work when the host volume was located inside the repository (root_of_context/path/to/gitignored/directory/letsencrypt:/etc/letsencrypt, but did work with /etc/letsencrypt:/etc/letsencrypt, which I personally find ugly, but oh well.

EDIT 2: Looking back, this was probably just a problem with my .dockeringore including the repository path. Using a relative path vs. an absolute path should not matter to Docker.


Solution

  • Volumes are mounted on run, so after your container is built.
    Since you mounted letsencrypt-data on /etc/letsencrypt, Nginx is going to look for your files into letsencrypt-data.
    I don't know the purpose of this mount but I guess your container would succeed in running if you removed - letsencrypt-data:/etc/letsencrypt from volumes.