Self-hosting with Docker

PCAPNG Analyzer runs entirely on hardware you control - nothing lives on our servers except license checks, and your capture files never leave your machine. The app's only outbound requests are that license check and a daily check for new versions; see security & privacy. Pick the setup that fits:

Just for you, on your own computer?

The desktop download is quicker: one file for Windows, macOS or Linux, with no Docker and no password to set up. The Docker setups below suit a team server or an install that runs all the time.

On your own computer

Just you, on Windows, macOS or Linux. No server, domain or HTTPS setup. About 2 minutes.

Local setup →

On a server for your team

Several people reaching it from their own browsers. Needs a Linux server and a domain name. About 15 minutes.

Server setup →

Both run the same Docker image, and either works on the Free tier (no key needed) or Pro. You can move from one to the other later by restoring a backup.

Run it on your own computer

1. Install Docker

Install Docker Desktop on Windows or macOS, or Docker Engine with the docker compose plugin on Linux. The image is built for x86-64 and 64-bit ARM, so it runs natively on Apple Silicon Macs too.

2. Create the Compose file

Make a folder anywhere (for example pcapng-analyzer in your home folder) and save this in it as docker-compose.yml:

services:
  pcapng-analyzer:
    image: smathieson/pcapng-analyzer:latest
    restart: unless-stopped
    # 127.0.0.1 = reachable from this computer only.
    ports:
      - "127.0.0.1:8088:8088"
    environment:
      AUTH_INITIAL_PASSWORD: change-me-now
      KEYGEN_ACCOUNT_ID: "54d7e608-a563-40ab-aaf0-658ee06b2110"
    volumes:
      - pcap-data:/data
    # Hardening: read-only filesystem, no Linux capabilities.
    read_only: true
    tmpfs: ["/tmp:size=64m,noexec,nosuid"]
    cap_drop: [ALL]
    security_opt: ["no-new-privileges:true"]

volumes:
  pcap-data:
    name: pcap-data

KEYGEN_ACCOUNT_ID is the same for every customer - it lets you activate a Pro key in Settings later. Staying on Free and don't want licensing wired up at all? Delete that line.

3. Start it and sign in

Open a terminal (PowerShell on Windows) in that folder and run:

docker compose up -d

Visit http://localhost:8088 and sign in as admin with the password change-me-now. The app makes you choose a new password straight away. It starts again on its own whenever Docker does.

Why no HTTPS?

Traffic to localhost never leaves your computer, so there's nothing on the network to encrypt. That's also why the port is bound to 127.0.0.1. Don't change it to expose the app on your network over plain HTTP - if colleagues need access, use the server setup instead.

Pro? Carry on with entering your license key.

Run it on a server for your team

What you need first

Using Cloudflare for your DNS?

Set the record to DNS only (grey cloud), not Proxied (orange cloud). Cloudflare's proxy rejects any upload larger than 100 MB (200 MB on its Business plan, 500 MB on Enterprise), below both the Free tier's 1000 MB cap and Pro's 5 GB, and all your browser shows is "Network error during upload". With DNS only, browsers connect straight to your server and Caddy still provides HTTPS.

1. Create the deploy directory

SSH into your server, then run this - replacing pcap.example.com with your real domain:

mkdir -p ~/pcapng-deploy && cd ~/pcapng-deploy
echo "DOMAIN=pcap.example.com" > .env
echo "ADMIN_PASSWORD=$(openssl rand -base64 24)" >> .env
chmod 600 .env

ADMIN_PASSWORD is the password your admin account starts with. There's no built-in default, so the app won't start without it.

Then create ~/pcapng-deploy/docker-compose.yml:

