Skip to content

Conversation

@Peeja
Copy link
Member

@Peeja Peeja commented Jan 22, 2026

This doesn't necessarily all need to be merged, although it probably wouldn't hurt to. We do need the changes to the gateway server there to make this possible.

A little breakdown here:

  • We need to implement the Delegated Routing spec (or at least the Content Routing API) to make the connection. We point Kubo at the routing endpoint, and that points all requests to the Gupway gateway.
  • The gateway needs to serve all of its content over TLS, or else Kubo will ignore it. It doesn't say anything, it just treats non-TLS HTTP as a protocol it doesn't know and skips it. So, we need to construct a phony cert for localhost and tell Kubo not to verify it. That's safe, because we know we control both ends of the conversation, on the same box.
  • Unfortunately, that setting not to verify TLS doesn't apply to the routing requests. They'll fail with a made up certificate. Fortunately, the routing system is happy to make its requests over plain HTTP if that's where you point it. So, annoyingly, we have to run two separate servers in the gateway process: one for the gateway proper using TLS, and one for the routing API without TLS. The latter is disabled unless you explicitly set a port for it to run on.

Copy link
Member

@alanshaw alanshaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this ❤️

We should defintely remove the TLS stuff before merging.

r.HidePort = true
r.Use(requestLogger(log))
r.Use(middleware.Recover())
r.GET("/routing/v1/providers/*", func(c echo.Context) error {
Copy link
Member

@alanshaw alanshaw Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just add this route to the existing echo server? Oh for the TLS hoop jump?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we need to run one with TLS and one without.

cobra.CheckErr(viper.BindPFlag("gateway.port", serveCmd.Flags().Lookup("port")))

serveCmd.Flags().Int("routing-port", routingPort, "Port for delegated routing server (HTTP, no TLS). Set to 0 to disable.")
cobra.CheckErr(viper.BindPFlag("gateway.routing-port", serveCmd.Flags().Lookup("routing-port")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No dash allowed in TOML keys (like JS).

Suggested change
cobra.CheckErr(viper.BindPFlag("gateway.routing-port", serveCmd.Flags().Lookup("routing-port")))
cobra.CheckErr(viper.BindPFlag("gateway.routing_port", serveCmd.Flags().Lookup("routing-port")))

cobra.CheckErr(viper.BindPFlag("gateway.log_level", serveCmd.Flags().Lookup("log-level")))

serveCmd.Flags().String("tls-cert", "", "Path to TLS certificate file (enables HTTPS)")
cobra.CheckErr(viper.BindPFlag("gateway.tls-cert", serveCmd.Flags().Lookup("tls-cert")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cobra.CheckErr(viper.BindPFlag("gateway.tls-cert", serveCmd.Flags().Lookup("tls-cert")))
cobra.CheckErr(viper.BindPFlag("gateway.tls_cert", serveCmd.Flags().Lookup("tls-cert")))

cobra.CheckErr(viper.BindPFlag("gateway.tls-cert", serveCmd.Flags().Lookup("tls-cert")))

serveCmd.Flags().String("tls-key", "", "Path to TLS key file (enables HTTPS)")
cobra.CheckErr(viper.BindPFlag("gateway.tls-key", serveCmd.Flags().Lookup("tls-key")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cobra.CheckErr(viper.BindPFlag("gateway.tls-key", serveCmd.Flags().Lookup("tls-key")))
cobra.CheckErr(viper.BindPFlag("gateway.tls_key", serveCmd.Flags().Lookup("tls-key")))

// Port is the port to run the gateway on.
Port int `mapstructure:"port" flag:"port" toml:"port"`
// TlsCert is the path to the TLS certificate file. If empty, TLS is disabled.
TlsCert string `mapstructure:"tls-cert" flag:"tls-cert" toml:"tls-cert"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
TlsCert string `mapstructure:"tls-cert" flag:"tls-cert" toml:"tls-cert"`
TlsCert string `mapstructure:"tls_cert" flag:"tls-cert" toml:"tls_cert"`

// TlsCert is the path to the TLS certificate file. If empty, TLS is disabled.
TlsCert string `mapstructure:"tls-cert" flag:"tls-cert" toml:"tls-cert"`
// TlsKey is the path to the TLS key file. If empty, TLS is disabled.
TlsKey string `mapstructure:"tls-key" flag:"tls-key" toml:"tls-key"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
TlsKey string `mapstructure:"tls-key" flag:"tls-key" toml:"tls-key"`
TlsKey string `mapstructure:"tls_key" flag:"tls-key" toml:"tls_key"`

TlsKey string `mapstructure:"tls-key" flag:"tls-key" toml:"tls-key"`
// RoutingPort is the port to use for delegated routing requests. Use 0 to
// disable delegated routing.
RoutingPort int `mapstructure:"routing-port" flag:"routing-port" toml:"routing-port"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
RoutingPort int `mapstructure:"routing-port" flag:"routing-port" toml:"routing-port"`
RoutingPort int `mapstructure:"routing_port" flag:"routing-port" toml:"routing_port"`

@Peeja
Copy link
Member Author

Peeja commented Jan 22, 2026

We should defintely remove the TLS stuff before merging.

Not sure what you mean. How can it work without the TLS stuff?

@alanshaw
Copy link
Member

We should defintely remove the TLS stuff before merging.

Not sure what you mean. How can it work without the TLS stuff?

In my experience TLS termination is almost always done with a reverse proxy. i.e. run an nginx to terminate the SSL and have it proxy to the service wherever it is running.

This is why I queried about the 2 echo servers and I assumed it was for local testing.

Personally I would add the route to the existing echo server and caveat that for delegated routing to work the gateway needs to be deployed with an SSL cert.

"Schema": "peer",
"Protocols": ["transport-ipfs-gateway-http"],
"ID": "k51qzi5uqu5dj26lryc36mobgexftham120h0nu7o4ig6xu56y4h8wdvc4le6t",
"Addrs": ["/dns4/localhost/tcp/%d/tls/http"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this you'll need to use X-Forwarded-Host as /dns/${X-Forwarded-Host}/tls/http otherwise similar to what you're already doing except don't specify TLS - /dns/localhost/tcp/%d/http

Wait, is that why requests weren't working without TLS - because you had /tls in the multiaddr here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, sort of. It's because the /tls has to be there, or it won't recognize it as an address type it can use. It only looks for /tls/http addresses. If there's a plain /http, it'll ignore it.

@Peeja
Copy link
Member Author

Peeja commented Jan 27, 2026

In my experience TLS termination is almost always done with a reverse proxy. i.e. run an nginx to terminate the SSL and have it proxy to the service wherever it is running.

Oh, sure. That's what I'd expect for a "real" server. Here, the intention is to use it purely as a local connection between your local guppy and a local Kubo. This isn't a setup for running a Bitswap service over Guppy (which would be what you're describing, which is not far from this), this is a setup for retrieving directly from Forge to your own machine, but with incremental. resumable retrieval. This is the setup where you have UCAN auth to retrieve, and no one is running a gateway and paying for traffic running through it. Really, it's a hack until we have true resumable retrieval inside Guppy itself.

I think we want to support both, so since this is a hacky setup already, maybe we should require a wrapping TLS server like nginx anyhow. Nginx isn't hard to run, and we can ship a script that sets everything up for you as long as you have Kubo and nginx installed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants