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:
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.
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.
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.
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
- A Linux server (VPS, home server, whatever) on x86-64 or 64-bit ARM - an ARM VPS or a Raspberry Pi 4 or 5 with a 64-bit OS works too - with Docker and the
docker composeplugin installed. - A domain name (or subdomain) pointed at that server's IP address - an "A record" in your DNS settings. Caddy uses it to get the HTTPS certificate that protects your team's passwords in transit.
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:
- "Couldn't verify the key with keygen.sh" - the app
can't reach our license service. Check the machine has outbound HTTPS
(a VPN or corporate proxy can block it), that its clock is right, and
on a server, that the app's
networks:line includesdefault. - "Licensing is not configured for this deployment" - the
KEYGEN_ACCOUNT_IDline is missing from your Compose file. Add it back and rundocker compose up -d. - "keygen.sh says: … (SUSPENDED)" or "(EXPIRED)" - the subscription was cancelled or has lapsed.
- "keygen.sh says: … (NOT_FOUND)" - the key doesn't exist. Copy it again straight from the email, all of it.
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.