
Build a local Cherry game service first, verify its connector, and then expose only the endpoint your players need
Cherry is a Go game server framework built around the Actor Model, with pluggable TCP, WebSocket, and HTTP connectors. This guide explains how to prepare a Go environment, add Cherry to a Go module, understand its required profile configuration, start an application, and verify the resulting local listener. Once the service works locally, we show how to make its TCP endpoint remotely accessible with Localtonet without configuring inbound router port forwarding or requiring a public IP address. Because Cherry does not document one universal port or connector profile, we clearly identify the values that must come from your own application configuration.
๐ What's in this guide
What you are building with Cherry
Cherry is a framework for creating game servers in Go rather than a finished game server with a universal executable, port, or gameplay protocol. Your application decides which actors, handlers, messages, serializers, and network connectors it needs. This distinction matters during installation: adding the Cherry module gives you the framework, but it does not automatically create a remotely playable server.
Cherry uses an Actor Model in which each actor has its own goroutine and processes its mailbox serially. The framework separates local client-to-actor traffic, remote actor-to-actor traffic, and system events into independent FIFO queues. An application can register request handlers, remote handlers, and event handlers while keeping the corresponding game logic associated with an actor.
The framework also provides an application builder and lifecycle. Components are registered and initialized before the application begins normal operation. During shutdown, components stop in reverse registration order. Cherry documents graceful shutdown handling for SIGINT, SIGQUIT, and SIGTERM, which is useful when running the service under an operating-system service manager or container orchestrator.
Startup().
For this tutorial, the important boundary is the frontend connector. A frontend Cherry node accepts client connections through a configured TCP, WebSocket, or HTTP listener. Localtonet can then publish the working local endpoint. Internal actor communication, discovery services, databases, administrative tools, and other backend dependencies should not be exposed merely because the client-facing connector needs remote access.
Cherry's documented startup example references a profile file, but the framework documentation supplied for this guide does not establish a default connector port, a complete universal profile, or one production deployment layout. Use the address and port from the profile or example you actually run. This article intentionally uses placeholders instead of inventing those values.
Prerequisites and deployment decisions
Start by choosing a machine that can run both your Cherry application and the Localtonet client, or a machine on the same private network that can reach the Cherry listener. The Localtonet client makes an outbound connection to our relay server, so the workflow does not require an inbound router forwarding rule, a public IP address, firewall changes for inbound internet traffic, or a separate VPN.
Cherry currently requires Go 1.24 or newer. Confirm the installed version before creating the application:
go version
The reported version must be Go 1.24 or later. If the command is unavailable or reports an older release, install or upgrade Go using the installation method appropriate to your operating system. Also confirm that the Go executable is available in your shell's command search path before continuing.
You will need a writable project directory and network permission to download Go modules. If the application will use Cherry's multi-node features, its discovery and communication dependencies must also be available. Those dependencies are not required merely because Cherry supports them. Their necessity depends on the mode and profile chosen by your application.
Decide which client-facing transport you are implementing before configuring remote access:
| Cherry connector | Typical client | Remote-access consideration |
|---|---|---|
| TCP | Native game client using a socket protocol | Use a Localtonet TCP tunnel pointed at the configured local listener. |
| WebSocket | Browser or other WebSocket-capable client | The application still needs a correctly configured WebSocket connector. Verify its local handshake and path before choosing the matching remote publication method. |
| HTTP Server | REST API, browser request, health endpoint, or supporting web service | An HTTP/s tunnel is generally the relevant Localtonet family for an HTTP application endpoint. |
This guide uses a TCP tunnel for the primary integration because Cherry documents a native TCP connector and TCP forwarding does not require Localtonet to understand the application's game packet format. A TCP tunnel carries the connection to the chosen local IP address and port. Cherry remains responsible for parsing Pomelo, Simple, protobuf, JSON, or any custom application payload.
Before exposing anything, identify the exact listener address, connector port, and protocol in your profile. A listener restricted to 127.0.0.1 can be targeted when the Localtonet client runs on the same machine. If the client runs on another device, the Cherry service must be reachable from that device through an appropriate private interface. Do not broaden the bind address without considering local-network exposure.
Install Cherry in a Go project
Go applications normally manage dependencies through a module. The module name below is an example namespace for a new local project, not a Cherry requirement. If you are adding Cherry to an existing Go module, keep its current module name and run only the dependency installation command in that project.
Create and enter a project directory
Choose a directory for your game server source code. Keep profiles, generated files, and deployment-specific secrets under deliberate source-control policies.
Initialize the Go module
Initialize a module if the directory is not already part of one. Replace the example module path with a namespace appropriate to your project.
Add the Cherry dependency
Use Cherry's documented package path. Go resolves the dependency and records the selected module information in the project.
Confirm dependency resolution
Review command output and the resulting module files. Resolve Go version, network, or module-proxy errors before writing connector configuration.
mkdir cherry-server
cd cherry-server
go mod init example.com/cherry-server
go get github.com/cherry-game/cherry
The final command is Cherry's documented installation command. A successful result means the framework dependency can be resolved in your module. It does not yet prove that a network listener exists, because that requires an application, a valid profile, and connector configuration.
You can ask Go to list the dependency after installation:
go list -m github.com/cherry-game/cherry
If module resolution fails, first recheck go version, the current directory, outbound network access, and whether the directory already belongs to another Go workspace or module. Avoid deleting module files reflexively in an established application because they may contain required dependency selections.
Create and configure the Cherry application
Cherry's minimal documented application configures a profile path, node ID, frontend-node flag, and application mode before starting. Create a main.go file with the following framework startup shape:
package main
import (
cherry "github.com/cherry-game/cherry"
)
func main() {
app := cherry.Configure(
"etc/profile/dev.json",
"game-1",
true,
cherry.Cluster,
)
app.Startup()
}
Each argument has operational consequences:
- Profile path:
etc/profile/dev.jsonis the profile location shown by Cherry's startup example. The path is relative when used exactly as written, so the process working directory affects whether the file can be found. - Node ID:
game-1identifies the node in this example. In a multi-node deployment, node identifiers need to follow the application's own uniqueness and naming policy. - Frontend flag:
truemarks this as a frontend node that accepts client connections. - Mode:
cherry.Clusteris the mode in the documented snippet. A clustered application may require communication or discovery infrastructure specified by its profile. - Startup:
app.Startup()begins Cherry's application lifecycle after configuration.
The example references a profile that is not created by the Go source itself. The supplied Cherry documentation does not establish complete universal contents for that profile, a connector port, application actors, game handlers, or production credentials. Copy the profile and related code from the specific official Cherry example you are implementing, or build them according to your application's connector requirements. Guessing a JSON schema or port would create a configuration that may not match the installed Cherry version.
Choose an evidence-backed starting example
Cherry documents two useful example directions. Its single-node chat example uses a web client, an HTTP server, a WebSocket connector, and JSON messages. It implements rooms, message sending, and broadcasts. This is the closest documented starting point when the objective is a browser-accessible WebSocket service.
Cherry also documents a multi-node distributed game example with web, gateway, center, and game nodes. It includes a larger account and character workflow. That example is more representative of a distributed backend, but it also introduces more processes and dependencies. Do not begin with the distributed topology merely to test remote connectivity. First prove one intended frontend node locally.
Register application behavior before expecting game responses
A connector accepting a socket does not automatically implement gameplay. Actors must register the handlers needed by the application, and the selected serializer and packet parser must agree with the client. Cherry documents local handlers for client requests, remote handlers for cross-node calls, and event handlers for decoupled system notifications.
Cherry supports protobuf by default and also supports JSON. It documents a Pomelo-compatible packet format and a Simple packet format. This means a generic network connection test can prove that a port is reachable, but it cannot prove that login, matchmaking, room creation, or another game operation works. End-to-end verification requires a client that speaks the same connector protocol, packet format, serializer, and application message schema.
Keep environment profiles deliberate
Cherry profiles can represent different development and runtime environments and can be split or combined. Keep development addresses and test credentials separate from production configuration. Validate the profile selected by the process instead of assuming that the source tree's example path is automatically appropriate in a packaged binary, container, or service manager.
If you change the process working directory during deployment, either preserve the expected relative directory structure or adapt the application to use the correct profile location. The evidence supplied for this guide does not define a command-line profile override, so we do not invent one.
Start and verify Cherry locally

