Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 47 additions & 16 deletions base/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
FROM alpine:3.23
# Build stage: the Docker Hardened "-dev" variant ships a shell + apk, which we
# need to create the skpr user, lay down our config and prepare the writable
# runtime directories. The results are copied into the minimal (shell-less)
# runtime image below.
FROM dhi.io/nginx:1.30-alpine3.23-dev AS build

USER root

# Create the skpr user (uid 1000) used for non-root, read-only execution.
RUN adduser -D -u 1000 skpr
RUN apk --update --no-cache add util-linux ca-certificates nginx nginx-mod-http-headers-more

# CA certificates for TLS to upstreams (parity with the previous image).
RUN apk --update --no-cache add ca-certificates

COPY --chown=skpr:skpr etc /etc

# We need to create and chown these directory for
# readonly and non-root execution.
RUN mkdir -p /run/nginx /var/tmp/nginx
RUN ln -sf /dev/stderr /var/log/nginx/error.log
RUN chown -R skpr:skpr /var/lib/nginx \
/var/log/nginx \
/var/tmp/nginx \
/var/lib/nginx/tmp \
/var/lib/nginx/logs \
/usr/lib/nginx/modules \
/run/nginx

# Declaring these here means they inherit the "chown"
# directive from above.
# Create and chown the directories nginx writes to at runtime so the image can
# run non-root against a read-only root filesystem. Paths match the nginx.conf
# pid / *_temp_path directives.
RUN mkdir -p /run/nginx /var/tmp/nginx /var/lib/nginx/tmp \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
&& chown -R skpr:skpr /run/nginx \
/var/tmp/nginx \
/var/lib/nginx \
/var/log/nginx \
/etc/nginx

# Runtime stage: minimal Docker Hardened Image, no shell or package manager.
# Tag floats nginx 1.30.x patches + alpine 3.23 rebuilds (stable stream); switch
# to 1.31-alpine3.23 for the mainline stream. Keep both stages on the same tag.
FROM dhi.io/nginx:1.30-alpine3.23

# Carry over the skpr user so nginx runs as uid 1000 and downstream images can
# COPY --chown=skpr.
COPY --from=build /etc/passwd /etc/group /etc/

# CA certificates for TLS to upstreams.
COPY --from=build /etc/ssl/certs /etc/ssl/certs

# Config and the pre-chowned writable directories.
COPY --from=build --chown=1000:1000 /etc/nginx /etc/nginx
COPY --from=build --chown=1000:1000 /run/nginx /run/nginx
COPY --from=build --chown=1000:1000 /var/tmp/nginx /var/tmp/nginx
COPY --from=build --chown=1000:1000 /var/lib/nginx /var/lib/nginx
COPY --from=build --chown=1000:1000 /var/log/nginx /var/log/nginx

# Declaring these here means they inherit the "chown" directive from above.
VOLUME /run/nginx
VOLUME /var/tmp/nginx
VOLUME /var/lib/nginx/tmp
Expand All @@ -28,4 +55,8 @@ STOPSIGNAL SIGTERM

USER skpr

# The DHI runtime image sets ENTRYPOINT ["nginx"] and CMD ["-g", "daemon off;"].
# Reset both so our single "nginx" invocation runs with "daemon off;" from
# nginx.conf, matching the previous image and avoiding a duplicate directive.
ENTRYPOINT []
CMD ["nginx"]
4 changes: 3 additions & 1 deletion base/etc/nginx/conf.d/header/server.conf
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
more_clear_headers Server;
# The Server header cannot be fully removed with stock nginx; that previously
# relied on the headers-more module (more_clear_headers Server). "server_tokens
# off" (set in nginx.conf) hides the version, leaving only "Server: nginx".
12 changes: 12 additions & 0 deletions base/etc/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ daemon off;

worker_processes 1;

