Run an API Node
For the pixagram-node repository at commit 4a271e8: hived and HAF 1.30.0, Hivemind mainnet. The six public nodes behaved as this stack does when checked on 2026-10-05. The full stack could not be run on the test machine; its configuration was checked with docker compose config.
An API node serves the chain to apps: balances, history, feeds, communities. The Pixagram app works only through API nodes, so each new one adds capacity and a place to fail over to, and a node near its users makes the app faster for them. This page sets one up, explains what each part does, and covers its ports, upgrades and the gateway's behaviour. An API node produces no blocks; for that, see Become a Witness.
What the stack runs
Internet → Caddy (TLS) → Jussi (routing, renames) → hived (chain calls)
→ Hivemind (social calls) ← HAF (hived + PostgreSQL)
| Service | Image | Job |
|---|---|---|
pixagram |
pixadock/pixagram:1.30.0 |
hived with the chain API plugins and account history |
pixagram_haf |
pixadock/pixagram-haf:1.30.0 |
A second hived that writes every block into PostgreSQL |
hivemind_setup |
pixadock/hivemind:mainnet |
Creates Hivemind's schema and roles, once |
hivemind_sync |
pixadock/hivemind:mainnet |
Indexes blocks from HAF |
hivemind |
pixadock/hivemind:mainnet |
Serves bridge.*, follow_api.*, tags_api.* |
jussi |
openresty/openresty:alpine |
Routes each call and renames fields (Differences from Hive) |
ssl-proxy |
caddy:alpine |
TLS, certificates, compression |
init_permissions |
alpine:3.20 |
Fixes file ownership, once |
Chain Architecture explains how a call travels through them.
Size the server
Recommended: 4 vCPU, 16 GB of memory, 100 GB SSD, on Linux x86-64 (Run a Node). On the pre-launch network the stack used 5.4 GB of memory and 0.21 vCPU when idle, 2.46 vCPU at peak during the first sync, and about 15 GB of disk with its images.
Retune PostgreSQL below about 24 GB of memory. HAF ships PostgreSQL configured for Hive's full chain, with 16 GiB of shared buffers, and PostgreSQL does not start if it cannot reserve them. The repository has an override directory, mounted and read last; Set it up creates the file there before the first start.
Before you start
-
Prepare the server as in Run a Node: Docker, a synchronized clock.
-
Open ports 80, 443, 2001 and 2002 (TCP) in your provider's firewall.
-
Point a name at the server. At your domain registrar, create an A record such as
api.example.comwith the server's IPv4 address, and wait until it resolves:Shell
dig +short api.example.comExpected output: the server's address. Caddy requests a certificate as soon as it starts, and failed requests count against the domain's limits at Let's Encrypt.
Set it up
Shellgit clone https://github.com/pixagram-blockchain/pixagram-node.git
cd pixagram-node
echo 'SITE_ADDRESS=api.example.com' > .env
chmod 600 .env
If the server has less than about 24 GB of memory, retune PostgreSQL now (why); raise the values in proportion on a larger machine:
Shellcat > pixagram-haf/haf_postgresql_conf.d/local.conf <<'EOF'
shared_buffers = 2GB
effective_cache_size = 4GB
maintenance_work_mem = 512MB
EOF
Then start everything:
Shelldocker compose up -d
docker compose logs -f pixagram_haf
- Without
SITE_ADDRESSCaddy serves plain HTTP on port 80 and requests no certificate. The default is deliberate: a template that names a real domain would make every unedited copy request certificates it cannot obtain. - The first sync pulls the chain over P2P twice, once for hived and once for HAF, and indexes it into PostgreSQL and Hivemind.
hivemind_setupruns once and must exit with code 0 beforehivemind_syncandhivemindstart. Do not restart the stack while it runs.- Jussi may restart for up to a minute after a cold start. It looks up Hivemind's address when it loads its configuration and fails while Hivemind is still starting; its restart policy brings it back.
Close the local ports
docker-compose.yml publishes four ports meant for the machine itself on every interface: hived's HTTP (7777), Hivemind (7778), HAF's HTTP (7779) and HAF's websocket (8092). Docker writes its own firewall rules, so the server's firewall (ufw, for example) does not close them. Either block them in your provider's firewall, or bind them to the machine itself with docker-compose.override.yml:
YAMLservices:
pixagram:
ports: !override
- "127.0.0.1:7777:7777"
- "2001:2001"
pixagram_haf:
ports: !override
- "127.0.0.1:7779:7778"
- "127.0.0.1:8092:8092"
- "2002:2002"
hivemind:
ports: !override
- "127.0.0.1:7778:8080"
Shelldocker compose up -d
!override replaces the port list instead of adding to it, and needs Docker Compose 2.24.4 or newer. An override file is not tracked by git, so git pull leaves it alone.
| Port | Open to | Purpose |
|---|---|---|
| 80, 443 | everyone | The public API, and certificate renewal |
| 2001 | everyone | hived's peers |
| 2002 | everyone | HAF's peers |
| 7777, 7778, 7779, 8092 | this machine only | Direct access to hived, Hivemind and HAF, bypassing the gateway |
Check that it serves
From any machine:
Shell# the chain layer
curl -s -X POST https://api.example.com -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"condenser_api.get_dynamic_global_properties","params":[],"id":1}'
# the social layer
curl -s -X POST https://api.example.com -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"bridge.get_ranked_posts","params":{"sort":"created","tag":"","limit":1},"id":1}'
-
The first call's
head_block_numbershould matchhttps://api.pixagram.comwithin a block or two, and its fields should readcurrent_pxs_supply, notcurrent_hbd_supply. That shows the gateway's renames work. -
The second call should return one post.
-
Hivemind's own progress is in PostgreSQL. On a healthy node it equals the head block:
Shell
docker compose exec pixagram_haf psql -U haf_admin -d haf_block_log -tAc \ 'SELECT last_completed_block_num FROM hivemind_app.hive_state'
What the gateway changes
Jussi renames Hive's field names to Pixa's in every response, and some of them back in requests (the full list). Two consequences matter to operators:
- Clients expect the same API on every public node. Change
jussi/nginx.confthrough the repository, so that every node changes together, not on one node alone. - The renames apply to the whole body, text included. Until that is fixed, a transaction whose text contains a renamed name fails to broadcast through any node running this gateway (known issue).
Run it day to day
Shelldocker compose ps # all long-running services should be "running"
docker compose logs -f hivemind_sync # indexing progress
docker compose restart jussi # if bridge.* calls return 502
- After a reboot every long-running service starts again by itself (
restart: unless-stopped).init_permissionsandhivemind_setupstay stopped; they run once. - Keep
.envand the data directories out of git. The repository's.gitignorecovers them; the data directories hold your peer list and logs. - If
Permission deniedappears at start, run the stack's own ownership fix again:docker compose run --rm init_permissions. Do notchownall of./pixagram-hafyourself: PostgreSQL's data inpixagram-haf/haf_db_storemust keep its own owner, and the fix leaves it alone.
Upgrade
A new hived version needs a replay of the consensus node, and HAF and Hivemind rebuilt from scratch, because HAF cannot replay into a database that already holds blocks. The whole chain resyncs in minutes. The repository's README gives these steps for the move to 1.30.0 at hardfork 30 (2026-10-07); a node left on 1.29.0 applies the old rules from block 949,330 and drifts from the network.
Shellgit pull
docker compose pull pixagram pixagram_haf
# 1. hived: rebuild the state from the block log, then start normally
docker compose stop pixagram
HIVED_EXTRA_ARGS="--force-replay --exit-before-sync" docker compose run --rm --no-deps pixagram
docker compose up -d pixagram
# 2. HAF and Hivemind: drop their derived data and resync them together
docker compose stop pixagram_haf hivemind_sync hivemind hivemind_setup
docker compose rm -f pixagram_haf hivemind_sync hivemind hivemind_setup
sudo rm -rf pixagram-haf/haf_db_store pixagram-haf/blockchain pixagram-haf/logs pixagram-haf/p2p
docker compose up -d
# 3. Jussi keeps Hivemind's old address and answers 502 on bridge.* until restarted
docker compose restart jussi
- HAF is healthy within a few minutes;
hivemind_synclogs live blocks after 10 to 15 minutes. - Start Hivemind together with HAF, as above. Started against a HAF that has already synced, its hand-over to live indexing has failed on
hive_notification_cache_pkey. - The
rm -rfline keepspixagram-haf/haf_postgresql_conf.d/and yourlocal.conf.
Get listed
Once both checks pass, ask the maintainers to add your node to the app's node list (DEFAULT_NODES), and name it on your witness page if you run one. A node in a region the others do not cover, such as Africa or South Asia on 2026-10-05, helps users there most.
Sources
- Repository
pixagram-blockchain/pixagram-nodeat commit4a271e8:README.md(sizing, PostgreSQL, setup, verification, restarts, upgrade),docker-compose.yml(services and published ports),ssl-proxy/Caddyfileandjussi/nginx.conf. - Override syntax: Docker's Merge Compose files (
!overriderequires Compose 2.24.4); the override above checked withdocker compose configon 2026-10-05. - Public nodes: the gateway's renames, request limit, compression and method list, compared on all six on 2026-10-05; locations from the app's node list.