Get started
This page runs nginx with ngx_mruby in Docker, sends a request that a Ruby
script answers, and then changes the script. The example is the folder
examples/start of the repository: compose.yaml builds
nginx with ngx_mruby from the source in your checkout with the
Dockerfile, and starts it with the nginx.conf and
hello.rb of the folder.
Before you start
Section titled “Before you start”- You need Docker with the Compose plugin (
docker compose), git, curl and a network connection: the build downloads nginx from nginx.org and the mrbgems ofbuild_config.rbfrom GitHub. - No verified prebuilt image of this v3 development version is provided,
so the first run compiles mruby and nginx. On 2026-10-29, on GitHub’s
ubuntu-24.04runner with Docker Engine 28.0.4 and Docker Compose 2.38.2, step 3 took 170 seconds. Later runs reuse the built image. - These steps run in CI on every pull request that changes
examples/(the workflow.github/workflows/examples.yml), which compares every output on this page with what the commands print.
Run nginx with a Ruby handler
Section titled “Run nginx with a Ruby handler”The site documents ngx_mruby 3.x, which is developed on the branch next.
-
Clone the branch
nextof the repository.$ git clone --branch next https://github.com/matsumotory/ngx_mruby.git -
Go to the folder of the example.
$ cd ngx_mruby/examples/start -
Build the image and start nginx. With
--wait, the command returns when nginx answers the health check ofcompose.yaml, and Compose reports the containerstart-nginx-1as healthy.$ docker compose up --build --wait -
Send a request to
/hellowith the argumentname. The Ruby script writes the response.$ curl -s 'http://localhost:8080/hello?name=Ruby'Hello, Ruby! hello.rb answered GET /hello.
What answered the request
Section titled “What answered the request”nginx.conf sends the requests for /hello to the script with
mruby_content_handler:
# The nginx configuration of the start page. compose.yaml mounts this# folder at /example, and the image starts nginx with this file.user nobody nogroup;worker_processes 1;error_log /dev/stderr;
events { worker_connections 64;}
http { access_log /dev/stdout;
server { listen 8080;
location /hello { mruby_content_handler /example/hello.rb; } }}hello.rb reads the argument through Nginx::Request and writes the body
with Nginx.rputs:
# The content handler of the start page (examples/start/nginx.conf).r = Nginx::Request.newname = r.var.arg_name.to_sname = "world" if name.empty?r.content_type = "text/plain"Nginx.rputs "Hello, #{name}! hello.rb answered #{r.method} #{r.uri}.\n"nginx runs the script inside the worker process, with an mruby VM that ngx_mruby embeds in nginx. No other process takes part. The Ruby reference lists the classes and methods that a script can use.
Change the script
Section titled “Change the script”compose.yaml mounts this folder into the container, and the directive
names the script without the parameter cache, so nginx reads the file
again for every request. A change to hello.rb takes effect with the next
request, without a reload.
-
Replace
HellowithGood morninginhello.rb. The command keeps the original file ashello.rb.orig.$ sed -i.orig 's/Hello/Good morning/' hello.rb -
Send the request again. The response has the new greeting.
$ curl -s 'http://localhost:8080/hello?name=Ruby'Good morning, Ruby! hello.rb answered GET /hello. -
Put the original script back.
$ mv hello.rb.orig hello.rb -
Validate the mounted configuration and reload it. Use the binary and configuration paths of this image, rather than relying on
PATH.
$ docker compose exec -T nginx /usr/local/nginx/sbin/nginx -t -c /example/nginx.conf$ docker compose exec -T nginx /usr/local/nginx/sbin/nginx -s reload -c /example/nginx.conf$ curl -s 'http://localhost:8080/hello?name=Ruby'Hello, Ruby! hello.rb answered GET /hello.-
Stop and remove the container. Compose reports the container
start-nginx-1as removed.$ docker compose down
Reading the file for every request is convenient while you write a
script, and it reads the disk on the request path. In production, add
cache to the directive, as
Caching compile code
shows, so that nginx compiles the script once when it reads its
configuration.
Apply your changes
Section titled “Apply your changes”| Change | Apply it | Why |
|---|---|---|
Ruby without cache |
Send the next request | The handler reads the mounted script each time |
nginx.conf, or Ruby compiled with cache |
Validate with nginx -t, then reload as above |
nginx compiles configuration-time code when it reads the configuration |
| mrbgems or build options | Rebuild the image | These change the compiled module |
The mount is read-only inside the container; edit files on the host. The example
publishes port 8080 on host interfaces; for a local-only trial, change the Compose
mapping to 127.0.0.1:8080:8080 before starting it. Use docker compose logs nginx
to inspect a failed health check or configuration error. An image-metadata error
before compilation is a registry/network failure, not an nginx response.
Containers are one trial path. For Linux installation into an existing deployment,
follow Install, matching the nginx version and
module build options. Official nginx packages and images do not include ngx_mruby;
--with-compat is not compatibility with arbitrary nginx versions. Running this
Linux image on a Mac is not evidence of a native macOS build.
The recorded 170-second run above is historical CI evidence, not a current timing guarantee or an arm64 result. A fresh linux/arm64 trial on 2026-10-30 stopped while fetching the Ubuntu base-image metadata, before compilation. That attempt did not validate startup, editing or reload. The examples workflow validates the commands on its Linux runner; consult its run for the commit you use.
Primary references: NGINX containers, Linux packages, dynamic modules, reload, and bind mounts.
Next steps
Section titled “Next steps”-
Install: build ngx_mruby into your own nginx, as a static or a dynamic module.
-
Directives: the phases where nginx runs Ruby, and the directive for each.
-
Request phases: the order in which nginx runs the handlers of one request.
-
Agent proxy: extend the handler into tested model routing and streamed relay recipes.