In Docker Compose, the official nginx image serves the folder mounted at /usr/share/nginx/html: the line /some/content:/usr/share/nginx/html:ro under the service’s volumes, read-only because nginx only reads it. In a Compose file, a relative path such as ./content resolves against the file’s own directory.
The docker run command, converted
The static-content command from the image’s Docker Hub page, with the port it publishes in its next example and the tag pinned:
docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d -p 8080:80 nginx:1.31
services:
some-nginx:
image: nginx:1.31
ports:
- "8080:80"
volumes:
- /some/content:/usr/share/nginx/html:ro
Configuration from the environment
The default site is /etc/nginx/conf.d/default.conf; mounting a file at /etc/nginx/nginx.conf replaces the main configuration instead. Since 1.19 the image also reads /etc/nginx/templates/*.template at startup, runs them through envsubst, and writes the result to /etc/nginx/conf.d without the suffix:
services:
web:
image: nginx:1.31
ports:
- "8080:80"
volumes:
- ./content:/usr/share/nginx/html:ro
- ./templates:/etc/nginx/templates:ro
environment:
NGINX_HOST: example.com
NGINX_PORT: "80"
healthcheck:
test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://localhost/"]
interval: 10s
timeout: 3s
retries: 3
# templates/default.conf.template
server {
listen ${NGINX_PORT};
server_name ${NGINX_HOST};
root /usr/share/nginx/html;
add_header X-Host $host;
}
Only variables set in the container’s environment are replaced, so nginx’s own $host stays as it is. NGINX_PORT has to match the container side of ports, here 80. Both the Debian and Alpine variants of 1.31 include curl, so the healthcheck works on either.
Gotchas
- A content folder without
index.htmlanswers/with 403, andcurl -fturns that into an unhealthy container. - After editing a mounted config,
docker compose exec web nginx -tchecks it anddocker compose exec web nginx -s reloadapplies it without dropping connections. Templates are only rendered at startup, so a changed template needsdocker compose restart web. nginx:1.31is the mainline branch andnginx:1.30the stable one;nginx:latestfollows mainline.- As a reverse proxy, nginx reaches other services by name:
proxy_pass http://app:3000;in a template, withapplisted underdepends_on.