CandyGo
February 26, 2026 ยท View on GitHub
CandyGo is a pure Go (no cgo) rewrite of the original candy project, targeting 1:1 behavior compatibility.
candy is an amazing net tool made by lanthora
The project provides:
- client mode: join virtual network (WebSocket control plane + UDP P2P data plane)
- server mode: WebSocket relay + dynamic address allocation + SD-WAN route publish
- service mode: HTTP API (
/api/run,/api/status,/api/shutdown) - the candy.cfg is fully compatible with original candy
Goals
- Keep protocol and runtime behavior aligned with the original C++ implementation
- Keep naming and function semantics as close as possible
- Prioritize compatibility and stability before adding features
Requirements
- Go 1.25+
- Windows client mode:
wintun.dllis required (place near executable or inSystem32) - Linux/macOS: TUN and route operations usually require root/admin privileges
Build
go build ./...
go test ./...
Run
CLI
go run . --help
go run . -m client -w ws://127.0.0.1:26816 -t 192.168.202.2/24
go run . -m server -w ws://0.0.0.0:26816 -d 192.168.202.0/24
Service
go run . service --help
go run . service --bind 0.0.0.0:26817
Windows helper
run.bat is provided for Windows startup convenience (including elevation flow).
Config compatibility
- Supports loading config via
-c /path/to/candy.cfg - If
-cis not provided, it auto-detects:./candy.cfgcandy.cfgin executable directory
- Maintains compatibility with original common keys (
mode,websocket,password,tun,stun,route,dhcp,sdwan, etc.)
Cross-compile output
Use build scripts to output binaries directly under dist/:
build.bat(Windows)build.sh(Linux)
Generated file naming pattern:
dist/candygo-windows-amd64.exedist/candygo-linux-amd64dist/candygo-linux-armv7dist/candygo-linux-armv8dist/candygo-linux-mipsdist/candygo-linux-mipsel
Docker
The Docker image uses the prebuilt binary from dist/ (default: dist/candygo-linux-amd64).
dockerfile: runtime image definitiondocker-compose.yml: host network + privileged container (candygo)update-docker.sh: remove old container/image, rebuild with nativedocker build, recreate container with preserved parameters
Default persistent mounts in compose:
/var/lib/candy:/var/lib/candy(rw)/path/to/candy.cfg:/etc/candy.cfg:ro
Project map
Key directories and files:
- entry and mode dispatch:
main.go - app facade + lifecycle:
internal/app/- API facade:
internal/app/candy_api.go - client/server core:
internal/app/client_core.go,internal/app/server_core.go - service HTTP API:
internal/app/service.go
- API facade:
- config and persistence:
internal/config/- config parse/load/save:
internal/config/config.go - init template (
--init-config):internal/config/initconfig.go
- config parse/load/save:
- websocket protocol and transport:
internal/websocket/- websocket messages:
internal/websocket/websocket_messages.go - websocket client/server:
internal/websocket/websocket_client.go,internal/websocket/websocket_server.go
- websocket messages:
- p2p/routing:
internal/peer/- peer messages:
internal/peer/peer_messages.go - peer state machine + manager:
internal/peer/peer.go,internal/peer/peer_manager.go
- peer messages:
- tun and routes:
internal/tun/- tun core:
internal/tun/tun.go - os implementation:
internal/tun/tun_impl.go,internal/tun/tun_windows_api.go
- tun core:
- shared primitives/utilities:
internal/common/- logging/time/version:
internal/common/constants.go,internal/common/random_time.go - ip/message/core types:
internal/common/ip.go,internal/common/message.go
- logging/time/version:
License
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
See LICENSE for full text.