Sign inSign up

australproject/nginx

By australproject

•Updated 13 days ago

Image
0

3.4K

australproject/nginx repository overview

⁠Austral Docker Nginx 1.20

License Docker Image Version (tag latest semver) Docker Automated build Docker Cloud Build Status Docker Image Size (latest semver)

View repository for the base image Alpine 3.15 : Docker Hub⁠ or Gitub⁠

⁠Versions

  • Alpine: 3.15
  • Nginx: 1.20
  • Brotli module: installed when available (enabled automatically)

⁠Modes

MODEUse
php (default)Static files + PHP-FPM (FASTCGI_PASS), for Symfony, WordPress, ...
staticStatic site / SPA: unknown routes return index.html

With MODE=php, PHP_MODE defines which PHP files can be executed:

PHP_MODEBehaviour
classic (default)Any existing .php file (WordPress, legacy sites). Script execution is always blocked in uploads/ directories
frontOnly the front controller (index.php) and the scripts you allow (see below). Every other .php URL returns 404

Allowed scripts (PHP_MODE=front): some projects have extra scripts reachable by URL, for example a yipikai.php that switches the site to dev mode. List them explicitly:

environment:
  - PHP_MODE=front
  - PHP_ALLOWED_SCRIPTS=yipikai.php            # comma separated, file names at the root of the public directory
  - PHP_ALLOWED_SCRIPTS_IPS=203.0.113.10,198.51.100.0/24   # optional: only these IPs can reach them

The front controller itself (PHP_FRONT_SCRIPT, default index.php) is never reachable directly, only through the application routes. With PHP_ALLOWED_SCRIPTS_IPS, other visitors get a 403 (the real client IP is used, see REAL_IP_FROM).

Previous settings still work: ALONE=true or FASTCGI_PASS=alone select MODE=static, FASTCGI_PASS_VALUE is used as FASTCGI_PASS, and a mounted /etc/nginx/sites-available/website.custom still replaces the site configuration.

⁠Running as any user (non-root)

The image runs as root or as any UID/GID, for example with Docker Swarm:

services:
  nginx:
    image: australproject/nginx:1.20
    user: "3001:3001"
    volumes:
      - /home/owner/websites/example.com:/home/www-data/website:ro

The configuration is rendered at start-up into /tmp/nginx (writable by any user). Use the same UID/GID as the PHP service so both read the same files. As root, workers run as www-data (legacy behaviour).

Listening on port 80 as non-root works on current Docker versions. If it fails with Permission denied, set LISTEN_PORT=8080 and update the Traefik port label.

Quick test:

docker run --rm -u 3001:3001 -e MODE=static -p 8080:80 australproject/nginx:1.20
curl -i http://127.0.0.1:8080/healthz

⁠Environment variables

VariableDefaultDescription
MODEphpphp or static
PHP_MODEclassicclassic or front
PHP_FRONT_SCRIPTindex.phpFront controller (front mode: internal only; also used as fallback in classic mode)
PHP_ALLOWED_SCRIPTSemptyfront mode: other scripts reachable by URL (comma separated)
PHP_ALLOWED_SCRIPTS_IPSemptyfront mode: IPs/CIDRs allowed to reach those scripts (empty = everyone)
PUBLIC_DIRpublicPublic directory, relative to /home/www-data/website
LISTEN_PORT80Listening port
FASTCGI_PASSphp:9900PHP-FPM address (host or host:port). Resolved at request time: nginx starts even if PHP is not up yet
FASTCGI_READ_TIMEOUT300sPHP timeout (keep it equal to FPM_REQUEST_TERMINATE_TIMEOUT)
HTTPSoffValue of the PHP HTTPS variable: on, off or auto (from X-Forwarded-Proto)
APP_DEBUGfalsePassed to PHP as APP_DEBUG FastCGI parameter
APP_ENVprodPassed to PHP as APP_ENV FastCGI parameter
CLIENT_MAX_BODY_SIZE64MMaximum upload size (keep it aligned with PHP_POST_MAX_SIZE)
CACHE_STATIC_MAX_AGE3600Browser cache of static files, in seconds
CORS_ALLOW_ORIGIN*Access-Control-Allow-Origin of static files. Empty to disable
X_FRAME_OPTIONSDENYX-Frame-Options header. Empty to disable
REAL_IP_FROM10.0.0.0/8,172.16.0.0/12,192.168.0.0/16Trusted proxies (comma separated) for the real client IP. Empty to disable
WORKER_PROCESSESautoNginx workers
WORKER_RLIMIT_NOFILEhard limit of the container (max 16384)Open files per worker
WORKER_CONNECTIONShalf of WORKER_RLIMIT_NOFILE (max 4096)Connections per worker
ERROR_LOG_LEVELwarnNginx error log level
ACCESS_LOG_ENABLED10 disables the access log
BROTLIautoauto, on or off