services:
  pcapng-analyzer:
    image: smathieson/pcapng-analyzer:latest
    restart: unless-stopped
    environment:
      AUTH_INITIAL_PASSWORD: ${ADMIN_PASSWORD}
      TRUST_X_FORWARDED_FOR: "1"
      KEYGEN_ACCOUNT_ID: "54d7e608-a563-40ab-aaf0-658ee06b2110"
    volumes:
      - pcap-data:/data
    # Hardening: read-only filesystem (data lives in the volume), no
    # Linux capabilities, no privilege escalation.
    read_only: true
    tmpfs: ["/tmp:size=64m,noexec,nosuid"]
    cap_drop: [ALL]
    security_opt: ["no-new-privileges:true"]
    pids_limit: 256
    # "internal" links it to Caddy; "default" lets it make its two
    # outbound calls - checking your license key and checking for
    # updates. Keep both.
    networks: [internal, default]
    # No "ports:" on purpose - only Caddy is reachable from the internet.

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    command: caddy reverse-proxy --from ${DOMAIN} --to pcapng-analyzer:8088
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - caddy-data:/data
    networks: [internal, default]

networks:
  internal:
    internal: true

volumes:
  pcap-data:
    name: pcap-data
  caddy-data:

Caddy gets you a free, auto-renewing HTTPS certificate for your domain and is the only container reachable from the internet. TRUST_X_FORWARDED_FOR tells the app it's behind that proxy, so it sees real client addresses and marks its cookies HTTPS-only. KEYGEN_ACCOUNT_ID works as in the local setup: the same for everyone, and deletable if you're staying on Free.

The internal network is a private link between Caddy and the app; default only gives the app outbound access for its license check (to api.keygen.sh) and update check (to api.github.com), and opens nothing inbound. Don't put the app on internal alone - that blocks license checks.

2. Start it

docker compose up -d
docker compose logs -f pcapng-analyzer   # watch it start, then Ctrl-C

You should see listening on http://0.0.0.0:8088 in the logs. If your server runs a firewall such as ufw, make sure ports 80 and 443 are allowed (and keep SSH open).

3. First sign-in

Visit https://pcap.example.com (your real domain). Sign in as admin, using the password generated in step 1:

grep ADMIN_PASSWORD ~/pcapng-deploy/.env

The app forces you to set a new password immediately, before anything else is reachable.

Enter your license key (Pro only)

No key yet? Pro has a 14-day free trial, and its key is emailed as soon as you start it.

Settings → License → paste the key you were emailed → Activate. It's checked immediately, so you'll see it unlock on the spot: full network health, explained findings, trends and first-seen context, your own threat-intel (IOC) lists, history re-scans, branded incident reports, shareable copies, watched-folder auto-ingest, alerts, SIEM export and API tokens, the 5 GB upload cap, and unlimited history. Detection already runs on Free, so captures analysed before you entered the key show their full findings straight away, with no re-analysis. (Captures analysed by an earlier release on Free need Reanalyze once.)

If it ever shows as unlicensed unexpectedly, hit Recheck on that same page before contacting support - most often it's a temporary network blip, and it self-heals within the grace period.

If a key won't activate, the License page shows why:

Next, see the guides on IOC lists and history re-scans, incident reports and the watched folder.

Keeping it backed up

Everything that matters - captures, analysis results, your login - lives in the pcap-data Docker volume. From the folder with your docker-compose.yml (these work in PowerShell, macOS and Linux alike):

docker compose stop pcapng-analyzer
docker run --rm -v pcap-data:/data -v "${PWD}:/backup" alpine sh -c 'tar czf /backup/pcap-backup-$(date +%F).tar.gz -C /data .'
docker compose start pcapng-analyzer

Stopping the app first keeps the SQLite database consistent in the archive - it's only down while the copy runs. On a server, put that in a cron job (e.g. daily) if you want it automatic.

To restore - or to move between computer and server - put the backup file in the folder with your docker-compose.yml and run:

docker compose create
docker run --rm -v pcap-data:/data -v "${PWD}:/backup" alpine sh -c 'tar xzf /backup/pcap-backup-YYYY-MM-DD.tar.gz -C /data'
docker compose up -d

docker compose create sets up an empty pcap-data volume without starting the app, so the backup goes in before first boot. Replacing an install that's already there? Run docker compose down and then docker volume rm pcap-data first - that deletes the current data, so only do it once you have the backup file.

Updating to a new version

From the same folder:

docker compose pull
docker compose up -d

Your data volume is untouched - nothing to migrate by hand.

Need help?

Email [email protected] - include your license key (if you have one) and, if something's broken, the output of docker compose logs pcapng-analyzer. Refunds: your first Pro payment is refunded in full within 14 days, no questions asked, same email address.