Remote tunneling should be the final connectivity step, not the first diagnostic tool. Start the application locally and confirm that its selected connector listens on the expected address and port. This separates Cherry configuration errors from tunnel configuration errors.
Place the required profile and application files
Ensure that the configured profile exists at the path expected by main.go. Include the actors, handlers, connector setup, packet parser, and serializer required by your chosen Cherry example or application.
Build the Go application
Compile the current module so that import, type, and dependency problems appear before runtime.
Run the application from the expected working directory
Start the program where its relative profile path resolves correctly. Watch the console and configured log outputs for initialization failures.
Confirm the local listener
Inspect listening sockets and verify that the configured connector owns the expected port. Use the actual port from your Cherry profile.
Exercise the application protocol
Connect with the matching game or example client. Confirm a real operation, not only that the operating system accepts a TCP connection.
go build .
go run .
On Linux, one general way to inspect listening TCP sockets is:
ss -ltnp
On macOS, a general listener inspection command is:
lsof -nP -iTCP -sTCP:LISTEN
On Windows PowerShell, listening TCP connections can be inspected with:
Get-NetTCPConnection -State Listen
Find the port configured for your Cherry connector. Record both the port and its local bind address. If the process is absent from the listener output, Localtonet cannot make that endpoint work because there is no local service accepting connections.
A basic TCP connection probe can be useful when your operating system has an appropriate networking utility, but it is only a transport check. For a WebSocket deployment, use the web client supplied by your selected example or another client configured for the exact path and message format. For an HTTP endpoint, request a route that your application actually defines. Cherry does not establish one universal health-check URL, so do not assume that / or /health exists.
A socket test proves that something accepted a connection. It does not validate the Pomelo or Simple packet framing, protobuf or JSON serialization, actor routing, authentication, or application handler behavior. Complete at least one real client operation locally before exposing the listener.
Make the Cherry TCP endpoint remotely accessible with Localtonet

