i2pplus

I2P+ in Docker

Quick start

If you just want to give I2P+ a quick try or are using it on a home network, follow these steps:

Pull from GitHub Container Registry

docker pull ghcr.io/i2pplus/i2pplus:latest
docker run -d -p 7657:7657 -p 7667:7667 -p 4444:4444 ghcr.io/i2pplus/i2pplus:latest

Then open http://127.0.0.1:7657 in your browser. The web console binds to 0.0.0.0 (all interfaces) inside the container, so you can also access it at your Docker host’s IP address. The I2NP external port is assigned randomly - check your router console (Network section) or router.config for the assigned port. For full network participation, you’ll need to map this port externally.

Or build locally

  1. Install git, docker-io and docker-compose via your package manager
  2. Download the I2P+ git repository with the command: git clone https://github.com/I2PPlus/i2pplus.git
  3. Copy docker/docker-compose.yml to docker-compose.yml in the root directory of your local I2P+ git workspace
  4. cd to the i2pplus git workspace and execute docker-compose up --build
  5. Start a browser and go to http://127.0.0.1:7657 and then hit the Wizard link to configure your router
  6. To stop the router, hit Ctrl+C and then, optionally, docker-compose down
  7. To remove all existing cache files and generated images, run docker system prune -a -f

Running a container

Memory usage

By default the image limits the memory available to the Java heap to 1024MB. You can override this at runtime with the -e JVM_XMX=2048m flag, or by modifying the JVM_XMX environment variable in the docker/rootfs/startapp.sh file before building.

Security

The container runs as a non-root user i2p for security. If you need to exec into the container for debugging, note that you are running as user i2p.

Custom UID / GID

By default the i2p user is created with UID 1000 and GID 1000. On most Linux systems the first user is 1000, so this works out of the box. If your host user has a different UID/GID (check with id), volume-mounted files will be owned by the container’s UID/GID instead of yours, causing permission errors.

Fix at build time with docker compose (recommended):

Create a .env file in the project root (next to docker-compose.yml):

UID=1001
GID=1001

Then rebuild:

docker compose up --build -d

Or pass build args directly:

docker compose build --build-arg UID=1001 --build-arg GID=1001
docker compose up -d

Or with plain docker build:

docker build --build-arg UID=1001 --build-arg GID=1001 -t i2pplus -f docker/Dockerfile .

Note: Changing UID/GID requires a full rebuild (docker compose build --no-cache). A previously built image with UID 1000 will still use 1000 regardless of later .env changes.

Healthcheck

The image includes a HEALTHCHECK that monitors the router every 5 minutes. You can verify container health with:

docker inspect --format='' i2pplus

Read-only root filesystem

For enhanced security, you can run with a read-only root filesystem:

docker run --read-only --tmpfs /i2p/.i2p:rw --tmpfs /i2psnark:rw ...

Ports

There are several ports which are exposed by the image. You can choose which ones to publish depending on your specific needs.

Port Interface Description TCP/UDP
4444 127.0.0.1 HTTP Proxy TCP
6668 127.0.0.1 IRC Proxy TCP
7654 127.0.0.1 I2CP Protocol TCP
7656 127.0.0.1 SAM Bridge TCP TCP
7657 0.0.0.0 Web Console (non-SSL) TCP
7667 0.0.0.0 Web Console (SSL) TCP
7658 127.0.0.1 I2P Webserver TCP
7659 127.0.0.1 SMTP Proxy TCP
7660 127.0.0.1 POP Proxy TCP
7652 LAN interface UPnP TCP
7653 LAN interface UPnP UDP
RANDOM 0.0.0.0 I2NP Protocol TCP+UDP

Networking

At the minimum, you’ll want the Router Console (7657) and the HTTP Proxy (4444) available on localhost or your LAN network. Most services bind to 127.0.0.1 and will only be available inside the container. The web console binds to 0.0.0.0 so it’s accessible from your Docker host by default — both the non-SSL (7657) and SSL (7667) ports are bound. Services should not be exposed to the public internet. They can be disabled in the I2P+ web console if not required.

