Getting started¶
This page takes a Raspberry Pi with nothing on it to a stack that is measuring your internet connection and drawing it, in seven numbered steps. Each step says what you should see when it worked, so you never have to guess whether to go on. Budget 20 minutes, most of it waiting for Docker to pull images.
At the end you will have:
- SmokePing measuring 21 targets every 300 seconds — 10 pings per cycle for ICMP, 5 for DNS, HTTP and TCP,
- Grafana dashboards on
:3000and a web admin on:8080, - a
smoking-picommand for everything afterwards — start, stop, upgrade, backup, passwords, doctor, - optionally, an assistant you can ask "how's my internet?" (step 7).
The guide is written for Raspberry Pi OS (64-bit), the reference platform. Ubuntu 22.04/24.04 and Debian 12/13 work the same way and are checked on every release; the one difference is in step 1. macOS is untested.
Already have a clone running?
Nothing here asks you to move. A checkout keeps working exactly as it did — see From a clone in step 2, and Upgrading for going from one release to the next.
Step 0 — What you need¶
| Minimum | Comfortable | |
|---|---|---|
| Board | Raspberry Pi 4, 2 GB | Raspberry Pi 5, 4 GB |
| Storage | 16 GB SD card | 32 GB+, or an SSD over USB |
| OS | Raspberry Pi OS 64-bit (Bookworm), Ubuntu 22.04+, Debian 12+ | same |
| Network | Ethernet or Wi-Fi, outbound ICMP not blocked | Ethernet |
Two things are worth knowing before you start:
- Outbound ICMP is the whole point. If your network blocks pings, every
target will read 100% loss and nothing else will be wrong. Test it first:
ping -c3 google.com. - A year of measurements is a few GB. They live in Docker volumes, which
survive
apt removeand are only ever deleted when you ask explicitly (smoking-pi purge). An SD card will do; an SSD will do it longer.
Step 1 — Docker with the Compose plugin¶
Smoking Pi runs everything in containers, so Docker Engine and the Compose v2 plugin are the only prerequisites. Check what you have:
docker compose version
Expected:
Docker Compose version v2.38.2
If that prints docker: 'compose' is not a docker command (or Docker is
missing entirely), install it from Docker's own repository:
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
newgrp docker
Raspberry Pi OS and Debian 12 need Docker's repository
Debian 12 — today's Raspberry Pi OS — ships no Compose v2 at all:
apt install docker.io gets you a 20.10 daemon and the Python
docker-compose 1.29, which cannot read these compose files. This is
measured, not assumed; the full host matrix is in
Supported hosts. Debian 13, Ubuntu
22.04 and 24.04 have a usable Compose v2 in the distribution.
The usermod line lets you run Docker without sudo. It takes effect on
your next login; newgrp docker gives it to you in the current shell.
Step 2 — Install Smoking Pi¶
From the apt repository (recommended)¶
Three lines add the repository, one installs the package:
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://estcarisimo.github.io/smoking-pi/apt/smoking-pi.gpg | sudo tee /etc/apt/keyrings/smoking-pi.gpg >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/smoking-pi.gpg] https://estcarisimo.github.io/smoking-pi/apt ./" | sudo tee /etc/apt/sources.list.d/smoking-pi.list
sudo apt update && sudo apt install smoking-pi
Check it:
smoking-pi version
Expected: the release number, e.g. 2.12.0.
The package installs the code under /opt/smoking-pi, a smoking-pi
command in /usr/bin, and a systemd unit. It does not start anything
yet — step 3 does that, after you have chosen what to run.
One-off install without the repository
Every GitHub release
attaches the same .deb:
sudo apt install ./smoking-pi_<version>_all.deb. You lose
apt upgrade as the way to get the next release.
From a clone¶
A checkout is the development path and the way to run an unreleased branch.
It needs git and nothing else:
git clone https://github.com/estcarisimo/smoking-pi.git
cd smoking-pi
./cli/smoking-pi link # if it says "open a new terminal", do that first
smoking-pi version
link makes smoking-pi a command in every directory: a symlink to the
checkout's cli/smoking-pi in /usr/local/bin (through sudo when
it asks no password), else in ~/.local/bin (open a new terminal if it
says that is not on your PATH yet). setup.sh, smoking-pi install and upgrade
do the same, so a clone installed before link existed gets it at its
next upgrade. It never shadows the package's /usr/bin/smoking-pi.
From a clone the images are built locally rather than pulled (checked
out on a release tag, git checkout v2.13.0, it pulls that release's),
sudo is not needed (the env file is yours), and the state stays beside the
edition's compose file instead of under /etc. Everything else in this
guide is identical.
macOS¶
A Homebrew formula exists and has never been run on a Mac:
brew tap estcarisimo/smoking-pi https://github.com/estcarisimo/smoking-pi
brew install smoking-pi
It needs Docker Desktop, and be aware of what it costs you: on Docker
Desktop network_mode: host is the Linux VM, not your Mac, so Pro's first
hop and Wi-Fi measurements describe the VM. Basic and Standard are
unaffected. If you try it, say how it went.
Step 3 — Choose what to run¶
sudo smoking-pi install
This asks three questions (with whiptail menus if it is installed,
--edition/--database/--profiles flags if you prefer, --yes for
nothing at all), then generates every password and API token, detects your
timezone and starts the containers. Then it sets up each optional service
you picked, enables the service that starts Smoking Pi at boot, and prints
what to open. The passwords are never printed; the end of this step says
how to read them.
Which edition? Pro is preselected.
| Edition | For | What you get |
|---|---|---|
| basic | One box, one person | SmokePing, targets in a YAML file, the classic web UI, RRD storage |
| standard | A small team | + web admin with login, PostgreSQL as the source of truth, a REST API |
| pro | Everything | + Grafana, InfluxDB or ClickHouse, HTTP/TCP/DNS/IPv6 probes, Wi-Fi stats, alerting, MCP server, AI reports, the doctor |
Pick pro unless you know you want less; this guide assumes it. Each edition has its own volumes, so moving up later is a new install of the bigger edition, not a conversion.
Which time-series backend? InfluxDB, unless you have a reason — ClickHouse works but is the less traveled path.
Which optional services? Alerts comes preselected; the other three are off unless you pick them. Each one needs something only you can give, and install asks for it right after the containers start, with the command that owns that service:
| Profile | What it adds | What install asks |
|---|---|---|
mcp |
An MCP server, so an assistant can query your history | which assistant: OpenClaw on this Pi, one on the Internet (Claude, ChatGPT, Grok...) or OpenClaw elsewhere; step 7 |
alerts |
Downtime, microcut and Wi-Fi alerts | where they go: Telegram, OpenClaw, a webhook or nowhere (smoking-pi alerts, Alerting) |
ai |
Written health reports | an Anthropic API key, typed, not shown (AI reports) |
dns |
The DNS observer: what this house actually uses | nothing; it prints the DNS setting to change on your router (DNS observer) |
Skip a question, or install with --yes (which asks nothing), and the end
of the install lists the same commands under Still to do. The DNS
observer asks nothing either way: it starts, and the router setting is
listed. You can turn any service on or off afterwards:
smoking-pi enable # which are on
sudo smoking-pi enable mcp alerts # records them, starts them
sudo smoking-pi disable alerts
Every other setting is changed by name with config, which checks the
value before writing it and recreates just the services that read it:
sudo smoking-pi config list # every setting, by section; secrets hidden
sudo smoking-pi config list alerts # one section
sudo smoking-pi config describe WEEKLY_AT
sudo smoking-pi config set WEEKLY_AT 07:30
describe says what a setting does, what it takes (a number in a range,
true or false, one of a list, a time), its default and which services read
it; set refuses a value of the wrong kind rather than leave a container
failing on it. A secret such as ANTHROPIC_API_KEY is typed at a prompt,
never on the command line:
sudo smoking-pi config set ANTHROPIC_API_KEY
Settings generated at install (database passwords, tokens, the backend) are refused: the data volumes hold them.
Expected, at the end: what to open, as the last thing on the screen.
Starts at boot: the smoking-pi service is enabled.
Installed: the pro edition. The first measurements arrive after one
300-second step; then 'sudo smoking-pi doctor --live' checks that they do.
Open Smoking Pi:
Web admin http://192.168.1.27:8080/ (user admin)
Grafana http://192.168.1.27:3000/ (user admin)
Passwords: sudo smoking-pi passwords --show-secrets (on this machine)
Open it on the computer you are connected from (192.168.1.30), not in this terminal.
Also, from most computers on this network: http://smoking-pi.local:8080/
If you installed over SSH, the address is the one your computer reached
the Pi at, not localhost — which, typed on your laptop, is your laptop.
install waits up to two minutes for the page to answer before printing it,
and says so if it still doesn't: the first start can take longer while
images download. sudo smoking-pi url prints the same block, and checks
again, whenever you need it.
Finding it later without its address. Every edition answers for
smoking-pi.local on the local network: http://smoking-pi.local:8080/
(Basic: http://smoking-pi.local/). A second Smoking Pi on the same
network gets smoking-pi-2.local; sudo smoking-pi url prints the name
it holds, and MDNS_NAME changes it (The Pi's name on the
network).
When Avahi runs on the Pi (it
does on Raspberry Pi OS), install, up and upgrade announce the stack
on the local network with DNS-SD. From any Linux machine on the same
network that has the command:
smoking-pi discover
Smoking Pi on raspberrypi
http://raspberrypi.local:8080/ (192.168.1.27, pro 2.14.1)
It needs avahi-browse (sudo apt install avahi-utils). On a Mac,
dns-sd -B _smoking-pi._tcp lists the same announcements. A network that
blocks multicast (a guest Wi-Fi, client isolation) hides it: use the
address above.
The record holds no password or token, but everyone on the network can
read it: the page's port, the edition, the version and, on Pro,
Grafana's port. On a shared or office network you may not want that. Set
SMOKING_PI_ANNOUNCE=0 in /etc/default/smoking-pi (or in the
environment of the command) and the next up withdraws it. It is written
by install, up and upgrade when they run as root (the systemd unit
does at every boot), withdrawn by down, and removed when the package is
uninstalled.
The secrets are set but not printed: an install transcript is the last place a password should live. Read them when you need them:
sudo smoking-pi passwords --show-secrets
Without --show-secrets it shows every service's address and status,
and every secret as set (hidden), which is still the answer to "did the
token get generated?". --show-secrets refuses to write into a pipe or a file
unless you add --force, so a password does not end up in a log or a
pasted issue by accident.
install runs once, deliberately
Run over an existing env file, install refuses and tells you to use
smoking-pi up. This is not caution for its own sake: it would
regenerate every secret, and the database volumes still hold the old
ones — a stack that no longer starts. Starting over on purpose is
smoking-pi purge --config.
Step 4 — Check that it starts at boot¶
A package install enables the smoking-pi service itself (Starts at
boot above). Check it:
systemctl is-enabled smoking-pi # enabled
systemctl is-active smoking-pi # active
On a package install, disabled means install could not enable it (it
said so):
sudo systemctl enable --now smoking-pi. The unit is a oneshot that runs
smoking-pi up and stays "active": it brings the stack up after a reboot
and hands the rest to Docker's own restart policies. From a clone there is
no unit — use smoking-pi up, or install one from packaging/systemd/.
Step 5 — Check that it is actually working¶
Four checks, in the order that finds problems fastest.
Packaged: these commands need sudo
The package keeps your secrets in /etc/smoking-pi/env, inside a
directory that is 0750 and owned by root — which is the point of
putting them there. Every smoking-pi command that reads it (status,
passwords, up, logs, doctor --live, …) therefore runs under
sudo; without it Compose stops at permission denied on the env file.
From a clone the env file is yours and no sudo is needed anywhere.
1. Every container is up.
sudo smoking-pi status
Expected, for Pro on InfluxDB with no optional profiles — six
services, five of them (healthy) (SmokePing has no health check; each
optional profile from step 3 adds one more service). Columns trimmed here;
the real output also carries IMAGE, COMMAND, CREATED and PORTS:
NAME SERVICE STATUS
pro-config-manager-1 config-manager Up 2 minutes (healthy)
pro-grafana-1 grafana Up 2 minutes (healthy)
pro-influxdb-1 influxdb Up 2 minutes (healthy)
pro-postgres-1 postgres Up 2 minutes (healthy)
pro-smokeping-1 smokeping Up 2 minutes
pro-web-admin-1 web-admin Up 2 minutes (healthy)
A container that is Restarting is the one to look at:
sudo smoking-pi logs <service>.
2. The URLs answer.
sudo smoking-pi url
It prints the address to open and exits non-zero if nothing answers there.
sudo smoking-pi passwords lists every service's address.
For Pro: SmokePing on http://<pi>/, the web admin on http://<pi>:8080,
Grafana on http://<pi>:3000, InfluxDB on http://<pi>:8086. Log in to
Grafana with admin and the password from sudo smoking-pi passwords
--show-secrets.
3. Data arrives — after five minutes, not before.
SmokePing's step is 300 seconds, so the first point of every graph exists five minutes after the containers start, and the graphs are empty until then. That is the single most common "it's broken" that isn't. Wait, then open SmokePing and look at top_sites → Google, or, in Grafana, the Individual Pings – Latency & Loss dashboard.
Standard and Pro answer this for you: the web admin's dashboard has a
Measurements card that checks, for every configured target, when
SmokePing last wrote its data. Measuring means every target updated in
the last two steps. Anything else is listed by name: stopped updating
(it had data, and has not for a while), no data (SmokePing never wrote
any), or waiting (added a moment ago, before its first step). The same
check is GET /measurements on the config API. "SmokePing: Running" above
it only means the container is up.
4. The instrumentation agrees with itself.
sudo smoking-pi doctor --live
The doctor checks that the dashboards, the exporters, the containers and
DNS actually describe the same system — the class of problem where
everything is "up" and the graphs are still wrong. Expected: every check
ok. What each one means is in Instrumentation doctor.
Step 6 — Measure what you care about¶
The install seeds 21 targets — 5 top sites, 3 DNS resolvers, 9 HTTP
(three sites × three versions), 3 TCP handshakes and one example of your
own — and 7 probes (ping v4 and v6, DNS, HTTP/1.1, HTTP/2, HTTP/3,
TCP). Your own targets go in through the web admin on :8080 —
Targets → Add — which writes to PostgreSQL, regenerates SmokePing's
config and reloads it. The first hop is not in that list because nobody
has to add it: CPE discovery traceroutes out every hour, finds the first
responsive hop and injects it as a target of its own.
The first login is a short tour. On Standard and Pro, the web admin opens on a four-step welcome the first time: whether it is measuring, what your own network suggests adding (below), what it measures layer by layer (ping, DNS, TCP, HTTP/1.1–3, and on Pro whether the DNS observer is on), and the targets the install set up, each with a switch to pause the ones you do not care about. The install still seeds its targets, so it measures from the first minute; the tour shows them rather than replacing them, and nothing is added or paused unless you choose it. Finish or Skip for now and it stays out of the way; the dashboard's Welcome tour button brings it back.
Start with what your own network suggests. The seeded targets are the same on every install; your router and the resolvers your network hands out are not. On Pro, where SmokePing shares the host's network, the web admin's dashboard has a Your connection card that reads them from the host itself:
- the interface every measurement leaves by, and whether it is Wi-Fi;
- your router (the default gateway). Loss or delay there is your Wi-Fi or your LAN, and a problem that is fine at the router but bad further out is past your home. It is not seeded, because every home's router has a different address;
- the ISP's first hop, which CPE discovery already measures;
- the DNS resolvers the host was given. A local cache or a VPN stub
(
127.0.0.53, Tailscale's100.100.100.100) is not worth measuring and says so.
Each one says whether it is measured already, and under which name. What
is not has an Add… button that opens Targets → Add filled in: you
see the target, change it if you like, and save it through the same
validation as anything you type. Nothing is added for you. The same list
is GET /recommendations on the config API. On Standard, whose SmokePing
sits on a Docker network, the card says it cannot see the host's router
instead of showing Docker's.
Useful to know on the first day:
- Netflix's Open Connect appliances serving your network are discovered
for you; you do not have to find them. Each keeps one name per slot and
site (
Netflix_1_DFW) while Netflix hands it a different appliance every day, so its history is one curve; which appliance stood behind it, and when, is thetarget_hostmeasurement (InfluxDB; the ClickHouse exporter does not write it). - HTTP targets are per-version. Adding
example.comover HTTP/2 and HTTP/3 gives you two curves and the bare TCP handshake underneath as the floor (HTTP and TCP probes). - IPv6 targets are gated: a v6 probe is only configured if the host really has working v6, so you do not get a wall of red (IPv6 gating).
- If the Pi is on Wi-Fi, the uplink itself is measured — signal, bitrate, throughput, disconnects — so a bad hour can be blamed on the air rather than the ISP (Wi-Fi uplink stats).
- Measure what the house uses, not a generic list (Pro, opt-in). The
seeded targets are a starting point. To learn what this house actually
resolves, start the DNS observer with
smoking-pi dns enable, point the router's DNS at the Pi and confirm the path withsmoking-pi dns test. After a few days,smoking-pi dns adoptadds the highest-scoring services as targets (by query volume at first, by hours seen per week once there are three days of data). It changes nothing until the router points at it, and it sees DNS queries only, never traffic (DNS observer).
Step 7 — Connect an assistant (optional)¶
Smoking Pi is complete without this. What it adds is being able to ask, in
a chat window, "was the line bad last night?" and get an answer from
months of recorded history rather than a live ping.
It is two pieces: the MCP server (the mcp profile from step 3), which
exposes your measurements as tools, and an assistant that calls them.
One command connects either kind, and smoking-pi install offers it at the
end when mcp was picked (skipped, it is listed under Still to do):
- OpenClaw on this Pi:
sudo smoking-pi connect openclaw— the token, the profile, registration and the skill — andsudo smoking-pi connect openclaw --checkproves the agent is really using your history. OpenClaw integration explains each step for when one of them does not work. - An assistant on the Internet (Claude, ChatGPT, Grok, Cursor...): it
needs a way in, then signs in with a one-time pairing code and gets
read-only tools.
sudo smoking-pi connect --tailscalepublishes the MCP server through Tailscale Funnel, andsudo smoking-pi connect claude(orchatgpt,grok...) prints the URL, the code and that assistant's steps. Connecting any assistant covers other tunnels. - OpenClaw on another machine: OpenClaw on another machine.
The tools themselves, and what each one answers: MCP server.
Put authentication in front of anything you expose
The MCP endpoint and the web admin are on your LAN as installed. Reaching them from outside goes through a Cloudflare tunnel with authentication in front — never a port forward.
When something goes wrong¶
| What you see | Why | What to do |
|---|---|---|
docker: 'compose' is not a docker command |
Debian 12 / Raspberry Pi OS ships no Compose v2 | Step 1 — install from Docker's repository |
permission denied ... /var/run/docker.sock |
Your user is not in the docker group |
sudo usermod -aG docker "$USER", then log out and in |
install says the edition is already installed |
An env file exists; re-running would rotate every secret | sudo smoking-pi up to start it, or sudo smoking-pi purge --config to start over — that deletes the measurements |
| Graphs empty five minutes in | Nothing yet: the step is 300 s | Wait one step, then check sudo smoking-pi logs smokeping |
| Every target at 100% loss | ICMP blocked upstream, or no route | ping -c3 google.com from the host; if that fails it is the network, not Smoking Pi |
| Grafana rejects the password | Grafana keeps the first-boot password in its volume | sudo smoking-pi restart grafana, wait 30 s, try the password from sudo smoking-pi passwords --show-secrets again. If it still refuses, Grafana's volume predates that password — reset the account: sudo docker compose exec -T grafana grafana cli admin reset-admin-password --password-from-stdin |
| SmokePing's port is already taken | Pro's SmokePing is on the host network, port 80 | Free port 80, or use Basic/Standard, which map a port you can change |
| An optional service runs but does nothing | Its profile is on and its key is not set | sudo smoking-pi alerts (alerts: it sets the mode and its keys, and tests delivery) or sudo smoking-pi config set ANTHROPIC_API_KEY (ai). Neither crash-loops on a missing key — they log it and stay up, so status looks healthy while nothing is delivered |
| A container restarting in a loop | Its own logs say which | sudo smoking-pi logs <service> — read the last start, not the whole file |
| The page loads on the Pi but not from your laptop | A firewall between the two, or the laptop is on another network (a guest Wi-Fi) | Tunnel through SSH, which already works: ssh -L 8080:localhost:8080 <user>@<pi>, then open http://localhost:8080/ on the laptop. sudo smoking-pi url prints this line with your addresses filled in |
smoking-pi not found after apt install |
A shell that cached its PATH |
hash -r, or open a new shell |
Still stuck? sudo smoking-pi doctor --live is written for exactly this and
names the component rather than the symptom. Failing that,
open an issue with its
output.
What to read next¶
- Upgrading —
apt upgrade && sudo smoking-pi upgrade, and the two majors that are a data migration. - Alerting — one message per episode, only when it matters, with its cause: is it me or the internet?
- Instrumentation doctor — what each check proves.
- Packaging — the layout, the supported hosts, and the lifecycle end to end.
Backups are one command and worth doing before any upgrade:
sudo smoking-pi backup