Leadlantern docs
v1.0.0
Get help
● Start · Your server

Installation
a Linux server with Caddy and systemd.

This page takes you from a new Linux server to Leadlantern running behind https and starting by itself after a reboot. You run the commands on the server over ssh. Plan about 45 minutes the first time.

Ubuntu / DebianCaddysystemdpnpm 12

01The plan in plain words

Leadlantern is one Node.js program. It listens on port 8080 on the server itself. Caddy, a small web server, sits in front of it, gets an https certificate for your domain by itself and passes visitors on to port 8080. systemd, which every modern Linux has, starts Leadlantern after a reboot and restarts it if it stops.

  1. Install Node.js, pnpm and Leadlantern.
  2. Configure .env with a secret key, listening only on the server itself.
  3. Create the owner through an ssh tunnel, before anyone else can reach the server (why).
  4. Run it as a service with systemd.
  5. Put Caddy in front for https, then set the public URL.

021. Install

Windows

The commands on this page are written for macOS and Linux shells. On a Windows PC run them inside WSL (Ubuntu) or in Git Bash; production belongs on a Linux server. See Windows.

# Node.js 26 LTS, build tools and pnpm (Debian/Ubuntu, standard NodeSource procedure)
curl -fsSL https://deb.nodesource.com/setup_26.x | sudo -E bash -
sudo apt-get install -y nodejs build-essential python3
sudo npm install -g pnpm
node --version              # v26 (24 or newer also works)

# a system user that runs the program
sudo useradd --system --create-home --home-dir /path/to/leadlantern --shell /usr/sbin/nologin leadlantern

# copy the source folder of the download to /path/to/leadlantern/source (scp, sftp or unzip), then:
sudo chown -R leadlantern:leadlantern /path/to/leadlantern
cd /path/to/leadlantern/source
sudo -u leadlantern pnpm install
sudo -u leadlantern pnpm build
sudo -u leadlantern pnpm test        # optional: offline tests, no keys needed

Pick any folder for /path/to/leadlantern, for example /opt/leadlantern, and use it everywhere below. Production runs the compiled JavaScript in dist/; pnpm dev is for development only.

03pnpm 12 and the two native builds

In plain words: pnpm 12 does not run the install scripts of a package unless the project allows it. Leadlantern needs two of them: better-sqlite3 (the database driver) and esbuild (used by the test runner). The shipped pnpm-workspace.yaml allows exactly those two:

allowBuilds:
  better-sqlite3: true
  esbuild: true

Keep that file next to package.json. Without it pnpm 12 stops with ERR_PNPM_IGNORED_BUILDS. Use pnpm 10 or newer.

042. Configure .env

cd /path/to/leadlantern/source
sudo -u leadlantern cp .env.example .env
openssl rand -hex 32        # paste the result into .env as ADMIN_SECRET_KEY
sudo -u leadlantern nano .env

Set HOST=127.0.0.1 now. Leadlantern then answers only on the server itself, which is all Caddy needs. Every variable:

VariableDefaultWhat it does
ADMIN_SECRET_KEYempty32 random bytes as 64 hex characters (openssl rand -hex 32). Encrypts the keys you save in the console and signs unsubscribe links. Empty: a key is generated into data/.admin-secret-key on first start. Back it up.
PORT8080The port Leadlantern listens on.
HOST0.0.0.0Which network address it listens on. 127.0.0.1 = only this server (use it behind Caddy on the same server). 0.0.0.0 = every address.
DATA_DIRdataThe folder for leadlantern.sqlite and admin.sqlite, relative to the source folder.
PUBLIC_URLemptyThe https address of this server, e.g. https://leads.your-agency.com. Report and unsubscribe links are built from it. Setting it here locks the console field.
TRUST_PROXY01 behind Caddy or nginx, so the rate limits of the public pages see each visitor's own address (below).
TRUST_PROXY_HOPS1How many proxies stand in front (1 to 5). Used only with TRUST_PROXY=1.
LEADLANTERN_WORKERS10 stops the background job that removes Google details after 30 days (Google's 30-day rule). Only for maintenance.
GOOGLE_PLACES_API_KEYemptyOptional. Same as the console field; set here, it locks the field.
PAGESPEED_API_KEYemptyOptional. Same as the console field.
AI_API_KEYemptyOptional. Same as the console field.
RESEND_API_KEYemptyOptional. Same as the console field.
DEMO_MODE, ADMIN_DEMO_PASSWORD, ADMIN_DEMO_EMAIL, ADMIN_DEMO_NOTICEempty / 0Only for a public demo host. Leave them empty on your server (Demo mode).

Keys can also be typed in the console under Settings → Integrations, where they are stored encrypted. Never commit .env to a repository.

05About ADMIN_SECRET_KEY

In plain words: this one value locks the keys you save in the console. Back it up together with the data folder.

  • If you lose it, the saved keys cannot be read. Set a new key, then type each key again under Integrations. Unsubscribe links in e-mails already sent stop working, because they were signed with the old key; people can still answer the e-mail and ask to be removed.
  • If you did not set one, the generated key is in data/.admin-secret-key. The server prints a reminder on every start to copy it into .env.
  • It must be exactly 64 hex characters. Anything else stops the server with ADMIN_SECRET_KEY must be 32 bytes as 64 hex characters.

063. Create the owner first

cd /path/to/leadlantern/source
sudo -u leadlantern pnpm start       # prints the one-time setup code

On your own computer, in a second terminal, open a tunnel to the server and then open http://localhost:8080/admin in your browser:

ssh -L 8080:127.0.0.1:8080 you@your-server

Type the setup code, your e-mail and a password of at least 12 characters. Then stop the server with Ctrl+C. Why this order matters: First start.

074. Run it as a service

Create /etc/systemd/system/leadlantern.service (sudo nano /etc/systemd/system/leadlantern.service):

[Unit]
Description=Leadlantern
After=network.target

[Service]
WorkingDirectory=/path/to/leadlantern/source
ExecStart=/usr/bin/node dist/src/index.js
Restart=always
User=leadlantern

[Install]
WantedBy=multi-user.target
which node                                  # put this path in ExecStart if it is not /usr/bin/node
sudo systemctl daemon-reload
sudo systemctl enable --now leadlantern
sudo systemctl status leadlantern
journalctl -u leadlantern -n 50             # the server's messages

The program reads .env from its own folder by itself; the unit needs no environment lines.

085. https with Caddy

  1. Point your domain (an A record for leads.your-agency.com) at the server's IP address.
  2. Install Caddy as its website describes for your system (caddyserver.com → Docs → Install).
  3. Write the site into /etc/caddy/Caddyfile:
leads.your-agency.com {
    reverse_proxy 127.0.0.1:8080
}
sudo systemctl reload caddy

Caddy gets the certificate by itself on the first visit. Then:

  1. Add to .env: TRUST_PROXY=1 and PUBLIC_URL=https://leads.your-agency.com (or set the public URL later in the console).
  2. Restart: sudo systemctl restart leadlantern.
  3. Open https://leads.your-agency.com/admin and sign in.

09TRUST_PROXY and TRUST_PROXY_HOPS

In plain words: the public pages (report links and unsubscribe links) limit how often one visitor may call them. Behind a proxy every request seems to come from the proxy, so Leadlantern must read the visitor's address from the X-Forwarded-For header instead. TRUST_PROXY_HOPS says how many proxies added an entry: the visitor's address is that many entries from the right.

Your setup.env
Nothing in front (trial on your computer)TRUST_PROXY=0
Caddy (or nginx) on the serverTRUST_PROXY=1, TRUST_PROXY_HOPS=1
Cloudflare in front of CaddyTRUST_PROXY=1, TRUST_PROXY_HOPS=2

Do not set TRUST_PROXY=1 without a proxy: anyone could then send a made-up address and step around the limits.

10nginx instead of Caddy

If you already run nginx, a site block like this does the same job (the certificate comes from your usual tool, for example certbot):

server {
    listen 443 ssl;
    server_name leads.your-agency.com;
    # ssl_certificate and ssl_certificate_key lines from your certificate tool
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

11Firewall

Open only ssh, 80 and 443. With HOST=127.0.0.1 port 8080 is not reachable from outside anyway.

sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable

12Next

Open Get started in the console and fill in the settings it lists (The console), then run your first search (Finding businesses). A health check for monitoring tools answers at /healthz with {"ok":true}.