Security note: Binding the web console to 0.0.0.0 makes it accessible on all network interfaces. If your Docker host is exposed to the internet, restrict access by setting IP_ADDR to your LAN IP (e.g., 192.168.1.10) or use Docker’s -p 127.0.0.1:7657:7657 to limit exposure to localhost only. Without these precautions, the console may be reachable from the public internet if firewall rules permit.

To receive inbound connections from peers, you must expose the external I2NP port (TCP+UDP). Without it, the router will show as firewalled and rely on hole punching, which is less reliable. See External Network Port below for how to set a fixed port for port forwarding.

External Network Port

By default, I2P+ uses a random port for the I2NP Protocol (TCP+UDP). This is recommended for security - avoid using a fixed port as it’s fingerprintable. The port is assigned at first start and remains consistent for that container (stored in router.config).

Set at build time:

docker build --build-arg EXTERNAL_PORT=12345 -t i2pplus .

Or set at runtime:

docker run -e EXTERNAL_PORT=12345 i2pplus:latest

Your allocated port will be listed in your Router Web Console at http://127.0.0.1:7657/info. Note: This is the only port that you need to expose to the public internet, access to other ports should only be permitted from localhost or your LAN.

Useful Docker Commands

Build the image

# From project root
docker build -t i2pplus:latest -f docker/Dockerfile .

# Save to file for transfer
docker save i2pplus:latest -o /tmp/i2pplus.tar

# Load from file
docker load -i /tmp/i2pplus.tar

Run the container

# Basic run (with port mapping for console access)
docker run -d -p 7657:7657 -p 7667:7667 -p 4444:4444 --name i2pplus i2pplus:latest

# With persistent config (survives container restart)
# Note: The external I2NP port is random - see your router console or router.config for the assigned port
docker run -d -v /path/to/i2p-data:/i2p/.i2p \
           -v /path/to/snark:/i2psnark \
           -p 7657:7657 -p 7667:7667 -p 4444:4444 \
           --name i2pplus i2pplus:latest

# Override JVM heap size
docker run -d -e JVM_XMX=2048m i2pplus:latest

# Override JAVA options
docker run -d -e JAVA17OPTS="-XX:+UseG1GC" i2pplus:latest

Manage the container

# View logs
docker logs i2pplus
docker logs -f i2pplus  # follow

# Interactive shell (for debugging)
docker exec -it i2pplus /bin/bash

# Stop/Start
docker stop i2pplus
docker start i2pplus

# Remove container
docker rm -f i2pplus

docker-compose

# Start
docker-compose up --build -d

# View logs
docker-compose logs -f

# Stop
docker-compose down

Troubleshooting

# Check container status
docker ps -a

# Check resource usage
docker stats i2pplus

# Check configuration
docker exec i2pplus cat /i2p/router.config

# Shell script syntax check
bash -n docker/rootfs/startapp.sh && echo "OK"

Cleanup

Remove all data and restart fresh

# Stop container (if running) and remove
docker stop i2pplus 2>/dev || true
docker rm -f i2pplus

# Remove volumes (config, plugins, reseed data)
docker volume rm i2pplus_i2p-home  # or your volume name
docker volume rm i2pplus_i2psnark  # or your volume name

# Or if using bind mounts, delete the host directories
rm -rf /path/to/i2p-data
rm -rf /path/to/snark

# Rebuild and start fresh
docker build -t i2pplus:latest -f docker/Dockerfile .
docker run -d -v /path/to/i2p-data:/i2p/.i2p -v /path/to/snark:/i2psnark i2pplus:latest

Clear specific caches (without losing config)

# Enter container
docker exec -it i2pplus /bin/bash

# Clear router cache
rm -rf /i2p/.i2p/routerCache

# Clear profile (WARNING: this deletes ALL data including config - only use if you want a fresh start)
rm -rf /i2p/.i2p/

# Clear I2PSnark torrents
rm -rf /i2psnark/*

# Exit container and restart
exit
docker restart i2pplus

Clean up Docker resources

# Use the cleanup script (recommended)
./docker/cleanup.sh --all

# Or manually:
# Remove stopped containers
docker container prune -f

# Remove unused images
docker image prune -a -f

# Remove unused volumes
docker volume prune -f

# Full cleanup
docker system prune -a -f

The cleanup.sh script provides an interactive way to clean up specific resources:

./docker/cleanup.sh --help