⁠Cache and headers

  • Static files whose name contains a hash (app.3f2a9c1b.js, app-3f2a9c1b.css): public, max-age=31536000, immutable
  • Other static files: public, max-age=CACHE_STATIC_MAX_AGE
  • HTML files: no-cache (always revalidated, so a new deployment is seen immediately)
  • Static files served directly also carry the header Austral: Direct-Link
  • Security headers on every response: X-Frame-Options, X-Content-Type-Options: nosniff, Referrer-Policy
  • Hidden files (.git, .env, .htaccess, ...) return 404, except /.well-known/
  • A missing static file is handled by the application (MODE=php), so dynamic robots.txt or generated images keep working

Gzip is always enabled, and Brotli when the module is installed.

⁠Overriding the configuration

Mount a directory on /overrides (read-only is fine):

Path in /overridesEffect
website.confReplaces the whole site configuration (copied as is, no variable substitution)
nginx.confReplaces the whole nginx.conf
server.d/*.confAdded inside the server block (extra location, redirects, ...)
conf.d/*.confAdded at http level (extra maps, limits, other servers, ...)
# /overrides/server.d/redirect.conf
location = /old-page { return 301 /new-page; }

⁠Error pages

Errors generated by nginx (403, 404 on static sites, 413 upload too large, 502/503/504 when PHP is down or too slow...) use styled pages: 400 401 403 404 405 408 413 414 429 500 501 502 503 504. Errors returned by the PHP application itself (the Symfony or WordPress 404/500 pages) are left untouched.

VariableDefaultDescription
ERROR_PAGESonoff restores the default nginx error pages
ERROR_LANGfrLanguage of the default pages: fr or en
INTERCEPT_PHP_ERRORSoffon also replaces the error pages returned by PHP

To use your own pages, mount a directory on /overrides/errors:

File in /overrides/errorsEffect
404.html, 502.html, ...Page used as is for this status code
error.htmlGeneric template for every code that has no own file. Placeholders: ${ERROR_CODE}, ${ERROR_TITLE}, ${ERROR_MESSAGE}, ${ERROR_HOME_LABEL}
anything else (style.css, images, fonts)Served under /__errors/, e.g. <link rel="stylesheet" href="/__errors/style.css">
volumes:
  - ./error-pages:/overrides/errors:ro

The HTTP status code is kept (a 404 page is still sent with a 404 status). Use absolute paths starting with /__errors/ for your assets.

⁠Health check

GET /healthz returns 200 ok and is not logged. The image healthcheck uses it.

⁠Logs

Access and error logs go to the container output (docker logs). Behind Traefik, the real client IP is read from X-Forwarded-For (REAL_IP_FROM).

⁠Commit Messages

The commit message must follow the Conventional Commits specification⁠. The following types are allowed:

  • update: Update
  • fix: Bug fix
  • feat: New feature
  • docs: Change in the documentation
  • spec: Spec change
  • test: Test-related change
  • perf: Performance optimization

Examples:

update : Something

fix: Fix something

feat: Introduce X

docs: Add docs for X

spec: Z disambiguation

See License⁠

⁠Credits

Created by Matthieu Beurel⁠. Sponsored by Yipikai Studio⁠.

Tag summary

Content type

Image

Digest

sha256:b6f0993f5…

Size

22.2 MB

Last updated

13 days ago

docker pull australproject/nginx:1.28