Back to Dashboard

openresty

1.31.1.1-alpine

OpenResty with common modules pre-compiled. Multi-arch, SBOM-attested, daily upstream monitoring.

Trust posture

πŸ“‹ SBOM ATTESTEDπŸ›‘ TRIVY: 3 HIGH (advisory) Β· SCANNED 2026-08-29πŸ— AMD64 + ARM64 πŸ”— 4/4 deps tracked daily πŸ” REPRODUCE THESE CHECKS LOCALLY
PULLS 8.9K 6517 to 8899 pulls across 30 recorded days 2026-08-02: 6517 pulls2026-08-03: 6524 pulls2026-08-04: 6551 pulls2026-08-05: 6553 pulls2026-08-06: 6687 pulls2026-08-07: 6687 pulls2026-08-08: 6710 pulls2026-08-09: 6734 pulls2026-08-10: 6750 pulls2026-08-11: 6775 pulls2026-08-12: 6819 pulls2026-08-13: 6932 pulls2026-08-14: 6976 pulls2026-08-15: 7059 pulls2026-08-16: 7083 pulls2026-08-17: 7187 pulls2026-08-18: 7207 pulls2026-08-19: 7377 pulls2026-08-20: 7401 pulls2026-08-21: 7588 pulls2026-08-22: 7846 pulls2026-08-23: 7862 pulls2026-08-24: 7893 pulls2026-08-25: 7917 pulls2026-08-26: 8122 pulls2026-08-27: 8186 pulls2026-08-28: 8194 pulls2026-08-30: 8846 pulls2026-08-31: 8895 pulls2026-09-01: 8899 pulls
STARS 0

VERIFIABLE TRUST ARTIFACTS

Provenance

Build commit
8a8b07b
Build digest
sha256:ef26e8ff96ba6bd087f0281619ab7043b02f7a3e8a18f2af96473a7d96ee25a7
Index digest
sha256:04cc9a85fdcdcee0751ee066b7c8c9ba1e508dfe98089f6b2a3f9278e224f220
Manifest digest (amd64)
sha256:d58c6d28683470f324ef05700634ac4a5e9f4dd4c1cef7b046f5a7e5c37aa0e8
Manifest digest (arm64)
sha256:9dd9457aca5d9912cf715479f119dc9f16891abc2237cd1853af7909e15167f2
SBOM attestation
43788953…
Trivy last scan
2026-08-29 00:47 UTC
Base image
Verify
gh attestation verify oci://ghcr.io/oorabona/openresty:1.31.1.1-alpine --owner oorabona guide β†’

Security scan results

Trivy Β· last scan 2026-08-29

Last scan: (advisory mode β€” Trivy runs continue-on-error in CI; we surface findings, we do not block builds on them).

0Critical
3High
6Medium
12Low
0Info

