Pubky Testnet
A local test network for developing Pubky homeserver or applications depending on it.
To build a testnet Docker image, see Docker build options.
Quick start
Start Postgres if you don't already have one running:
For more Postgres setup options see the Install Guide — Set Up PostgreSQL.
Run a local testnet with persistent state:
TEST_PUBKY_CONNECTION_STRING='postgres://postgres:postgres@localhost:5432/postgres' \
The data directory is auto-initialized on first run with a config.toml and server keypair. On subsequent runs, the existing state is picked up and the homeserver keeps the same identity.
The TEST_PUBKY_CONNECTION_STRING environment variable is read on every startup and overrides the database_url in the on-disk config.
To seed a custom homeserver config on first run (errors if config.toml already exists):
TEST_PUBKY_CONNECTION_STRING='postgres://postgres:postgres@localhost:5432/postgres' \
If you don't need persistent state, simply omit the persist subcommand. An ephemeral database is auto-created on startup and cleaned up on shutdown:
TEST_PUBKY_CONNECTION_STRING='postgres://postgres:postgres@localhost:5432/postgres' \
Ports and addresses
| Component | Port |
|---|---|
| DHT bootstrap node | 6881 |
| Pkarr relay | 15411 |
| HTTP relay | 15412 |
| Homeserver ICANN HTTP | 6286 |
| Homeserver Pubky HTTPS | 6287 |
| Homeserver admin | 6288 |
Homeserver address: 8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo
The CLI uses [StaticTestnet] under the hood — see the type's rustdoc for programmatic use.
Writing tests (EphemeralTestnet)
For automated Rust tests, use [EphemeralTestnet]. Each instance gets its own isolated DHT and homeserver with random ports, so tests run in parallel without conflicts.
use EphemeralTestnet;
// Cleans up ephemeral Postgres databases after the test
async
Postgres for tests
You need a running PostgreSQL instance (see Quick start for a Docker one-liner). By default, EphemeralTestnet reads the TEST_PUBKY_CONNECTION_STRING environment variable:
TEST_PUBKY_CONNECTION_STRING='postgres://postgres:postgres@localhost:5432/postgres' \
Each test automatically gets its own ephemeral pubky_test_{uuid} database on the configured server. The #[pubky_testnet::test] macro ensures the database is cleaned up after the test completes or panics.
You can also pass the connection string programmatically:
use ;
async
Docker Postgres
To avoid managing Postgres yourself, enable the docker-postgres feature. This uses testcontainers to run PostgreSQL in a Docker container that is automatically cleaned up on drop and on Ctrl+C/SIGTERM. Docker must be running on the host.
[]
= { = "<version>", = ["docker-postgres"] }
#
#
#
use EphemeralTestnet;
#
async
Important: If you have multiple tests, see Sharing Docker Postgres Across Tests below.
Sharing Docker Postgres Across Tests
Each .with_docker_postgres() starts a separate container. To avoid that overhead,
use DockerPostgres::shared() to start one container and reuse it. Tests remain isolated
— each testnet gets its own ephemeral database.
#
#
Custom Configuration
use ;
async