openresty
1.31.1.1-alpineOpenResty with common modules pre-compiled. Multi-arch, SBOM-attested, daily upstream monitoring.
Trust posture
VERIFIABLE TRUST ARTIFACTS
Provenance
- Build commit
ed67d41- Build digest
-
sha256:94fa75d77a3005aa485602e833786ec81aa80e050f26f5c5a97cf0dcaf3444d2 - Index digest
-
sha256:0aa799e563298d23710ad2de4faa5cd8f2f16a9a0a6c3820b4e6c894f9c386e0 - Manifest digest (amd64)
-
sha256:2e16a87392a78a087ccd47cae6212151899c328d3de17655ba61a39d2ca0b19f - Manifest digest (arm64)
-
sha256:236d14d59f0209771ba54e4b5e9f8a5b0beb5a80d19f308332c57533d3d81383 - SBOM attestation
-
34817631β¦ - Trivy last scan
- 2026-07-10 20:41 UTC
- Base image
- Verify
gh attestation verify oci://ghcr.io/oorabona/openresty:1.31.1.1-alpine --owner oorabonaguide β
Security scan results
Trivy Β· last scan 2026-07-10
β Full report via gh api β see Verify Images.
Explore
Build lineagesha256:
Package summary n/a β runtime parsed
Recent changes n/a β runtime parsed
Build history n/a β runtime fetched
Dependency health 1 update available
Dependency Health
1 update available| Dependency | Current | Latest | Type |
|---|---|---|---|
| RESTY_OPENSSL_VERSION | 3.5.6 | 3.5.7 | patch |
Up-to-date dependencies
Documentation
README
OpenResty
High-performance web platform combining Nginx with LuaJIT for dynamic, programmable request handling.
Verify this image
Every build ships a Sigstore-signed SBOM and a full Trivy scan β verify them yourself, no login required:
gh attestation verify oci://ghcr.io/oorabona/openresty:latest --owner oorabona
Full walkthrough (SBOM payload, Trivy findings, multi-arch manifest inspection, upstream dependency tracking) β https://oorabona.github.io/docker-containers/verify-images/
Quick Start
# Pull from GitHub Container Registry
docker pull ghcr.io/oorabona/openresty:latest
# Pull from Docker Hub
docker pull oorabona/openresty:latest
# Run with custom configuration
docker run -d \
--name openresty \
-p 80:80 \
-p 443:443 \
-v ./conf.d:/usr/local/openresty/nginx/conf/conf.d:ro \
-v ./lua:/usr/local/openresty/lualib/app:ro \
ghcr.io/oorabona/openresty:latest
Features
- Nginx + LuaJIT: Full Nginx functionality with embedded LuaJIT for dynamic scripting
- Built from Source: Compiled with optimized configuration, not based on official image
- Optional Proxy Connect: Includes ngx_http_proxy_connect_module for forward proxy support
- LuaRocks: Lua package manager included for easy module installation
- Extensive Modules: Pre-compiled with HTTP/2, SSL, streaming, and dynamic modules
- Production Ready: Includes healthcheck, non-root worker processes, and security hardening
Usage
Docker Compose
services:
openresty:
image: ghcr.io/oorabona/openresty:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./conf.d:/usr/local/openresty/nginx/conf/conf.d:ro
- ./lua:/usr/local/openresty/lualib/app:ro
read_only: true
tmpfs:
- /var/run/openresty
- /var/cache/nginx
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
Basic Lua Example
Place your nginx configuration in conf.d/:
# conf.d/default.conf
server {
listen 80;
server_name localhost;
location / {
content_by_lua_block {
ngx.say("Hello from OpenResty + Lua!")
}
}
location /api {
access_by_lua_file /usr/local/openresty/lualib/app/auth.lua;
proxy_pass http://backend;
}
}
Custom Lua Modules
Create Lua modules in the lua/ directory:
-- lua/auth.lua
local jwt = require "resty.jwt"
local token = ngx.var.http_authorization
if not token then
ngx.status = 401
ngx.say("Missing Authorization header")
return ngx.exit(401)
end
-- Validate JWT token
local jwt_obj = jwt:verify("secret-key", token)
if not jwt_obj.verified then
ngx.status = 403
ngx.say("Invalid token")
return ngx.exit(403)
end
Installing Lua Packages
# Install a package with LuaRocks
docker exec openresty luarocks install lua-resty-jwt
# List installed packages
docker exec openresty luarocks list
Build Arguments
| Argument | Description | Default |
|---|---|---|
VERSION |
OpenResty version | latest |
RESTY_IMAGE_BASE |
Base image name | alpine |
RESTY_IMAGE_TAG |
Base image tag | latest |
RESTY_VERSION |
OpenResty version (same as VERSION) | ${VERSION} |
RESTY_OPENSSL_VERSION |
OpenSSL version (3.5 LTS) | 3.5.6 |
RESTY_OPENSSL_PATCH_VERSION |
OpenResty OpenSSL patch version | 3.5.5 |
RESTY_PCRE_VERSION |
PCRE2 version | 10.47 |
RESTY_PCRE_SHA256 |
SHA256 digest for the PCRE2 .tar.gz (must match RESTY_PCRE_VERSION; update both together) |
(see config.yaml) |
RESTY_J |
Parallel build jobs | 4 |
RESTY_CONFIG_OPTIONS |
Nginx build options | (see Dockerfile) |
RESTY_CONFIG_OPTIONS_MORE |
Additional configure options | -j${RESTY_J} |
RESTY_LUAJIT_OPTIONS |
LuaJIT compile options | (see Dockerfile) |
RESTY_ADD_PACKAGE_BUILDDEPS |
Additional build dependencies | Β |
RESTY_ADD_PACKAGE_RUNDEPS |
Additional runtime dependencies | Β |
RESTY_EVAL_PRE_CONFIGURE |
Commands before configure | Β |
RESTY_EVAL_POST_MAKE |
Commands after make | Β |
LUAROCKS_VERSION |
LuaRocks version | 3.13.0 |
ENABLE_HTTP_PROXY_CONNECT |
Enable proxy connect module | false |
NGX_PROXY_CONNECT_VERSION |
Proxy connect module version | 0.0.7 |
Environment Variables
| Variable | Description | Default |
|---|---|---|
PATH |
Includes OpenResty binaries | /usr/local/openresty/β¦ |
OpenResty uses standard Nginx environment variables:
- Configure via nginx.conf or environment-specific conf files
- Use
envsubstin config files for dynamic variables - See Nginx documentation for configuration options
Volumes
| Path | Description |
|---|---|
/usr/local/openresty/nginx/conf/conf.d |
Nginx configuration files (mount read-only) |
/usr/local/openresty/lualib/app |
Custom Lua modules (mount read-only) |
/var/run/openresty |
Runtime files (use tmpfs) |
/var/cache/nginx |
Cache directory (use tmpfs) |
/var/log/nginx |
Log files (logs to stdout/stderr by default) |
Ports
| Port | Protocol | Description |
|---|---|---|
| 80 | HTTP | Default HTTP port |
| 443 | HTTPS | Default HTTPS port |
Configure custom ports in your nginx configuration. For non-privileged operation, use ports > 1024.
Security
Process Security
- Master Process: Runs as root (required for binding to ports 80/443)
- Worker Processes: Run as non-root
nginxuser (uid 101, gid 101) - No Shell: nginx user has
/sbin/nologinshell - Signal Handling: Uses SIGQUIT for clean shutdown
Runtime Hardening
The included docker-compose.yml demonstrates security best practices:
services:
openresty:
image: ghcr.io/oorabona/openresty:latest
read_only: true # Immutable filesystem
tmpfs:
- /var/run/openresty # Writable runtime directory
- /var/cache/nginx # Writable cache directory
- /tmp # Writable temp directory
cap_drop:
- ALL # Drop all capabilities
cap_add:
- NET_BIND_SERVICE # Only allow binding privileged ports
security_opt:
- no-new-privileges:true # Prevent privilege escalation
Non-Privileged Port Alternative
For maximum security without root at all:
services:
openresty:
image: ghcr.io/oorabona/openresty:latest
user: "101:101" # Run as nginx:nginx
read_only: true
tmpfs:
- /var/run/openresty
- /var/cache/nginx
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
ports:
- "8080:8080"
- "8443:8443"
Note: Requires nginx configuration to listen on 8080/8443 instead of 80/443.
Healthcheck
Built-in healthcheck verifies OpenResty is responding:
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost/nginx_status || exit 1
Ensure your nginx configuration includes a status endpoint:
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Dependencies
This container includes the following pinned dependencies:
| Dependency | Version | Monitoring Status | Notes |
|---|---|---|---|
| Alpine Linux | latest | Active | Base image |
| OpenResty | (from version.sh) | Active | Main application |
| OpenSSL | 3.5.6 | Pinned (3.5 LTS) | LTS, supported to 2030-04-08; migrated from EOL 1.1.1w (#448) |
| PCRE2 | 10.47 | Active (pinned) | Migrated from EOL PCRE1 8.45 (#453 volet 1); tracked-source monitoring redesign tracked in #453 |
| LuaRocks | 3.13.0 | Active | Lua package manager |
| ngx_http_proxy_connect_module | 0.0.7 | Active | Optional forward proxy support |
Note on pinned dependencies:
- OpenSSL 3.5.6: Pinned to the OpenSSL 3.5 LTS series (supported to 2030-04-08). Migrated from the EOL 1.1.1w pin after openssl.org removed the 1.1.1w tarball and broke the build (#448). OpenRestyβs
sess_set_get_cb_yieldpatch (version 3.5.5) is applied for Lua coroutine session-callback yield.monitor: falseis retained for now; the tracked-source monitoring redesign is tracked in #453. - PCRE2 10.47: Migrated from EOL PCRE1 8.45 (#453 volet 1). Downloaded from
github.com/PCRE2Project/pcre2/releasesand integrity-verified via SHA256 (RESTY_PCRE_SHA256) before extraction.RESTY_PCRE_VERSIONnow refers to a PCRE2 version (PCRE1 is retired). When bumping the version, update bothRESTY_PCRE_VERSIONandRESTY_PCRE_SHA256together β they are coupled to the same.tar.gzasset.monitor:falseis retained; tracked-source monitoring redesign is tracked in #453.
Architecture
Build Process
- Bootstrap: Downloads and compiles OpenSSL 3.5.x with OpenResty patches
- PCRE2 Compilation: Downloads, SHA256-verifies, and builds PCRE2 10.47 with JIT support
- Optional Module: Downloads ngx_http_proxy_connect_module if enabled
- OpenResty Build: Configures and compiles OpenResty with all modules
- LuaRocks Installation: Installs Lua package manager
- Cleanup: Removes build dependencies to minimize image size
Included Nginx Modules
Core HTTP Modules:
- http_ssl_module - HTTPS support
- http_v2_module - HTTP/2 protocol
- http_realip_module - Client IP from proxy headers
- http_addition_module - Add text before/after responses
- http_sub_module - Response substitution
- http_dav_module - WebDAV methods
- http_flv_module - FLV streaming
- http_mp4_module - MP4 streaming
- http_gunzip_module - Decompress responses
- http_gzip_static_module - Serve pre-compressed files
- http_auth_request_module - External authentication
- http_random_index_module - Random directory index
- http_secure_link_module - Signed URL validation
- http_slice_module - Range request slicing
- http_stub_status_module - Basic status page
Dynamic Modules:
- http_geoip_module - Geolocation based on IP
- http_image_filter_module - Image transformation
- http_xslt_module - XSLT transformations
Stream Modules:
- stream_core_module - TCP/UDP load balancing
- stream_ssl_module - TLS for stream
Mail Modules:
- mail_core_module - Mail proxy
- mail_ssl_module - SMTP/IMAP/POP3 SSL
Directory Structure
/usr/local/openresty/
βββ bin/
β βββ openresty # OpenResty binary
β βββ resty # Resty CLI
β βββ restydoc # Documentation viewer
βββ luajit/
β βββ bin/
β βββ luajit # LuaJIT interpreter
β βββ luarocks # Lua package manager
βββ lualib/ # Lua libraries
β βββ resty/ # OpenResty Lua modules
β βββ app/ # Custom modules (mount here)
βββ nginx/
β βββ conf/
β β βββ nginx.conf # Main configuration
β β βββ conf.d/ # Additional configs (mount here)
β βββ html/ # Default web root
β βββ logs/ # Logs (symlinked to stdout/stderr)
βββ openssl/ # OpenSSL libraries
βββ pcre2/ # PCRE2 libraries
Common Use Cases
API Gateway
upstream backend {
server api1:3000;
server api2:3000;
keepalive 32;
}
server {
listen 80;
location /api/v1 {
access_by_lua_block {
-- Rate limiting
local limit = require "resty.limit.req"
local lim = limit.new("limit_store", 100, 50)
local key = ngx.var.remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
return ngx.exit(429)
end
end
}
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
Web Application Firewall
-- lua/waf.lua
local rules = {
sql_injection = [[(\%27)|(\')|(\-\-)|(\%23)|(#)]],
xss = [[(\%3C)|(<)|(\%3E)|(>)|(\%3c)|(\%3e)]],
}
local uri = ngx.var.uri
local args = ngx.var.args or ""
for rule_name, pattern in pairs(rules) do
if string.match(uri, pattern) or string.match(args, pattern) then
ngx.log(ngx.ERR, "WAF: Blocked ", rule_name, " attempt")
return ngx.exit(403)
end
end
Caching Proxy
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cache:10m max_size=1g inactive=60m;
server {
listen 80;
location / {
proxy_cache cache;
proxy_cache_valid 200 60m;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_bypass $http_cache_control;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://origin;
}
}
Dynamic Load Balancing
-- lua/balancer.lua
local balancer = require "ngx.balancer"
local redis = require "resty.redis"
-- Get healthy backends from Redis
local red = redis:new()
red:connect("redis", 6379)
local backends = red:smembers("healthy_backends")
-- Round-robin selection
local current = ngx.shared.balance:incr("counter", 1, 0)
local index = (current % #backends) + 1
local backend = backends[index]
-- Set upstream server
local ok, err = balancer.set_current_peer(backend)
if not ok then
ngx.log(ngx.ERR, "failed to set peer: ", err)
return ngx.exit(500)
end
Performance Tips
- Connection Pooling: Use keepalive upstream connections
- Lua Shared Dictionaries: Cache data across workers with
lua_shared_dict - LuaJIT Optimization: Profile code with
-jdumpfor hotspots - Worker Processes: Set to number of CPU cores
- Sendfile: Enable for static file serving
- TCP Nopush: Reduce network overhead
- Gzip: Compress responses (or use gzip_static)
Version Management
# Check current version
./version.sh
# Check latest upstream version
./version.sh latest
# Output JSON for automation
./version.sh --json
Building Locally
# From repository root
./make build openresty
# With specific version
./make build openresty 1.25.3.2
# With proxy connect module
docker build \
--build-arg ENABLE_HTTP_PROXY_CONNECT=true \
-t openresty:latest .