x/tunnel v0.1.0
First release of github.com/restatedev/sdk-go/x/tunnel — a module that serves a Restate SDK deployment over an outbound connection to Restate Cloud's tunnel servers, so a deployment in a private network needs no inbound HTTP listener and no public ingress. It's the Go equivalent of TypeScript's @restatedev/restate-sdk-tunnel and interoperates with the restate-operator's in-process tunnel mode.
Install
go get github.com/restatedev/sdk-go/x/tunnel@v0.1.0Requires github.com/restatedev/sdk-go v1.0.1+.
Usage
Instead of server.Restate.Start (which listens), you build a *server.Restate, wrap it with NewTunnel, and call Start:
package main
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
restate "github.com/restatedev/sdk-go"
"github.com/restatedev/sdk-go/server"
"github.com/restatedev/sdk-go/x/tunnel"
)
type Greeter struct{}
func (Greeter) Greet(ctx restate.Context, name string) (string, error) {
return "You said hi to " + name + "!", nil
}
func main() {
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
srv := server.NewRestate().
Bind(restate.Reflect(Greeter{}))
err := tunnel.NewTunnel(srv,
// Config can either be in-code via options, or via env variables (see godoc for all details)
tunnel.WithRegion("us"),
tunnel.WithEnvironment("env_...", "publickeyv1_..."),
tunnel.WithAuthToken(os.Getenv("RESTATE_AUTH_TOKEN")),
tunnel.WithTunnelName("greeter-v1"),
).Start(ctx) // blocks until ctx is cancelled, then drains + closes
if err != nil {
slog.Error("tunnel exited with error", "err", err.Error())
os.Exit(1)
}
}Once started, the tunnel client connects to Restate cloud and allows to use this process as service deployment.
Start logs the deployment URL on connect; register it (the operator does this for you on Kubernetes):
restate deployments register <deployment-url>Check https://pkg.go.dev/github.com/restatedev/sdk-go/x/tunnel for the full API documentation
Zero-config under the operator
With tunnelMode: in-process the operator injects the RESTATE_INPROC_* env vars, which setups all the necessary configuration entries. The code just needs:
err := tunnel.NewTunnel(srv).Start(ctx)How it works
Dial out (TLS, ALPN h2) → role-flip: Restate Cloud drives the connection as the HTTP/2 client while the SDK serves as the HTTP/2 server (http2.Server.ServeConn) → GET /_/start-tunnel handshake completed via HTTP/2 trailers → each invocation is one stream whose /<scheme>/<host>/<port> prefix is stripped before the request is handed to the reused server.Restate handler (discovery, invoke, and request-identity verification against the signing key).