After the Cherry endpoint works locally, create a Localtonet TCP tunnel that targets its local IP address and port. The Localtonet client on the selected device establishes an outbound connection to our relay server. The running tunnel provides a public host and port that a compatible remote game client can use.
Creating a tunnel configuration does not mean it is running. You must start it, and it remains available only while the selected client device is connected and the tunnel is running.
Install and run the Localtonet client
Run the Localtonet client on the Cherry host or another device that can reach the Cherry listener over the private network. Use the current installation workflow for your operating system from our platform.
Authenticate and select the client device
Use the device-specific authentication token supplied through your Localtonet account. Do not place the token in source code, screenshots, logs, or public configuration files.
Select an available relay server
Choose an available server or region shown by the current dashboard. Available server codes can change and may vary, so this guide does not hardcode one.
Create the TCP tunnel
Select the TCP tunnel type and point it to the Cherry connector's verified local IP address and port. If both processes run on the same machine and Cherry listens on loopback, the local target can use that loopback address.
Start the tunnel
Use the Start button after reviewing the target. Wait until the selected device and tunnel show a connected, running state.
Connect through the assigned public endpoint
Configure the remote game client with the public host and port assigned to the running tunnel. Keep the Cherry packet format, serializer, and application protocol unchanged unless your application design specifically requires otherwise.
Manage the tunnel from the Localtonet dashboard or REST API. Stop it when remote access is temporarily unnecessary, or delete it when the endpoint should no longer exist. For current client and tunnel guidance, use the Localtonet documentation.
Verify the target address and port before starting the tunnel. A Cherry deployment may also run discovery, database, administration, monitoring, or inter-node services. The client-facing connector is the intended target. Do not expose backend dependencies or administrative listeners unless you have a separate, reviewed access design for them.
What changes in the remote client
The remote client normally replaces the private Cherry address with the assigned Localtonet public host and port. It must still speak the protocol expected by Cherry. A TCP tunnel does not convert raw TCP into HTTP, change Simple framing into Pomelo framing, or transform JSON into protobuf.
If your game client validates a hostname, uses application-level encryption, sends a virtual host, or expects a specific WebSocket URL path, preserve those requirements in the client and server configuration. Those details belong to the Cherry application protocol and are not established by Cherry's minimal startup example.
WebSocket and HTTP deployments
Cherry's single-node chat example demonstrates a web-oriented architecture with an HTTP server, WebSocket connector, and JSON messages. In that design, first verify the web page, WebSocket path, and application messages locally. A browser deployment may involve an HTTP endpoint and a WebSocket endpoint, possibly on the same application listener depending on the example configuration.
Localtonet supports HTTP/s and TCP tunnel families. Use the tunnel family that matches the listener you have actually configured and verified. The supplied Cherry evidence does not establish one universal WebSocket path, port, origin policy, or TLS arrangement, so this guide cannot provide a single WebSocket URL that applies to every Cherry application.
Secure a remotely accessible Cherry server

