Installation
WaterWall is distributed as a standalone executable. You do not need a package
manager service, a database, or a separate runtime. Download the build for your
operating system, place a core.json beside the executable, and run it from
that directory.
Most deployments run WaterWall on a Linux VPS. You can manage the files from a Windows machine over SSH or VS Code Remote SSH, but the commands below are meant to be executed on the server.
Download
Download the latest release from the WaterWall release page and choose the asset that matches your operating system and CPU architecture.
Linux x64 builds are packed executables under their existing download names,
including the old-CPU and AVX512 builds. Run the executable normally; it restores
WaterWall in memory at startup without extracting a temporary executable to disk.
These builds require Linux 3.19 or newer with memfd_create, file sealing,
execveat, permission to execute anonymous memory-backed files, and readable
/proc/self/exe. The selected build's CPU and system-library requirements still
apply. Set-ID and file-capability deployment are not supported by the packed loader.
Windows downloads retain ordinary executables. Optional source builds with
WW_PACK_RUNTIME=ON use a private temporary executable and a separate child
process, while the launcher waits and cleans up. This needs native Windows
acceptance before release use. Keep required companion DLLs beside the launcher.
Firewall rules and service wrappers that identify a stable executable path/PID
must account for the temporary child; a rule for the outer executable is not
sufficient. Forced termination may leave temporary files. Windows ARM packing is
unsupported.
On Linux, a typical manual install looks like this:
mkdir -p ~/waterwall
cd ~/waterwall
# Put the downloaded archive or binary here, then extract it if needed.
chmod +x ./WaterWall
If the release asset is compressed, extract it first with the matching tool, for
example tar, unzip, or 7z.
Directory Layout
A small deployment usually looks like this:
waterwall/
WaterWall
core.json
configs/
local-test.json
logs/
By default, WaterWall reads ./core.json from the process working directory. The
paths inside core.json, including the files listed in configs, are passed to
the loader as written, so keep your working directory intentional.
Selecting Another Core Input
Use any of the equivalent forms -c:PATH, --c:PATH, -config:PATH,
--config:PATH, or config:PATH. The path may be relative or absolute. Use
stdin to pipe the JSON directly:
./WaterWall --config:/etc/waterwall/core.json
./WaterWall --config:stdin < core.json
You may instead set WW_CORE_JSON_INPUT to a path or stdin. A CLI option has
priority over the environment variable, and the environment variable has
priority over the default ./core.json.
The selected source does not change the working directory. Relative paths inside the JSON remain relative to the directory where WaterWall was started.
Minimal core.json
Create core.json beside the executable:
{
"log": {
"path": "logs/",
"core": {
"loglevel": "INFO",
"file": "core.log",
"console": true
},
"network": {
"loglevel": "INFO",
"file": "network.log",
"console": true
},
"dns": {
"loglevel": "INFO",
"file": "dns.log",
"console": true
},
"internal": {
"loglevel": "INFO",
"file": "internal.log",
"console": true
}
},
"misc": {
"workers": 1,
"ram-profile": "client",
"mtu": 1500,
"try-enabling-bbr": true,
"libs-path": "libs/"
},
"dns": {
"domain-strategy": "prefer-ipv4"
},
"configs": [
"configs/local-test.json"
]
}
The configs array is required and must contain at least one config file path.
Other sections are optional, but keeping misc explicit makes the runtime easier
to reason about.
Minimal Test Chain
Create configs/local-test.json:
{
"name": "local-test",
"author": "waterwall-user",
"config-version": 1,
"core-minimum-version": 0,
"nodes": [
{
"name": "listen-http",
"type": "TcpListener",
"settings": {
"address": "127.0.0.1",
"port": 8080
},
"next": "connect-example"
},
{
"name": "connect-example",
"type": "TcpConnector",
"settings": {
"address": "example.com",
"port": 80
}
}
]
}
Run WaterWall:
cd ~/waterwall
./WaterWall
In another terminal, test the local listener:
curl -v http://127.0.0.1:8080/
If the request reaches example.com, the binary, core file, config loader, TCP
listener, DNS resolver, and TCP connector are all working.
Running on a VPS
For a public service, bind listeners to a public or wildcard address:
"address": "0.0.0.0"
Then allow the port in your VPS firewall or cloud firewall. For example, if you
listen on port 443, the operating system and provider firewall must both allow
inbound TCP 443.
Ports below 1024 usually require root privileges or a capability such as
CAP_NET_BIND_SERVICE. Packet-level nodes such as TunDevice may also require
extra privileges because they create or use network interfaces.
Common Problems
core.json not found:
Make sure you run WaterWall from the directory that contains core.json, select
it with --config:PATH or WW_CORE_JSON_INPUT, or use your service manager's
working-directory option.
Config file not found:
Check every path in configs. Relative paths are normally relative to the
current working directory.
Permission denied:
Run chmod +x ./WaterWall. If the listener port is below 1024, run with the
needed privilege or choose a higher port for testing.
Port already in use:
Use ss -ltnp on Linux to find the process already listening on that TCP port.
Remote clients cannot connect:
Check the listener address, WaterWall logs, the Linux firewall, and the provider
firewall. A listener bound to 127.0.0.1 only accepts local connections.
DNS resolution fails:
Check the dns block in core.json, especially servers and
domain-strategy, then look at logs/dns.log.