Title: How to setup your own IPFS private network
Author: Solène
Date: 21 August 2026
Tags: linux network ipfs
Description: In this article, you will learn how to set up your own
IPFS private network.
# Introduction
In this blog post, you will learn how to make a private IPFS network
that will allow private peers to exchange data between each other.
This is in opposition to the default setup in which you use the default
configuration connecting to the whole IPFS network. The incentive to
have your own network is mostly speed, because this does not have any
extra access control, any peer can potentially access to any content
you have in your IPFS network.
If you do not know about IPFS, I wrote some blog posts, but otherwise
IPFS website may give you some clue. It is not easy to grasp, but you
can see it as a network service providing content addressed object
storage. The base blocks provide features to manage data in the
network but also cache it or provide it through a web gateway.
(HTM) IPFS project official website
Kubo is the reference implementation of IPFS.
The setup I explain in this article is pretty much useless for most
people. Depending on your needs, you will have a better experience
with Nextcloud/Seafile for central file sharing, Peergos for encrypted
storage, syncthing for directory synchronization between peers, or even
magic wormhole for one-shot transfers. I am still not sure which
purpose an IPFS private swarm serves correctly, but none of the use
cases I just listed, maybe it is useful if you need to keep some
dataset synchronized and quickly available in multiple areas, but then
an hyperscaler may be more suited.
# Setup
In this setup, you will have various nodes that can speak to each other
(through a VPN, LAN or directly over the Internet) and potentially but
not mandatory, a node that is up 24/7.
They must all share the same `swarm.key` to create a swarm (a group of
nodes, that is private until you get access to the key).
The setup itself will allow nodes to publish data and give it access to
other nodes for caching, downloading or relaying, but also give the
opportunity to publish on a web gateway.
# Too Long Didn't Read
IPFS daemon will hold data until it reaches its maximum allowed size,
then will run a garbage collector to reclaim disk space by removing
unused data. Data which was pinned on the server will never be garbage
collected. A directory or file is content addressed, this mean is has
a unique address derived from its content, which mean the URL of a
resource depends on its content, if you update a directory, it will get
a new URL because its content changed.
IPFS has a mechanism called IPNS which allows to publish a content hash
under a fixed hash, which is published to other peers under some
conditions, this is the only way to provide an address that never
change but in which you can change the content. An IPNS address
requires an associated cryptographic key that is managed by kubo, if
you want to pin a resource for each people you share data with, you
will need a dedicated key for each.
Data do not propagate magically over IPFS, if you add data to your
node, it remains local until another node pulls in the content, then it
will be able to distribute the data too, but there is a high chance it
gets garbage collected one day if the node owner do not pin your data.
IPFS has no at rest encryption or access control available, it is a
method to publish data.
# Configuring a node
First, you need to install Kubo, make sure to not install kubo-desktop
which is unfortunately incompatible with a private swarm.
I personally prefer to use it in a container version for sandboxing
reasons.
Generate the swarm.key with this code:
```
echo -e "/key/swarm/psk/1.0.0/\n/base16/\n$(openssl rand -hex 32)" > swarm.key
```
Download the ipfs-webui which is normally downloaded by kubo from the
IPFS network, but as you are not connecting to it, you need to inject
the webui in your kubo. On the following URL, download the "car" file
that matches your kubo version.
=> https://github.com/ipfs/ipfs-webui/releases
Now, create and init your IPFS daemon using this script, if you do not
use podman and prefer to use `ipfs` binary, replace the long podman
command by just `ipfs`.
The script takes `swarm.key` as the first parameter and the web-ui car
file as a second parameter:
```
#!/bin/sh
set -xe
if ! test -f "$1"
then
echo "You must give the swarm.key file in parameter"
exit 1
fi
if ! test -f "$2"
then
echo "You must give the ipfs-webui@v4.13.0.car file in parameter (version should match your kubo version)"
echo "You can download it from https://github.com/ipfs/ipfs-webui/releases"
exit 1
fi
# execute commands with ipfs
run() {
podman run --replace --name kubo \
-e LIBP2P_FORCE_PNET=1 -e IPFS_PROFILE=lowpower \
--userns=keep-id \
-v $HOME/.ipfs/:/data/ipfs:Z \
docker.io/ipfs/kubo:release $*
}
# import webui, requires stdin
import_webui() {
podman run --replace -i --name kubo \
-e LIBP2P_FORCE_PNET=1 -e IPFS_PROFILE=lowpower \
--userns=keep-id \
-v $HOME/.ipfs/:/data/ipfs:Z \
docker.io/ipfs/kubo:release dag import < "$1"
}
# make sure the directory exist
# you can adjust if you want to store it elsewhere
mkdir -p ~/.ipfs
# copy the swarm key
cp "$1" ~/.ipfs/swarm.key
# uncomment this if you do not use the container version which does it automatically
#run init
# allow server to give other peers address
run config Routing.Type dht
# allow other peers to relay if a peer is not directly reachable by us but another peer can
run config --json Swarm.RelayClient.Enabled true
# remove all the default stuff
run bootstrap rm --all
run config --json Routing.DelegatedRouters '[]'
run config --json Bootstrap '[]'
# private swarm key = TLS can not be used but it is still encrypted
run config --json AutoTLS.Enabled false
run config --json AutoConf.Enabled false
# allow to use IPNS through pubsub and advertise often
run config --json Ipns.UsePubsub true
run config Ipns.RecordLifetime 240h
run config Ipns.RepublishPeriod 1m
run config Ipns.MaxCacheTTL 1m
import_webui "$2"
echo "Setup successful"
echo "You can visit http://localhost:5001/webui/ after starting the server"
```
Now, start the server (use `ipfs daemon` and the environment variables
if not using the container):
```
podman run --replace --name kubo --restart=always \
-e LIBP2P_FORCE_PNET=1 \
-e IPFS_PROFILE=lowpower \
-p 8080:8080 -p 127.0.0.1:5001:5001 -p 4001:4001 -p 4001:4001/udp \
--userns=keep-id \
-v $HOME/.ipfs/:/data/ipfs:z docker.io/ipfs/kubo:release
```
On the webui, in the Peers menu, add your other peers.
# 24/7 server specific setup
The snippet above will work for a server, but you want to change a few
things:
If you use a container with restricted network, you need to give a
reachable IP address to announce to your other peers:
```
ipfs config --json Addresses.Announce '["/ip4/192.168.1.166/tcp/4001"]'
```
You may also want it to be the DHT server to allow peers to discover
each others through it, and maybe relay data between peers which could
not connect directly:
```
# allow to give other peers address for mesh networking
ipfs config Routing.Type dhtserver
# allow to relay data between two peers that could not connect to each other
ipfs config --json Swarm.RelayService.Enabled true
```
You may also want to limit the amount of storage allowed in your Kubo
server before the garbage collector free some space:
```
ipfs config Datastore.StorageMax "50GB"
```
# Networking
There are 4 differents ports in use that you need to be aware of:
* Port 4001 TCP and port 4001 UDP are used by peers to exchange data
between each other
* Port 5001 TCP is used to reach the admin API and the webui, do not
expose it publicly
* Port 8080 TCP is used for the gateway, it allows to expose your IPFS
private network content to people able to reach the gateway, without
them installing kubo at all
# Conclusion
In my use case, I have a script regularly pinning a list of IPNS
addresses on the server running the HTTPS gateway, so it always
download the latest version of the IPNS published resources and make
them available through the gateway even if the computers owning the
file is offline.
This is actually not super useful as I could have done the same thing
using Nextcloud, or with a script copying the files to a static HTTPS
server.
# Going further
This infrastructure got more useful after adding a single
`ipfs-cluster` service near my gateway running 24/7 allowing the nodes
to use it as a remote pinning service. Now, a node can pin a CID on
the gateway which make sure the data will be available locally there.