Skip to content

Allow TCP connections in Ruby

nginx’s stream module proxies TCP connections, and UDP sessions with listen ... udp. In a server of the stream block, mruby_stream runs a Ruby script in the access phase of the stream module, once per session, before nginx connects to the upstream. The script reads the addresses of the session through Nginx::Stream::Connection, and closes the session by setting stream_status to Nginx::Stream::ABORT.

The script lets the session through only from the addresses of its list. nginx then proxies the connection to the upstream, here an HTTP server of the test configuration on port 18168. The request and the response are the bytes that the client sends and receives over the TCP connection.

test/conf/conf.d/stream/42-guide-tcp.conf
upstream guide_tcp_backend {
server 127.0.0.1:18168;
}
server {
listen 127.0.0.1:12364;
mruby_stream build/nginx/html/guide_tcp.rb;
proxy_pass guide_tcp_backend;
}
test/html/guide_tcp.rb
allowed = ["127.0.0.1", "::1"]
c = Nginx::Stream::Connection
c.stream_status = Nginx::Stream::ABORT unless allowed.include?(c.remote_ip)
test/html/guide_tcp.request: the request that the case sends
GET /status HTTP/1.1
Host: 127.0.0.1:12364
Connection: close
test/html/guide_tcp.response: the response that the case compares
HTTP/1.1 200 OK
Content-Type: text/plain
the backend on port 18168 answered

On every CI run, the case test/t/cases/guides.rb sends this request and compares the status line, the headers shown on this page and the whole body. The five files last changed on 2026-10-29 in commit 32219e53.

  • The stream module runs the script for UDP sessions too; the test suite sends TCP only.
  • The script runs before nginx reads the client’s data, so it decides on the addresses and ports of the session, not on what the client sends.
  • The stream block has its own mruby state, separate from that of the http block, and its own directives for the code at startup (mruby_stream_init, mruby_stream_init_worker).