Run Freenet in Docker

Freenet publishes an official container image for every release. It is built for linux/amd64 and linux/arm64, so it runs on an ordinary server, a NAS, or a Raspberry Pi.

This page is for running a peer on a machine you administer. If you just want to use Freenet on your own computer, the normal install is simpler and does more for you.

Start a node

docker run -d --name freenet-node --network host \
  -v freenet-data:/data --restart unless-stopped \
  ghcr.io/freenet/freenet-core:latest

Then open http://127.0.0.1:7509/ to reach the node’s dashboard and any Freenet app it is serving.

Or, with a compose.yml:

services:
  freenet-node:
    image: ghcr.io/freenet/freenet-core:latest
    network_mode: host
    volumes:
      - freenet-data:/data
    restart: unless-stopped
    stop_grace_period: 45s

volumes:
  freenet-data:
docker compose up -d
docker compose logs -f

It keeps itself up to date

You do not need Watchtower, a cron job, or a habit of running docker compose pull. A container started once stays current on its own.

This matters more than it does for most software. Freenet ships releases frequently, sometimes several times a day, and a peer that falls too far behind is refused by the rest of the network rather than merely missing features. So the container applies updates itself, the same way the desktop install does.

Pulling a newer image is still worth doing occasionally, so a fresh container starts from a recent version instead of updating on first boot:

docker compose pull && docker compose up -d

Your node’s data lives in the freenet-data volume and survives that, along with any update the node has already applied to itself.

To see which version is actually running:

docker exec freenet-node freenet --version

Why --network host

Two things break under Docker’s default bridge network, and neither is obvious from the outside.

The dashboard becomes unreachable. Freenet’s local API binds to loopback, which under bridge networking is the container’s loopback rather than your machine’s. Nothing on the host can reach it, and publishing the port does not help, because the API is not listening on an address that port forwards to.

Peer-to-peer connectivity degrades. Freenet peers talk over UDP and rely on hole punching. Bridge networking rewrites the source port of outgoing packets, so it no longer matches the port other peers were told to use.

Host networking avoids both. It needs Linux; Docker Desktop on macOS and Windows does not support it in the same way.

If you cannot use host networking

This works, with the caveat that the node contributes capacity to the network but cannot serve apps to your browser:

services:
  freenet-node:
    image: ghcr.io/freenet/freenet-core:latest
    ports:
      - "31337:31337/udp"
    volumes:
      - freenet-data:/data
    restart: unless-stopped
    stop_grace_period: 45s

volumes:
  freenet-data:

Ports

PortProtocolPurpose
31337UDPPeer connections. Other peers reach you here.
7509TCPDashboard and local API. Loopback only.

Port 7509 is deliberately not exposed to your network. It can read and modify contract state, identities and key material, so treat it like a database socket rather than a web page. If you need to reach it from another machine, put an authenticating reverse proxy in front of it.

Checking on it

docker compose logs -f                                    # what the node is doing
docker inspect --format '{{.State.Health.Status}}' freenet-node
docker exec freenet-node ls /data/logs                    # rotating log files

The health status reports whether the node is up and serving. It does not tell you how well connected it is.

Full reference

The container README covers the remaining details: every environment variable, running under a different user, how the image is built and verified, and how the self-update supervisor works.