Docs

Self-host pglens on a server

pglens normally runs on your laptop. You can also run it on a server and open it at an address like https://db.example.com, so you and your team reach your databases from any browser without installing anything.

You need a server with Docker, a domain you control, and about ten minutes. pglens sits behind a reverse proxy that handles HTTPS and an extra login.

Requires pglens 3.7 or later. Updated October 27, 2026.

1. Run the container

On the server, start the published image. Replace db.example.com with your subdomain.

docker run -d --name pglens --restart unless-stopped \
  -p 127.0.0.1:54321:54321 \
  -v pglens-data:/home/node/.pglens \
  -e PGLENS_PUBLIC_URL=https://db.example.com \
  ghcr.io/tsvillain/pglens:latest

Images for linux/amd64 and linux/arm64 are published with every release, tagged latest, 3.7 and 3.7.0. Pin a version in production. To build it yourself, run docker build -t pglens . in a clone of the repository.

-p 127.0.0.1:54321:54321 publishes the port on the server's loopback only, so the proxy can reach pglens and the internet can't. The pglens-data volume keeps saved connections, passwords, query history and the sign-in token across restarts and updates.

2. Put HTTPS in front

Point a DNS record for your subdomain at the server, then configure one of these proxies.

Caddy

Caddy gets a certificate automatically. Generate the password hash with caddy hash-password.

db.example.com {
    basic_auth {
        admin <password hash>
    }
    reverse_proxy 127.0.0.1:54321
}

nginx

server {
    listen 443 ssl;
    server_name db.example.com;
    # ssl_certificate / ssl_certificate_key ...
    auth_basic "pglens";
    auth_basic_user_file /etc/nginx/pglens.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:54321;
        proxy_set_header Host $host;
    }
}

The proxy must pass the original Host header. Caddy does this by default; nginx needs the proxy_set_header line. pglens answers 403 to any hostname other than the one in PGLENS_PUBLIC_URL, which blocks DNS-rebinding attacks.

3. Sign in

docker logs pglens
# ✓ Server running on https://db.example.com
#   Open: https://db.example.com/?token=...

Open that link once. pglens stores the token in an HttpOnly, Secure, SameSite=Strict cookie and removes it from the address bar. To print the token again, run docker exec pglens node bin/pglens token.

Settings

Variable Default What it does
PGLENS_PUBLIC_URL unset Public origin, such as https://db.example.com. Allows that hostname, marks the cookie Secure for https, and is the URL pglens prints. Subdomains only; a path like /pglens is rejected.
PGLENS_BIND 127.0.0.1, 0.0.0.0 in Docker Address the server listens on.
PGLENS_PORT 54321, or a random port if busy Fixed port. If it's taken, pglens exits instead of picking another one.
PGLENS_SECRET_STORE keychain, file in Docker file keeps passwords in ~/.pglens/secrets.json (mode 0600) on servers without a keychain.
PGLENS_NO_UPDATE_CHECK unset, 1 in Docker Turns off the daily update check.

Without Docker

Install pglens with the usual command, then run pglens serve in the foreground under systemd or another process manager. Leave PGLENS_BIND at 127.0.0.1 when the proxy runs on the same machine.

# /etc/systemd/system/pglens.service
[Unit]
Description=pglens
After=network.target

[Service]
User=pglens
Environment=PGLENS_PUBLIC_URL=https://db.example.com
Environment=PGLENS_PORT=54321
Environment=PGLENS_SECRET_STORE=file
ExecStart=/home/pglens/.pglens/bin/pglens serve
Restart=on-failure

[Install]
WantedBy=multi-user.target

Access and security

Update

docker pull ghcr.io/tsvillain/pglens:latest && docker rm -f pglens
# run the same docker run command again; the volume keeps your data

Next

Get started

Stop writing SELECT *
just to look around.

curl -fsSL https://pglens.org/install.sh | bash

Free & open source · no account · no telemetry