This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This repository builds and publishes multi-platform Docker images for OpenResty (nginx + LuaJIT) with custom dependencies including OpenSSL 3.4.3 (FIPS-enabled), PCRE2 10.44, and the GeoIP2 module.
Docker Hub: intimatemerger/openresty
Platforms: linux/amd64, linux/arm64
# Build for specific platform (recommended)
# Use linux/arm64 for Apple Silicon, linux/amd64 for Intel/x86_64
docker build --platform=linux/arm64 -t dev-resty:local .
# Build for current platform without specifying (not recommended)
docker build -t dev-resty:local .
# Alternative: Use full repository name
docker build --platform=linux/arm64 -t intimatemerger/openresty:local .
# Build for multiple platforms (requires buildx)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t dev-resty:local .
# Test the built image
docker run -d -p 80:80 dev-resty:local# Run with custom nginx.conf
docker run -d -p 80:80 \
-v $(pwd)/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro \
dev-resty:localThe Dockerfile performs a complex multi-stage build in a single RUN command to minimize layer size:
- Dependency Installation: Installs Alpine build dependencies and runtime libraries
- OpenSSL Build: Downloads, patches (for OpenResty compatibility), and compiles OpenSSL 3.4.3 with FIPS support
- PCRE2 Build: Compiles PCRE2 10.44 with JIT support
- GeoIP2 Module: Downloads ngx_http_geoip2_module
- OpenResty Build: Compiles OpenResty with custom configure options linking to the built OpenSSL and PCRE2
- Binary Stripping: Removes debug symbols and unnecessary files to reduce image size
- Cleanup: Removes build dependencies and temporary files
RESTY_VERSION: OpenResty version (currently 1.27.1.2)RESTY_OPENSSL_VERSION: OpenSSL version (currently 3.4.3)RESTY_PCRE_VERSION: PCRE2 version (currently 10.44)RESTY_GEOIP2_VERSION: GeoIP2 module version (currently 3.4)
The build enables the following nginx modules:
- HTTP/2 and HTTP/3 support (
--with-http_v2_module,--with-http_v3_module) - Dynamic image filter module (
--with-http_image_filter_module=dynamic) - Auth request, real IP, gzip static, SSL modules
- GeoIP2 for geographical location detection
LuaJIT is configured with LUAJIT_NUMMODE=2 (number mode) and Lua 5.2 compatibility.
The repository uses two separate workflows for improved security and clarity:
Triggers:
- Push to
master/mainbranch → Build & push to Docker Hub - Tags matching
*.*.*.*-*(e.g.,1.27.1.2-0) → Build & push with version tags - Manual dispatch → Build & push
Generated Docker Tags:
latest- Latest build from main/master1.27.1- Three-part version (from git tag1.27.1.2-0)1.27- Two-part version
Required Secrets:
DOCKERHUB_USERNAME(variable) - Docker Hub usernameDOCKERHUB_PUSH_TOKEN(secret) - Docker Hub access token with Read & Write permissions
Triggers:
- Pull requests to
master/mainbranch
Purpose:
- Runs Trivy configuration scanner on Dockerfile and workflow files
- Uploads results to GitHub Security tab
- No Docker Hub access or secrets required - provides fast security feedback in isolation
The build-and-push workflow uses a three-stage process for efficient multi-platform builds:
-
build (matrix job):
- Runs on native runners:
ubuntu-latest(amd64),ubuntu-latest-arm(arm64) - Each platform builds independently in parallel
- Uses digest-based push (
push-by-digest=true) for reliable multi-arch images - Platform-specific cache scopes for optimal cache utilization
- Runs on native runners:
-
merge:
- Downloads all platform digests
- Creates manifest list using
docker buildx imagetools create - Pushes unified multi-platform image with appropriate tags
- Runs Docker Scout CVE scan on final image
- Workflow Separation: Build and security-scan workflows are completely isolated
- PRs never trigger workflows that access Docker Hub secrets
- Reduces attack surface for public repository
- SBOM Generation: Enabled (
sbom: true) for all builds to track dependencies - Provenance: Disabled (
provenance: false) for maximum compatibility with cloud services (ECR, ACR, GCR) - Vulnerability Scanning:
- Docker Scout (post-merge): Scans final multi-platform image for critical/high CVEs
- Trivy (PRs only): Scans Dockerfile and configuration, uploads to GitHub Security
- Native Runners: No QEMU emulation—each platform builds on native architecture for maximum speed
- Parallel Execution: Matrix strategy runs amd64 and arm64 builds simultaneously
- Platform-Specific Caching: Each architecture maintains separate GitHub Actions cache (
scope=${{ matrix.arch }}) - Digest-Based Merging: Ensures atomic multi-platform manifest creation
- Estimated Build Times:
- First build (cold cache): 15-30 minutes per platform (parallel)
- Subsequent builds (warm cache): 5-10 minutes per platform
- Total wall time: Similar to slowest platform (due to parallelization)
When updating OpenResty or dependencies:
-
Update version variables in
Dockerfile:RESTY_VERSION- OpenResty versionRESTY_OPENSSL_VERSION- OpenSSL versionRESTY_OPENSSL_PATCH_VERSION- OpenSSL patch version for OpenResty compatibilityRESTY_PCRE_VERSIONandRESTY_PCRE_SHA256- PCRE2 version and checksumRESTY_GEOIP2_VERSION- GeoIP2 module version
-
Update
README.mdif version tags change -
Create a feature branch (e.g.,
feature-1.27.1.2) and push -
After merge to master, tag with version number and revision:
# Initial release: use -0 git tag 1.27.1.2-0 git push origin 1.27.1.2-0 # Rebuild with same OpenResty version (e.g., OpenSSL update): increment revision git tag 1.27.1.2-1 git push origin 1.27.1.2-1
Git Tags (with revision number):
- Format:
1.27.1.2-0,1.27.1.2-1, etc. - Always include revision number for consistency
- Maintains complete build history
Docker Tags (generated automatically):
1.27.1- Three-part version (tracks latest patch within 1.27.1.x)1.27- Two-part version (tracks latest minor)latest- Latest build from master branch
Example: Pushing git tag 1.27.1.2-0 generates Docker tags:
intimatemerger/openresty:1.27.1intimatemerger/openresty:1.27intimatemerger/openresty:latest
Note: Four-part version tags (e.g., 1.27.1.2) are not published to Docker Hub. Users should use 1.27.1 to get the latest patch version within the 1.27.1.x series.
# Verify the container starts
docker run --rm dev-resty:local -t
# Check OpenResty version
docker run --rm dev-resty:local -v
# Test HTTP access
docker run -it --rm -p 8080:80 --name dev-resty dev-resty:local
curl http://localhost:8080- The entire build happens in a single
RUNcommand to minimize Docker layer size - OpenSSL requires OpenResty-specific patches for session callback yielding support
- Binary stripping is performed when
RESTY_STRIP_BINARIES="1"to reduce image size - Logs are symlinked to stdout/stderr for Docker-native logging
- Uses
SIGQUITinstead ofSIGTERMfor graceful shutdown