Environment
- Paperclip version: v2026.416.0 (regression from v2026.403.0)
- Deployment: Proxmox LXC container (unprivileged)
- Network: IPv6-only (no IPv4 address assigned, single
eth0 with DHCPv6)
- OS: Ubuntu 24.04
- Node.js: managed via npx / PM2
net.ipv6.bindv6only: 0 (dual-stack kernel setting)
Description
On an IPv6-only host, Paperclip v2026.416.0 always binds to 0.0.0.0:3100 instead of :::3100, making the server completely unreachable. This is a regression — v2026.403.0 worked correctly on the same host.
The root cause is that ALL_INTERFACES_BIND_HOST is hardcoded to "0.0.0.0" in @paperclipai/shared/dist/network-bind.js:
// @paperclipai/shared/dist/network-bind.js
export const ALL_INTERFACES_BIND_HOST = "0.0.0.0"; // ← hardcoded IPv4
This constant is used in resolveRuntimeBind() for the lan bind preset:
case "lan":
return { bind, host: ALL_INTERFACES_BIND_HOST, customBindHost, errors: [] };
And is re-exported via @paperclipai/shared/dist/index.js and consumed by @paperclipai/server/dist/config.js:
import { resolveRuntimeBind, ... } from "@paperclipai/shared";
This means that regardless of what is set in config.json ("host": "::") or environment variables (HOST=::, PAPERCLIP_BIND=lan, PAPERCLIP_DEPLOYMENT_MODE=authenticated), the resolved host is always overwritten with "0.0.0.0" by resolveRuntimeBind().
On a dual-stack host, 0.0.0.0 works because the kernel maps IPv4 to IPv6 sockets. On an IPv6-only host (no IPv4 interface), 0.0.0.0 binds to nothing reachable and the server is inaccessible.
Steps to Reproduce
- Set up an IPv6-only host (no IPv4 address on any interface)
- Install Paperclip:
npx paperclipai onboard --yes
- Configure as
authenticated/public with bind: lan
- Start:
npx paperclipai run
- Observe: server binds to
0.0.0.0:3100 instead of :::3100
Verify with:
ss -tlnp | grep 3100
# Output: LISTEN 0.0.0.0:3100 ← IPv4 only, unreachable on IPv6-only host
Expected Behavior
When bind is set to lan on an IPv6-only host, the server should bind to :::3100 (all interfaces, IPv6). The ALL_INTERFACES_BIND_HOST constant should be "::" to cover both IPv4 (via dual-stack) and pure IPv6 environments.
On dual-stack hosts, :: with net.ipv6.bindv6only=0 also accepts IPv4 connections, so this change is fully backwards compatible.
Actual Behavior
[INFO]: Server listening on 0.0.0.0:3100
Server is unreachable from any client because the host has no IPv4 address.
Workaround
Manually patch the compiled file in the npx cache:
sed -i 's/ALL_INTERFACES_BIND_HOST = "0\.0\.0\.0"/ALL_INTERFACES_BIND_HOST = "::"/' \
~/.npm/_npx/<hash>/node_modules/@paperclipai/shared/dist/network-bind.js
Note: this patch is lost whenever the npx cache is cleared or the package is reinstalled.
Proposed Fix
In packages/shared/src/network-bind.ts (or equivalent source):
// Before
export const ALL_INTERFACES_BIND_HOST = "0.0.0.0";
// After
export const ALL_INTERFACES_BIND_HOST = "::";
On Linux with net.ipv6.bindv6only=0 (the default), a socket bound to :: accepts both IPv4 and IPv6 connections, making this a safe change for all deployment environments. On systems with net.ipv6.bindv6only=1, operators can use PAPERCLIP_BIND_HOST=0.0.0.0 to override explicitly.
Additional Context
Node.js correctly supports IPv6 binding on this host — verified with:
const http = require('http');
const s = http.createServer((req, res) => res.end('ok'));
s.listen(9999, '::', () => console.log('listening:', s.address()));
// Output: listening: { address: '::', family: 'IPv6', port: 9999 }
The issue is exclusively in Paperclip's resolveRuntimeBind() overriding the configured host with the hardcoded 0.0.0.0 constant.
Environment
eth0with DHCPv6)net.ipv6.bindv6only:0(dual-stack kernel setting)Description
On an IPv6-only host, Paperclip v2026.416.0 always binds to
0.0.0.0:3100instead of:::3100, making the server completely unreachable. This is a regression — v2026.403.0 worked correctly on the same host.The root cause is that
ALL_INTERFACES_BIND_HOSTis hardcoded to"0.0.0.0"in@paperclipai/shared/dist/network-bind.js:This constant is used in
resolveRuntimeBind()for thelanbind preset:And is re-exported via
@paperclipai/shared/dist/index.jsand consumed by@paperclipai/server/dist/config.js:This means that regardless of what is set in
config.json("host": "::") or environment variables (HOST=::,PAPERCLIP_BIND=lan,PAPERCLIP_DEPLOYMENT_MODE=authenticated), the resolved host is always overwritten with"0.0.0.0"byresolveRuntimeBind().On a dual-stack host,
0.0.0.0works because the kernel maps IPv4 to IPv6 sockets. On an IPv6-only host (no IPv4 interface),0.0.0.0binds to nothing reachable and the server is inaccessible.Steps to Reproduce
npx paperclipai onboard --yesauthenticated/publicwithbind: lannpx paperclipai run0.0.0.0:3100instead of:::3100Verify with:
Expected Behavior
When
bindis set tolanon an IPv6-only host, the server should bind to:::3100(all interfaces, IPv6). TheALL_INTERFACES_BIND_HOSTconstant should be"::"to cover both IPv4 (via dual-stack) and pure IPv6 environments.On dual-stack hosts,
::withnet.ipv6.bindv6only=0also accepts IPv4 connections, so this change is fully backwards compatible.Actual Behavior
Server is unreachable from any client because the host has no IPv4 address.
Workaround
Manually patch the compiled file in the npx cache:
Note: this patch is lost whenever the npx cache is cleared or the package is reinstalled.
Proposed Fix
In
packages/shared/src/network-bind.ts(or equivalent source):On Linux with
net.ipv6.bindv6only=0(the default), a socket bound to::accepts both IPv4 and IPv6 connections, making this a safe change for all deployment environments. On systems withnet.ipv6.bindv6only=1, operators can usePAPERCLIP_BIND_HOST=0.0.0.0to override explicitly.Additional Context
Node.js correctly supports IPv6 binding on this host — verified with:
The issue is exclusively in Paperclip's
resolveRuntimeBind()overriding the configured host with the hardcoded0.0.0.0constant.