Skip to content

Commit 9b8d66d

Browse files
author
Paul C
committed
feat: Docker container packaging for WolfNet
- Dockerfile: debian-slim with iproute2/iptables, host network mode - entrypoint.sh: env var config, join token handling, key generation - docker-compose.yml: single-service compose for quick deployment - unraid-template.xml: Unraid Community Apps template Run with: docker run -d --name wolfnet --network host \ --cap-add NET_ADMIN --device /dev/net/tun:/dev/net/tun \ -v wolfnet-config:/etc/wolfnet \ -e WOLFNET_JOIN_TOKEN=<token> \ ghcr.io/wolfsoftwaresystemsltd/wolfnet:latest
1 parent 5ed94df commit 9b8d66d

4 files changed

Lines changed: 179 additions & 0 deletions

File tree

docker/Dockerfile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# WolfNet Docker Container
2+
# Secure mesh VPN — runs in --network host mode with /dev/net/tun
3+
#
4+
# Usage:
5+
# docker run -d --name wolfnet --network host \
6+
# --cap-add NET_ADMIN --device /dev/net/tun:/dev/net/tun \
7+
# -v wolfnet-config:/etc/wolfnet \
8+
# -e WOLFNET_JOIN_TOKEN=<token> \
9+
# ghcr.io/wolfsoftwaresystemsltd/wolfnet:latest
10+
11+
FROM debian:bookworm-slim
12+
13+
RUN apt-get update && apt-get install -y --no-install-recommends \
14+
iproute2 \
15+
iptables \
16+
procps \
17+
ca-certificates \
18+
&& rm -rf /var/lib/apt/lists/*
19+
20+
RUN mkdir -p /etc/wolfnet /var/run/wolfnet
21+
22+
COPY wolfnet /usr/local/bin/wolfnet
23+
COPY wolfnetctl /usr/local/bin/wolfnetctl
24+
COPY entrypoint.sh /entrypoint.sh
25+
26+
RUN chmod +x /usr/local/bin/wolfnet /usr/local/bin/wolfnetctl /entrypoint.sh
27+
28+
EXPOSE 9600/udp
29+
EXPOSE 9601/udp
30+
31+
VOLUME ["/etc/wolfnet"]
32+
33+
ENTRYPOINT ["/entrypoint.sh"]

docker/docker-compose.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# WolfNet Docker Compose — join an existing WolfNet mesh
2+
#
3+
# Usage:
4+
# WOLFNET_JOIN_TOKEN=<token> docker compose up -d
5+
#
6+
# Get the join token by running `wolfnet invite` on an existing WolfNet node.
7+
8+
services:
9+
wolfnet:
10+
image: ghcr.io/wolfsoftwaresystemsltd/wolfnet:latest
11+
container_name: wolfnet
12+
restart: unless-stopped
13+
network_mode: host
14+
cap_add:
15+
- NET_ADMIN
16+
devices:
17+
- /dev/net/tun:/dev/net/tun
18+
volumes:
19+
- wolfnet-config:/etc/wolfnet
20+
- /run/wolfnet:/var/run/wolfnet
21+
environment:
22+
- WOLFNET_JOIN_TOKEN=${WOLFNET_JOIN_TOKEN:-}
23+
# Optional overrides:
24+
# - WOLFNET_ADDRESS=10.0.10.5
25+
# - WOLFNET_PORT=9600
26+
# - WOLFNET_GATEWAY=false
27+
# - WOLFNET_DISCOVERY=true
28+
29+
volumes:
30+
wolfnet-config:

docker/entrypoint.sh

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# ─── WolfNet Docker Entrypoint ───
5+
# Configures WolfNet from environment variables and starts the daemon.
6+
7+
CONFIG_DIR="/etc/wolfnet"
8+
CONFIG_FILE="$CONFIG_DIR/config.toml"
9+
KEY_FILE="$CONFIG_DIR/private.key"
10+
STATUS_DIR="/var/run/wolfnet"
11+
12+
mkdir -p "$CONFIG_DIR" "$STATUS_DIR"
13+
14+
# ─── Check TUN device ───
15+
if [ ! -c /dev/net/tun ]; then
16+
echo "ERROR: /dev/net/tun not found."
17+
echo "Run with: --device /dev/net/tun:/dev/net/tun"
18+
echo "If the TUN module is not loaded, run: modprobe tun"
19+
exit 1
20+
fi
21+
22+
# ─── Generate keys if missing ───
23+
if [ ! -f "$KEY_FILE" ]; then
24+
echo "Generating WolfNet key pair..."
25+
wolfnet genkey > "$KEY_FILE"
26+
chmod 600 "$KEY_FILE"
27+
echo "Key generated. Public key:"
28+
wolfnet pubkey < "$KEY_FILE"
29+
fi
30+
31+
# ─── Handle join token ───
32+
if [ -n "$WOLFNET_JOIN_TOKEN" ] && [ ! -f "$CONFIG_DIR/.joined" ]; then
33+
echo "Joining WolfNet network with invite token..."
34+
if wolfnet join "$WOLFNET_JOIN_TOKEN" --config-dir "$CONFIG_DIR"; then
35+
touch "$CONFIG_DIR/.joined"
36+
echo "Successfully joined. Check 'docker logs wolfnet' for the reverse token."
37+
else
38+
echo "WARNING: Join failed. Starting with existing config if available."
39+
fi
40+
fi
41+
42+
# ─── Generate config from env vars if missing ───
43+
if [ ! -f "$CONFIG_FILE" ]; then
44+
echo "Generating config from environment variables..."
45+
ADDR="${WOLFNET_ADDRESS:-10.0.10.1}"
46+
SUBNET="${WOLFNET_SUBNET:-24}"
47+
PORT="${WOLFNET_PORT:-9600}"
48+
IFACE="${WOLFNET_INTERFACE:-wolfnet0}"
49+
GW="${WOLFNET_GATEWAY:-false}"
50+
DISC="${WOLFNET_DISCOVERY:-true}"
51+
HOSTNAME="${WOLFNET_HOSTNAME:-$(hostname)}"
52+
53+
cat > "$CONFIG_FILE" <<EOF
54+
[node]
55+
address = "$ADDR/$SUBNET"
56+
listen_port = $PORT
57+
interface = "$IFACE"
58+
hostname = "$HOSTNAME"
59+
gateway = $GW
60+
61+
[network]
62+
discovery = $DISC
63+
discovery_port = 9601
64+
EOF
65+
66+
# Add static peers if provided (JSON array)
67+
if [ -n "$WOLFNET_PEERS" ]; then
68+
echo "" >> "$CONFIG_FILE"
69+
echo "$WOLFNET_PEERS" | python3 -c "
70+
import json, sys
71+
peers = json.load(sys.stdin)
72+
for p in peers:
73+
print(f'''
74+
[[peers]]
75+
public_key = \"{p.get('public_key', '')}\"
76+
endpoint = \"{p.get('endpoint', '')}\"
77+
allowed_ips = \"{p.get('allowed_ips', '10.0.10.0/24')}\"
78+
''')
79+
" >> "$CONFIG_FILE" 2>/dev/null || true
80+
fi
81+
82+
echo "Config generated at $CONFIG_FILE"
83+
fi
84+
85+
echo "Starting WolfNet daemon..."
86+
echo " Config: $CONFIG_FILE"
87+
echo " Interface: ${WOLFNET_INTERFACE:-wolfnet0}"
88+
echo " Port: ${WOLFNET_PORT:-9600}"
89+
90+
exec wolfnet --config "$CONFIG_FILE"

docker/unraid-template.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0"?>
2+
<Container version="2">
3+
<Name>WolfNet</Name>
4+
<Repository>ghcr.io/wolfsoftwaresystemsltd/wolfnet:latest</Repository>
5+
<Registry>https://github.com/wolfsoftwaresystemsltd/wolfnet/pkgs/container/wolfnet</Registry>
6+
<Network>host</Network>
7+
<Privileged>false</Privileged>
8+
<Support>https://github.com/wolfsoftwaresystemsltd/wolfnet/issues</Support>
9+
<Project>https://github.com/wolfsoftwaresystemsltd/wolfnet</Project>
10+
<Overview>WolfNet is a secure private mesh VPN that creates encrypted tunnels between your servers using X25519 key exchange and ChaCha20-Poly1305 encryption. No WireGuard kernel module needed. Join your Unraid server to your WolfStack cluster overlay network.</Overview>
11+
<Category>Network:VPN</Category>
12+
<WebUI/>
13+
<TemplateURL/>
14+
<Icon>https://raw.githubusercontent.com/wolfsoftwaresystemsltd/wolfnet/main/icon.png</Icon>
15+
<ExtraParams>--cap-add=NET_ADMIN --device=/dev/net/tun:/dev/net/tun</ExtraParams>
16+
<PostArgs/>
17+
<DonateText>Support WolfStack development</DonateText>
18+
<DonateLink>https://wolf.uk.com</DonateLink>
19+
<Description>WolfNet creates a secure encrypted mesh network between your servers. Run on Unraid to join your WolfStack cluster. No WireGuard kernel module required — fully userspace crypto.</Description>
20+
<Config Name="Join Token" Target="WOLFNET_JOIN_TOKEN" Default="" Mode="" Description="Invite token from 'wolfnet invite' on an existing node" Type="Variable" Display="always" Required="true" Mask="false"/>
21+
<Config Name="WolfNet IP" Target="WOLFNET_ADDRESS" Default="" Mode="" Description="Override auto-assigned IP (leave empty for auto)" Type="Variable" Display="advanced" Required="false" Mask="false"/>
22+
<Config Name="Listen Port" Target="WOLFNET_PORT" Default="9600" Mode="" Description="UDP port for tunnel traffic" Type="Variable" Display="advanced" Required="false" Mask="false"/>
23+
<Config Name="Gateway Mode" Target="WOLFNET_GATEWAY" Default="false" Mode="" Description="Enable NAT gateway for other WolfNet nodes" Type="Variable" Display="advanced" Required="false" Mask="false"/>
24+
<Config Name="Config" Target="/etc/wolfnet" Default="/mnt/user/appdata/wolfnet" Mode="rw" Description="Configuration and key storage" Type="Path" Display="always" Required="true" Mask="false"/>
25+
<Config Name="Status" Target="/var/run/wolfnet" Default="/var/run/wolfnet" Mode="rw" Description="Runtime status files" Type="Path" Display="advanced" Required="false" Mask="false"/>
26+
</Container>

0 commit comments

Comments
 (0)