From dfd7365fac91952a4716d9b2a424dfca7d18dc22 Mon Sep 17 00:00:00 2001 From: Matt Cengia Date: Sun, 26 Apr 2026 09:47:30 +1000 Subject: [PATCH] Don't require separately built nginx container Often when running an nginx container or similar, one might use the upstream container image but override its config by using a volume to bind-mount in a new config file from a local directory. If running `docker compose` targeting a remote host, the bind-mount looks for its source on the remote host, rather than the local, so the sought file doesn't exist. I'd been working around this by building a custom nginx container whose only change was its config. This change instead uses an inline Docker Config object to work around this. I'd tried sourcing the config object from a local file, but this has the same problem as the above, in that it looks for the config source on the remote host. --- .env.example | 2 ++ docker-compose.prod.yml | 34 ++++++++++++++++++---- docker-compose.traefik.yml | 34 ++++++++++++++++++---- nginx/Dockerfile | 6 ---- nginx/default.conf | 23 --------------- nginx/docker-entrypoint-99-set-app-host.sh | 6 ---- 6 files changed, 60 insertions(+), 45 deletions(-) delete mode 100644 nginx/Dockerfile delete mode 100644 nginx/default.conf delete mode 100755 nginx/docker-entrypoint-99-set-app-host.sh diff --git a/.env.example b/.env.example index da74ba4..3bfa6b8 100644 --- a/.env.example +++ b/.env.example @@ -28,6 +28,8 @@ SUPERUSER_USERNAME=root SUPERUSER_PASSWORD=root SUPERUSER_EMAIL=root@localhost APP_PORT=8000 +# TODO Replace 'app' below with the name of the django service in compose file +WEB_APP_HOST=app:8000 CSRF_TRUSTED_ORIGINS=http://localhost:$APP_PORT ALLOWED_HOSTS=* diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 0fca9a6..9e2aefe 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -34,17 +34,41 @@ services: # condition: service_healthy web: - image: mattcen/nginx_django - build: ./nginx - environment: - # Replace 'app' below with the name of the django service above - WEB_APP_HOST: app:8000 + image: ghcr.io/nginx/nginx-unprivileged:alpine + configs: + - source: nginx_conf + target: /etc/nginx/conf.d/default.conf ports: - "$APP_PORT:80" depends_on: - app volumes: - media_files:/media + healthcheck: + test: '[ "$(curl -L -o /dev/null -s -w "%{http_code}\n" http://localhost/.nginx_healthcheck)" = 200 ]' + interval: 10s + timeout: 5s + retries: 5 + +configs: + nginx_conf: + #file: ./nginx.conf + content: | + upstream webapp { server ${WEB_APP_HOST}; } + server { + listen 80; + location / { + proxy_pass http://webapp; + proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for; + proxy_set_header Host $$host; + proxy_redirect off; + } + location /media/ { alias /media/; } + location /.nginx_healthcheck { + return 200 'running'; + default_type application/text; + } + } volumes: db_data: diff --git a/docker-compose.traefik.yml b/docker-compose.traefik.yml index 6a6c03d..d3530d7 100644 --- a/docker-compose.traefik.yml +++ b/docker-compose.traefik.yml @@ -38,15 +38,19 @@ services: - backend web: - image: mattcen/nginx_django - build: ./nginx - environment: - # Replace 'app' below with the name of the django service above - WEB_APP_HOST: app:8000 + image: ghcr.io/nginx/nginx-unprivileged:alpine + configs: + - source: nginx_conf + target: /etc/nginx/conf.d/default.conf depends_on: - app volumes: - media_files:/media + healthcheck: + test: '[ "$(curl -L -o /dev/null -s -w "%{http_code}\n" http://localhost/.nginx_healthcheck)" = 200 ]' + interval: 10s + timeout: 5s + retries: 5 networks: - backend - proxy @@ -59,6 +63,26 @@ services: traefik.http.services.replace_this_name_with_something_else.loadbalancer.server.port: 80 traefik.http.services.replace_this_name_with_something_else.loadbalancer.sticky: "true" +configs: + nginx_conf: + #file: ./nginx.conf + content: | + upstream webapp { server ${WEB_APP_HOST}; } + server { + listen 80; + location / { + proxy_pass http://webapp; + proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for; + proxy_set_header Host $$host; + proxy_redirect off; + } + location /media/ { alias /media/; } + location /.nginx_healthcheck { + return 200 'running'; + default_type application/text; + } + } + volumes: db_data: media_files: diff --git a/nginx/Dockerfile b/nginx/Dockerfile deleted file mode 100644 index 0c05615..0000000 --- a/nginx/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM nginx:1.29.1-bookworm - -COPY default.conf /etc/nginx/conf.d/default.conf -COPY docker-entrypoint-99-set-app-host.sh /docker-entrypoint.d/99-set-app-host.sh - -HEALTHCHECK --interval=10s --timeout=5s --retries=5 CMD bash -c '[[ "$(curl -L -o /dev/null -s -w "%{http_code}\n" http://localhost/.nginx_healthcheck)" == "200" ]]' diff --git a/nginx/default.conf b/nginx/default.conf deleted file mode 100644 index 5aa6aa0..0000000 --- a/nginx/default.conf +++ /dev/null @@ -1,23 +0,0 @@ -upstream webapp { - server replace_this_with_web_app_hostname_and_port; -} - -server { - - listen 80; - - location / { - proxy_pass http://webapp; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_redirect off; - } - - location /media/ { alias /media/; } - - location /.nginx_healthcheck { - return 200 'running'; - default_type application/text; - } - -} diff --git a/nginx/docker-entrypoint-99-set-app-host.sh b/nginx/docker-entrypoint-99-set-app-host.sh deleted file mode 100755 index bfe93f9..0000000 --- a/nginx/docker-entrypoint-99-set-app-host.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -if [ -n "$WEB_APP_HOST" ] -then - sed -i "s/replace_this_with_web_app_hostname_and_port/$WEB_APP_HOST/g" /etc/nginx/conf.d/default.conf -fi