| deploy | ||
| docs | ||
| netfishing_discovery | ||
| straywild_discovery | ||
| tests | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| CONTRIBUTOR-TERMS.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| TRADEMARKS.md | ||
straywild Discovery Server
An ephemeral public-room directory and allocation-based UDP privacy relay for straywild. Player hosts choose direct or relay routing when they advertise through HTTPS. Browsers retrieve compatible metadata without receiving an IP address, and relay-enabled joins give each player an isolated relay endpoint instead of the other peer's network address. Dedicated servers are direct-only and cannot consume shared relay capacity.
The service also runs a small UDP rendezvous. It observes packets from the host's exact ENet socket and lets that host punch the allocated relay socket. Relay gameplay is pinned to the authenticated joining socket and verified host endpoint, bounded by packet/byte budgets, and removed after an idle timeout. Addresses are held only in memory and are not written to the application log.
Friend presence and live room invitations use the same service as short-lived capability channels. There are no discovery accounts, durable friend records, or offline messages; friendship state stays on each player's device.
Requirements
- Python 3.11 or newer
- A TLS reverse proxy for public deployment
There are no runtime Python package dependencies.
Run locally
python3 -m straywild_discovery
The default listener is 127.0.0.1:7770.
curl http://127.0.0.1:7770/health
Set straywild_DISCOVERY_BUILD_REVISION to the deployed Git commit. The health response reports
both the package version and that build revision, which makes production/source drift visible.
Run the focused tests with:
python3 -m unittest discover -v
Configuration
Environment variables are documented in
deploy/straywild-discovery.env.example.
The intended public topology is:
straywild client -> HTTPS reverse proxy -> 127.0.0.1:7770 discovery service
straywild client -----------------------> public UDP rendezvous:7771
direct room client ---------------------> authoritative ENet/UDP host
relay room client ----------------------> allocated UDP relay:20000-22047
allocated UDP relay --------------------> player-hosted ENet/UDP host
Configure the Godot client with the reverse proxy's HTTPS origin through
network/discovery/base_url in project.godot. For local development, the
same value can be overridden without modifying the project by setting
straywild_DISCOVERY_URL before launching the game.
The reverse proxy must preserve the client address in X-Forwarded-For, and
its own address must be listed in straywild_DISCOVERY_TRUSTED_PROXY_CIDRS.
Apply ordinary request-rate limits to the write endpoints at the proxy. Do not
expose the Python listener directly to the public Internet.
Privacy logging policy
The discovery and relay application must not log private player information. This includes raw IP addresses and ports, address-derived pseudonyms, request paths tied to room IDs, room or player names, request bodies, headers, join and lease tokens, authentication material, and friendship capabilities. HTTP access logging is disabled completely. Unexpected request failures produce only a generic operational error without a peer address, request contents, or request-specific traceback.
The service necessarily handles network endpoints temporarily in memory to observe routes, apply abuse limits, and forward active relay traffic. Those endpoints expire with their room, join, or relay state and are never written to the application log or a database. Temporary processing is not permission to retain or repurpose that information.
Production deployments must also disable reverse-proxy access logs for every discovery route. Default proxy log formats normally contain a client address and are not acceptable here. Do not log forwarded addresses, request bodies, authorization headers, or tokens at the proxy, firewall, or service wrapper. Hosting providers and upstream networks may retain connection metadata under their own policies; operators should choose providers accordingly and disclose that boundary.
Use the sample systemd unit in deploy/straywild-discovery.service
as a deployment starting point. The service keeps only active leases in memory, so it requires no
database, backups, or schema migrations.
Connectivity boundary
The game first requests UPnP forwarding, then uses same-socket UDP rendezvous and hole punching. A player host chooses whether its public listing is direct or relay. A relay room punches a unique allocation and both peers exchange ENet packets through it; a direct room connects through the verified host route and consumes no relay allocation. ENet gameplay authority does not move to discovery. Dedicated advertisements must be direct and a dedicated relay request is rejected. Expose the configured traversal port and full relay allocation range over UDP in both the host firewall and provider firewall. The rendezvous listener intentionally processes its small, bounded packets serially so arbitrary datagrams cannot create unbounded worker threads. Apply conservative edge rate limits as an additional deployment control.
The relay prevents the player host and joiner from seeing one another's address during normal network traffic. It is not anonymity from the relay operator, hosting provider, upstream network, or a compromised client. The discovery process necessarily handles both endpoints in volatile memory. Clients treat the host-selected connection mode as binding: failure to allocate or reach a relay stops the join and never silently falls back to direct transport. Operators may explicitly disable relay availability for private development; a player relay advertisement is then rejected.
API
See docs/API.md for the versioned HTTP contract.
Repository relationship
This is deliberately a separate repository from the Godot game so the service can deploy and roll
back independently. Production tags follow the coordinated straywild release train: a
vX.Y.Z-alpha tag identifies the discovery snapshot tested for the same game and dedicated-server
release. The versioned HTTP contract remains independent from straywild's save schema and gameplay
network protocol. Each tagged deployment accepts room advertisements only from its matching game
release so incompatible rooms are never presented as publicly available.
Existing NETfishing installations can be upgraded in place. The legacy
netfishing_discovery module, command name, and NETFISHING_DISCOVERY_*
environment variables remain accepted, while new installations should use the
Straywild names shown above. When both forms of an environment setting exist,
the Straywild value takes precedence.
Licensing
Project-owned source code is licensed under the GNU General Public License, version 3 or, at your option, any later version (GPL-3.0-or-later).
straywild and Woofmeow branding is not granted under the GPL; see
TRADEMARKS.md. Unsolicited contributions are not accepted;
see CONTRIBUTING.md. Historical and expressly invited
work is governed by CONTRIBUTOR-TERMS.md.
Copyright © 2026 Woofmeow.