A remote endpoint should be treated as internet-facing from the moment the tunnel starts. Router configuration is no longer the barrier between the listener and remote clients. Security must therefore exist in the game protocol and application itself.
Add limits appropriate to your application around login attempts, message frequency, packet size, room operations, and resource-intensive actor calls. Cherry includes a synchronization utility package with rate-limiting functionality, but the framework does not automatically define the correct security policy for your game. Limits must reflect legitimate client behavior and should fail safely.
Protect dependency and profile changes through review. A profile may determine which interface receives connections, which discovery mechanism is used, and where logs are written. Avoid placing secrets directly into files that are committed to a public repository. The exact secret-management mechanism depends on your deployment environment and is not prescribed by the available Cherry startup documentation.
In clustered deployments, apply least privilege between nodes as well as at the public connector. The fact that Cherry supports remote actor calls does not mean every node, actor, or operation should be reachable by every other component. Keep public client input separate from trusted internal messages and enforce authorization before routing sensitive operations.
Routine operations and troubleshooting
Start and stop in the correct order
Start Cherry and confirm its listener before starting the Localtonet tunnel. This produces a clear operational state: the public endpoint is activated only after its local target is ready. During maintenance, stop the tunnel first if you want to prevent new remote connections, then gracefully stop Cherry using a supported process signal or your service manager.
Cherry documents graceful handling of SIGINT, SIGQUIT, and SIGTERM. Components stop in reverse registration order. Allow that lifecycle to complete rather than routinely forcing process termination, especially if components flush state, unregister discovery information, or close internal connections during shutdown.
The application cannot find its profile
Recheck the current working directory and the relative path passed to cherry.Configure. With etc/profile/dev.json, the process expects that path below its working directory. A binary launched by a service manager may have a different working directory than an interactive shell.
Also confirm file permissions and exact filename capitalization. Case differences can be hidden on one development filesystem and fail on another. Do not solve the problem by creating an empty JSON file because Cherry still needs the configuration required by your selected application and connectors.
Cherry starts but no port is listening
Confirm that the node is configured as a frontend node, the intended connector is registered, and the profile contains the connector configuration required by the selected example. Inspect Cherry's startup logs for component initialization failures. If the profile selects cluster infrastructure, confirm that required dependencies are reachable.
Search the listener table again using the operating-system commands shown earlier. A service may bind a different interface or port than expected. Update the Localtonet target only after confirming the actual intended listener, not merely after finding any open port owned by the process.
The local port works but the tunnel does not
Verify that the Localtonet client is connected, that the tunnel was explicitly started, and that the selected tunnel points to the same local address and port tested successfully. If the Localtonet client runs on another device, 127.0.0.1 refers to that other device, not the Cherry host. Use the Cherry host's reachable private address in that topology.
Check local network routing and host firewall rules between the Localtonet client device and the Cherry host. Localtonet avoids the need for inbound router port forwarding, but the client device still needs ordinary network reachability to its configured local target.
The remote TCP connection opens but gameplay fails
This usually shifts attention from transport to application protocol. Confirm that the remote client uses the correct packet format, serializer, message IDs, and expected startup sequence. A Pomelo-compatible client cannot automatically communicate with a custom Simple-protocol implementation, and JSON payloads do not automatically match protobuf handlers.
Compare the behavior with the same client against the local endpoint. If local and remote behavior differ, inspect address-dependent application assumptions, WebSocket paths, origin checks, host validation, and client configuration. If both fail, troubleshoot Cherry handlers and serialization before changing the tunnel.
The service stops being remotely reachable
A Localtonet tunnel is available only while the selected device remains connected and the tunnel remains running. Confirm the Cherry process, local listener, Localtonet client, device status, and tunnel status in that order. This sequence identifies whether the failure is in the application, local network path, client connection, or tunnel lifecycle.
Preparing for a persistent deployment
For a long-running server, arrange for the Cherry process and Localtonet client to start under the operating system's normal process-management facilities. Set an explicit working directory for Cherry so its profile path remains predictable. Configure restart behavior cautiously so persistent configuration errors do not create an uncontrolled restart loop.
Monitor at least process status, expected listener state, game-level health, and tunnel connectivity. A listening port is useful but incomplete. A lightweight application operation that traverses parsing, actor routing, and response serialization provides a stronger indication that the game service is functioning.
| Observed result | Likely investigation area | Next check |
|---|---|---|
| Go build fails | Go version, imports, or module dependencies | Run go version and review the compiler output. |
| Profile loading fails | Working directory, path, permissions, or profile contents | Confirm that the configured profile exists and matches the application. |
| No local listener | Frontend flag, connector initialization, or dependency failure | Inspect startup logs and operating-system listener output. |
| Local works, remote endpoint is closed | Localtonet client or tunnel lifecycle | Confirm device connection, target values, and that the tunnel was started. |
| Connection opens, messages fail | Packet format, serialization, handlers, or authentication | Repeat the same operation locally with the same client. |
| Intermittent loss after deployment | Process lifecycle, device connectivity, or application dependencies | Correlate Cherry logs, listener state, and tunnel status. |
Frequently asked questions
What version of Go does Cherry require?
Cherry requires Go 1.24 or newer. Run go version before adding the framework and upgrade Go if the installed release is older.
Does installing Cherry automatically start a game server?
No. go get github.com/cherry-game/cherry adds the framework dependency to a Go module. You still need an application, a valid profile, connector configuration, actors, handlers, serialization, and game-specific logic.
What is Cherry's default TCP or WebSocket port?
The documentation supplied for this guide does not establish a universal default port. The port comes from the profile and connector configuration used by your application or selected example. Verify the real listener locally before configuring Localtonet.
Should I use a TCP or HTTP tunnel for Cherry?
Use a TCP tunnel for a verified native TCP connector. Use the Localtonet HTTP/s family for an HTTP application endpoint. A WebSocket deployment requires you to verify its local HTTP and WebSocket behavior, including its path and application requirements, before choosing the matching publication configuration.
Does Localtonet understand or modify Cherry game packets?
A TCP tunnel forwards connections to the configured local IP address and port. Cherry and the game client remain responsible for Pomelo or Simple framing, protobuf or JSON serialization, authentication, handlers, and gameplay semantics.
Do I need router port forwarding or a public IP address?
No. The Localtonet client establishes an outbound connection to our relay server, so this workflow does not require inbound router port forwarding, inbound firewall changes, VPN setup, or a public IP address.
Can the Localtonet client run on a different machine from Cherry?
Yes, provided the selected client device can reach the Cherry listener over the private network. In that arrangement, do not use 127.0.0.1 as the tunnel target because it would refer to the Localtonet client device itself. Use the reachable private address of the Cherry host.
Is the public Cherry endpoint always available after I create it?
No. Creating a tunnel does not start it. The endpoint is available only while the selected Localtonet device is connected and the tunnel is running. Cherry must also remain active and listening at the configured local target.
Can I expose Cherry's discovery or database services through the same tunnel?
A TCP tunnel targets one configured local endpoint. More importantly, backend discovery, database, internal RPC, and administrative services should not be made public merely to expose the game connector. Publish only the client-facing listener required by the application and keep internal dependencies protected.
Make your verified Cherry connector reachable with Localtonet
Once your TCP, WebSocket, or HTTP application works locally, run our client, select the correct device and relay server, point the matching tunnel at the verified local endpoint, and start remote testing without opening an inbound router port.
Get Started Free โ