dbtrail
Guides

Console on a Hostname

Put the dbtrail console on console.example.com with TLS — DNS, certificate, and the one header rule that returns 403 until you set it

The console binds 127.0.0.1:8090. That is the right default for one operator on one box and the wrong one for a team, so at some point you put it on console.example.com. Four things, and only the fourth surprises people.

1. DNS

An A record (or AAAA) for the hostname, pointing at the host's public address. Nothing about dbtrail is involved in this step.

2. The firewall

Open 443 to the clients that need it. Leave 8090 closed — nothing outside the host should reach the console's own port.

3. TLS

Two shapes, equally supported. Pick by whether the host already runs a web server.

The console terminates TLS

bintrail-console serve --index-dsn '<dsn>' \
  --listen 0.0.0.0:8090 \
  --tls-cert /etc/ssl/console.crt \
  --tls-key  /etc/ssl/console.key \
  --allowed-hosts console.example.com

A reverse proxy terminates TLS

The console stays on loopback and nginx faces the network. This is the usual choice, and it gets you automatic certificate renewal for free.

server {
    listen 443 ssl;
    server_name console.example.com;

    ssl_certificate     /etc/letsencrypt/live/console.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/console.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8090;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Backup and SQL-export downloads are written straight to the response
        # as they are built. With buffering on, nginx spools the whole archive
        # to disk before sending a byte of it.
        proxy_buffering off;
    }
}

A credential comes first

A console on a non-loopback address refuses to start without a credential. Set a console password (or pass --token) before any of the above, or the process exits at startup.

4. The header rule

With the vhost above, the console answers every request:

HTTP 403
{"error": "forbidden: host not allowed"}

That is a defence working, not a misconfiguration. The console accepts a Host header only when it is localhost, an IP literal, or a name you listed. List the hostname:

--allowed-hosts console.example.com
# or
BINTRAIL_CONSOLE_ALLOWED_HOSTS=console.example.com

On watch the flag is --console-allowed-hosts.

Why it exists

A browser on someone's laptop can be pointed at a hostname that resolves to 127.0.0.1. Without a Host check, that page could drive a console the attacker has no network path to. This is DNS rebinding, and the allowlist costs one flag.

The shortcut, and why not to take it

nginx's default — no proxy_set_header Host line at all — sends the upstream address as the Host, so the console sees 127.0.0.1:8090. That is an IP literal, so it is always allowed. A vhost written that way works immediately and never mentions --allowed-hosts.

It also means every request arrives claiming to be for 127.0.0.1: the real hostname never appears in the console's logs, and anything that later needs to know its own public name has nothing to work with. Pass the real Host and list it.

Which binary

The flags below are the same on both consoles: bintrail-console (the open-core binary) and dbtrail-console-ee (the enterprise one, which is the same console plus its licensed features). Host-header handling is core behaviour and needs no licence.

What you get with it

The MCP endpoint rides the same allowlist. Once the hostname is allowed, an MCP client reaches it at https://console.example.com/mcp — no tunnel, no port forward, behind the same credential as the rest of the console.

On this page