# Written to a skpr-owned directory so nginx can run non-root with a read-only
# root filesystem (the base image's default pid path is not writable by skpr).
pid /run/nginx/nginx.pid;

include /etc/nginx/modules/*.conf;

events {
Expand All @@ -16,6 +20,14 @@ http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

# Temporary paths in a skpr-owned directory so nginx can run non-root with a
# read-only root filesystem (the base image's defaults are not writable by skpr).
client_body_temp_path /var/lib/nginx/tmp/client_body;
proxy_temp_path /var/lib/nginx/tmp/proxy;
fastcgi_temp_path /var/lib/nginx/tmp/fastcgi;
uwsgi_temp_path /var/lib/nginx/tmp/uwsgi;
scgi_temp_path /var/lib/nginx/tmp/scgi;

server_tokens off;

keepalive_timeout 65;
Expand Down
6 changes: 4 additions & 2 deletions drupal/dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
FROM from_image

RUN rm -f /etc/nginx/conf.d/header/x_drupal_cache.conf
RUN rm -f /etc/nginx/conf.d/header/x_drupal_dynamic_cache.conf
# Leave the Drupal cache headers visible for dev images. These empty overrides
# replace the production fastcgi_hide_header directives (shell-free so they work
# on the no-shell hardened base image).
COPY --chown=skpr:skpr etc /etc
2 changes: 2 additions & 0 deletions drupal/dev/etc/nginx/conf.d/header/x_drupal_cache.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Intentionally empty for dev images: the X-Drupal-Cache header is left visible
# (production hides it via fastcgi_hide_header). Overrides the base file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Intentionally empty for dev images: the X-Drupal-Dynamic-Cache header is left
# visible (production hides it via fastcgi_hide_header). Overrides the base file.
2 changes: 1 addition & 1 deletion drupal/etc/nginx/conf.d/header/x_drupal_cache.conf
Original file line number Diff line number Diff line change
@@ -1 +1 @@
more_clear_headers X-Drupal-Cache;
fastcgi_hide_header X-Drupal-Cache;
2 changes: 1 addition & 1 deletion drupal/etc/nginx/conf.d/header/x_drupal_dynamic_cache.conf
Original file line number Diff line number Diff line change
@@ -1 +1 @@
more_clear_headers X-Drupal-Dynamic-Cache;
fastcgi_hide_header X-Drupal-Dynamic-Cache;
2 changes: 1 addition & 1 deletion drupal/etc/nginx/conf.d/header/x_generator.conf
Original file line number Diff line number Diff line change
@@ -1 +1 @@
more_clear_headers X-Generator;
fastcgi_hide_header X-Generator;
6 changes: 3 additions & 3 deletions php-fpm/dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM from_image

# Allow errors to be displayed for non production PHP images. The dev copy of
# 10-error-page.conf disables the error_page 500 interception (shell-free so it
# works on the no-shell hardened base image).
COPY --chown=skpr:skpr etc /etc

# Allow errors to be displayed for non production PHP images.
RUN sed -i '/error_page 500/s/^/#/' /etc/nginx/conf.d/location/10-error-page.conf
15 changes: 15 additions & 0 deletions php-fpm/dev/etc/nginx/conf.d/location/10-error-page.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error_page 400 /error-pages/400.html;
#error_page 403 /error-pages/403.html;
#error_page 404 /error-pages/404.html;
error_page 405 /error-pages/405.html;
error_page 414 /error-pages/414.html;
error_page 416 /error-pages/416.html;
error_page 418 /error-pages/418.html;
# error_page 500 is intentionally disabled for dev images so PHP errors are
# displayed instead of the static 500 page. Keep the rest in sync with
# base/etc/nginx/conf.d/location/10-error-page.conf.
#error_page 500 /error-pages/500.html;
error_page 501 /error-pages/501.html;
error_page 502 /error-pages/502.html;
error_page 503 /error-pages/503.html;
error_page 504 /error-pages/504.html;
Loading