Top advisories (upstream, advisory)

    β†’ Full report via gh api β€” see Verify Images.

    Explore

    Build lineagesha256:
    Build Lineage
    Build Digest sha256:ef26e8ff96ba6bd087f0281619ab7043b02f7a3e8a18f2af96473a7d96ee25a7
    Base Image
    RESTY_IMAGE_TAG latest
    RESTY_OPENSSL_VERSION 3.5.6
    RESTY_OPENSSL_PATCH_VERSION 3.5.5
    RESTY_PCRE_VERSION 10.47
    RESTY_PCRE_SHA256 c08ae2388ef333e8403e670ad70c0a11f1eed021fd88308d7e02f596fcd9dc16
    LUAROCKS_VERSION 3.13.0
    NGX_PROXY_CONNECT_VERSION 0.0.7
    RESTY_J 4
    Package summary n/a β€” runtime parsed
    Recent changes n/a β€” runtime parsed
    Build history n/a β€” runtime fetched
    Dependency health 2 updates available

    Dependency Health

    2 updates available
    4/4 dependencies monitored
    Dependency Current Latest Type
    RESTY_OPENSSL_VERSION 3.5.6 3.5.8 patch
    RESTY_PCRE_VERSION 10.47 10.48 minor
    Up-to-date dependencies
    LUAROCKS_VERSION 3.13.0 NGX_PROXY_CONNECT_VERSION 0.0.7

    Documentation

    README

    OpenResty

    High-performance web platform combining Nginx with LuaJIT for dynamic, programmable request handling.

    Docker Hub GHCR Build

    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 8080:8080 \
      -p 8443:8443 \
      -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:
          - "8080:8080"
          - "8443:8443"
        volumes:
          - ./conf.d:/usr/local/openresty/nginx/conf/conf.d:ro
          - ./lua:/usr/local/openresty/lualib/app:ro
        cap_drop:
          - ALL
        security_opt:
          - no-new-privileges:true
    

    Basic Lua Example

    Place your nginx configuration in conf.d/:

    # conf.d/default.conf
    server {
        listen 8080;
        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

    The image runs as the non-root nginx user, which can’t write the system LuaRocks tree under /usr/local. Install packages at build time in a derived Dockerfile β€” reset to USER root first, since the base image’s final USER nginx otherwise carries into your RUN steps:

    FROM ghcr.io/oorabona/openresty:latest
    USER root
    RUN luarocks install lua-resty-jwt   # into the system tree, on OpenResty's lua_package_path
    USER nginx
    

    Runtime luarocks install --local also works, but it installs into the nginx user’s home tree, which is not on OpenResty’s default lua_package_path β€” you’d have to extend lua_package_path / lua_package_cpath in your nginx config for require to find it. Build-time install into the system tree is the simpler path.

    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 envsubst in 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
    8080 HTTP Default HTTP port
    8443 HTTPS Conventional non-root HTTPS port (opt-in β€” provide a cert + listen 8443 ssl;)

    The image runs fully as the non-root nginx user, which cannot bind a privileged port, so it listens on 8080 by default (8443 for TLS). Publish these to any host port you like; if you mount your own config, listen on a port β‰₯ 1024.

    Security

    Process Security

    • Master and Worker Processes: Both run as the non-root nginx user (uid 101, gid 101). The stock config listens on the unprivileged port 8080 (8443 is the conventional, opt-in HTTPS port), so the image needs no capabilities at all β€” compatible with cap_drop: ALL and no-new-privileges.
    • No Shell: nginx user has /sbin/nologin shell
    • Signal Handling: Uses SIGQUIT for clean shutdown

    Runtime Hardening

    The included docker-compose.yml demonstrates security best practices β€” a non-root image on unprivileged ports, zero capabilities, and an immutable root filesystem:

    services:
      openresty:
        image: ghcr.io/oorabona/openresty:latest
        read_only: true              # Immutable root filesystem
        volumes:
          # nginx (non-root) writes its pid/cache/temp files into image-created
          # dirs; a tmpfs over an existing dir isn't reliably writable by the
          # non-root user with the short-form `tmpfs:` list (it can't set a mode),
          # so use the long-form with an octal `mode: 01777` (some Compose versions
          # accept it only as an unquoted integer). One per writable dir:
          - { type: tmpfs, target: /var/run/openresty, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /var/cache/nginx, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /tmp, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /usr/local/openresty/nginx/client_body_temp, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /usr/local/openresty/nginx/proxy_temp, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /usr/local/openresty/nginx/fastcgi_temp, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /usr/local/openresty/nginx/uwsgi_temp, tmpfs: { mode: 01777 } }
          - { type: tmpfs, target: /usr/local/openresty/nginx/scgi_temp, tmpfs: { mode: 01777 } }
        cap_drop:
          - ALL                      # Drop all capabilities (none are needed)
        security_opt:
          - no-new-privileges:true   # Prevent privilege escalation
        ports:
          - "8080:8080"              # HTTP
          - "8443:8443"              # HTTPS β€” nothing listens here until you add a
                                     #         `listen 8443 ssl;` server + a cert
    

    On a normal (writable) rootfs the tmpfs mounts aren’t needed β€” the image writes only to its own already-chowned dirs β€” so read_only plus the tmpfs block is the extra step for an immutable filesystem.

    Because it runs as a non-root user, binds only unprivileged ports, and needs no capabilities, the image is a good fit for Kubernetes’ restricted Pod Security Standard β€” set the corresponding pod securityContext (runAsNonRoot: true, runAsUser: 101, allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], and a seccompProfile); a Compose cap_drop/security_opt is not itself a Kubernetes manifest.

    Healthcheck

    The built-in healthcheck verifies OpenResty is responding. It uses BusyBox wget (curl is not in the runtime image) against / on the non-privileged port the non-root server listens on:

    HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
        CMD wget -q -O /dev/null http://localhost:8080/ || exit 1
    

    The built-in check targets :8080 β€” the port the stock config listens on. If you mount a config that listens only on a different port (e.g. 8443, or another unprivileged port), override the healthcheck to match, or the container will report unhealthy even while serving.

    If you’d rather probe a dedicated status endpoint, add one to your nginx configuration and point a custom healthcheck at it:

    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_yield patch (version 3.5.5) is applied for Lua coroutine session-callback yield. monitor: false is 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/releases and integrity-verified via SHA256 (RESTY_PCRE_SHA256) before extraction. RESTY_PCRE_VERSION now refers to a PCRE2 version (PCRE1 is retired). When bumping the version, update both RESTY_PCRE_VERSION and RESTY_PCRE_SHA256 together β€” they are coupled to the same .tar.gz asset. monitor:false is retained; tracked-source monitoring redesign is tracked in #453.

    Architecture

    Build Process

    1. Bootstrap: Downloads and compiles OpenSSL 3.5.x with OpenResty patches
    2. PCRE2 Compilation: Downloads, SHA256-verifies, and builds PCRE2 10.47 with JIT support
    3. Optional Module: Downloads ngx_http_proxy_connect_module if enabled
    4. OpenResty Build: Configures and compiles OpenResty with all modules
    5. LuaRocks Installation: Installs Lua package manager
    6. 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 8080;
    
        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 8080;
    
        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 -jdump for 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 .