Skip to content

Add SNI test and fix hostname handling in nginx ssl handshake#154

Open
simbo1905 wants to merge 2 commits into
leafo:masterfrom
simbo1905:issue-153-nginx-sni-hostname
Open

Add SNI test and fix hostname handling in nginx ssl handshake#154
simbo1905 wants to merge 2 commits into
leafo:masterfrom
simbo1905:issue-153-nginx-sni-hostname

Conversation

@simbo1905

Copy link
Copy Markdown

Summary

In the nginx (ngx.socket) code path, pgmoon performs its TLS handshake without sending the SNI (Server Name Indication) extension. The server_name argument to tcpsock:sslhandshake is passed as nil:

https://github.com/leafo/pgmoon/blob/master/pgmoon/init.moon#L1078

when "nginx"
  @sock\sslhandshake false, nil, @config.ssl_verify

Managed PostgreSQL services that route connections by SNI cannot identify the target instance when the extension is absent, so they reject the connection during the handshake. libpq has sent SNI by default since PostgreSQL 14 (sslsni), so psql connects to the same endpoint while pgmoon does not.

The fix is one line: pass the host pgmoon already holds as the server_name.

when "nginx"
  @sock\sslhandshake false, @config.host, @config.ssl_verify

Working CI Proof On My Fork

The full suit with these two cherry-picked commits runs on my fork over at https://github.com/simbo1905/pgmoon/actions/runs/28831111428/job/85504998959#step:7:330

Environment

Component Version
pgmoon 1.17.0-1 (LuaRocks)
Debian 13 (trixie), debian:trixie-slim
nginx 1.26.3 (Debian package)
libnginx-mod-http-lua 1:0.10.28-2 (OpenResty lua-nginx-module, Debian package)
lua-resty-core / lua-resty-lrucache 0.1.31-1 / 0.15-2
LuaJIT 2.1.0+openresty20250117-2

Reproduction against a real SNI-routed service (Scaleway Serverless SQL)

This confirms the connection failure on a service that requires SNI. Following the Scaleway Serverless SQL quickstart, using the scw CLI:

1. Create a database:

scw sdb-sql database create name=pgmoon-sni-repro cpu-min=0 cpu-max=1 region=fr-par
scw sdb-sql database list region=fr-par

The database ID forms part of the hostname ({database-id}.pg.sdb.fr-par.scw.cloud), which is what the service routes on via SNI

2. Generate credentials in the console (Connect, then Generate API key). The IAM key id and secret become the PostgreSQL user and password.

3. Put the connection details in .env:

PGHOST={database-id}.pg.sdb.fr-par.scw.cloud
PGPORT=5432
PGDATABASE={database name}
PGUSER={IAM key id}
PGPASSWORD={IAM secret key}

4. psql connects, because libpq sends SNI:

$ set -a; . ./.env; set +a
$ PGSSLMODE=require psql -h $PGHOST -p $PGPORT -U $PGUSER -d $PGDATABASE -tAc "select version()"
PostgreSQL 16.14 (Debian 16.14-1.pgdg12+1) on x86_64-pc-linux-gnu, ...

5. pgmoon 1.17.0 under nginx fails on the same endpoint

There is a complete demo of pgmoon with OpenResty implementing the GoThinkster API that has to manually patch around htis error at https://codeberg.org/simbo1905/realworld-openresty-lua/src/tag/2026-07-06_0825_main/app/db.lua#L33-L53 so to reproduce comment out those lines.

connect failed: FATAL: Database hostname wasn't sent to server. Either add "?options=databaseid%3D{databaseid}"
at the end of your connection string, or use another client supporting TLS ServerNameIndication.
More solutions: https://www.scaleway.com/en/docs/faq/serverless-sql-databases/

The error names the cause directly: no TLS Server Name Indication. Note that Serverless SQL scales to zero, so the first connection after idle can be slow or time out once before the instance wakes; retry if that happens.

simbo1905 added 2 commits July 7, 2026 00:46
The nginx cosocket sslhandshake call hardcoded nil for server_name,
so TLS SNI never advertised the target hostname to the server.

Closes leafo#153
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant