Feasibility of hosting Teddycloud

Among friends and family, the new TeddyCloud is big :smile:

Now I started to think what needs to be taken into account when hosting Teddycloud for many.

  1. Should I create multiple Box-certs or simply use one for all boxes
  2. Assuming all boxes are ESP32, is it enough to flash them with the cloud name being my hosted DNS address?
  3. I am going to supply a dedicated IPv4 address for port 443 communication
  4. Using v0.4.5 I am going to put the web frontend behind a reverse proxy, which does some user authentication and SSL on another IP address.

Anything I forgot to consider?

Thanks,
Alex

I would still wait for a later version.

Will you host it internally or externally?

Besides that…

Different certs are mostly relevant

A) if you have different box versions and want to do firmware updates

B) if different households which shall not get all tonies of all participating people.

Be aware, that the gui does not (yet?) support different certs. I am not sure how the case 2 households with different tonies which shall only be owned by one, will be handled. I assume there is no distinction on teddycloud side, but still on boxine. Maybe @0xbadbee can enlighten this a little bit?

You use the same CA for all boxes, as it must fit to your server.
The client certificates you don’t need to exchange.

Yes

This is the easiest way to go. The toniebox has no SNI support. There may be a way to use a reverse proxy that reroutes all TLS traffic to a specific backend host, if no SNI is sent. (Don’t know in detail how this works, just a theory)

This is the way to go, but this won’t protect the API of the Toniebox and anybody knowing the endpoint could access your content files.

Beside all that, be sure you use the docker variant + the ubuntu version, as this protects against many security related bugs.

1 Like

Both, authenticated access to your backend(s) and routing traffic based on the client certificate behind a reverse proxy (e.g. nginx) w/o SNI information can be resolved using mTLS on your catchall domain.

Regarding acess to the web ui(s) the same teddycloud(s) may be exposed using SNI information and a authentication mechanism of your choice, e.g. http basic authentication.

1 Like

Would you happen to have an example for Haproxy on how to do this? Looks like SNI and mTLS is rather exclusive. One is an HTTP feature the other is part of the TLS handshake.

I wouldn’t want users with arbitrary client certs to go down the mTLS road when they actually want to connect to any of the websites I run on the machine…

Thanks,
Alex

I do not have a HAProxy configuration but porting the nginx configuration to HAProxy should be straightforward.

The following nginx configuration uses mTLS w/ a mapping to allow clients based on the fingerprint of their certificate.

In this example teddycloud runs on port 443 and nginx on 8443. In my setup both services are Containerized running in one pod and I ingress traffic on the host ip from port 443 to the nginx container on port 8443.

This allows specified toniebox clients to connect to teddycloud through nginx.

catchall.tld.conf (nginx)

map $ssl_client_fingerprint $reject {
	default 1;

	"b571ef0c5841a7c23bfce63f1a20286fcfcfcfcf"	0;
}

server {
	listen 8443 ssl;
	listen [::]:8443;
	server_name _;

	ssl_certificate /etc/ssl/certs/server/ttt-fullchain.pem;
	ssl_certificate_key /etc/ssl/certs/server/ttt.pem;

	ssl_client_certificate /etc/ssl/certs/client/ca.pem;
	ssl_verify_client optional_no_ca;

	root /usr/share/nginx/html/server;

	location / {
		if ($reject) {
			return 403;
		}
		set $upstream 127.0.0.1:443;
 		proxy_pass https://$upstream$request_uri;
		proxy_ssl_conf_command Options UnsafeLegacyRenegotiation;
	}
}

For access via web browsers you can expose the same teddycloud instance based on the SNI hostname using a separate nginx configuration file for the corresponding DNS name.

Best
Christian

A post was split to a new topic: Reflash ESP32 to change hostname

Just for reference, answering this from all the useful pieces of information I received…

In the flash file only the Boxine CA is replaced by TeddyCloud’s CA.
The existing box certs are dumped of course in order to be used by TeddyCloud when talking to Boxine.

The config.overlay.ini file allows for proper configuration of multiple boxes - each referenced by their dumped client certificates.

There will be more or less soon a update in the new /web gui where you can edit the settings for each known tonieBox. Have a look here: https://github.com/toniebox-reverse-engineering/teddycloud_web/issues/20

A first poc (readonly) is already in develop of teddycloud.

Feel free to add additional ideas or feature requests :slight_smile:

1 Like

With release 0.5.2 hosting TeddyCloud becomes a thing :slight_smile:

The only technical challenge is running the SSL backend without a second public IP address. If you use NGINX as a reverse proxy you’ll find a way to do it above.
In case of HAProxy I am using the following snippet:

global
...
    crt-base /usr/local/etc/haproxy/certs
...
defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    option  forwardfor
...
userlist TeddyCloudUsers
    user teddy insecure-password SomeStrongPasswordHerePlease
...
frontend tcp-in
    bind *:443,[::]:443 v6only
    mode tcp

    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    use_backend tcp2http if { req.ssl_sni -i tc.example.org }
    use_backend tcp2http if { req.ssl_sni -i regular.site1.com }
    use_backend tcp2http if { req.ssl_sni -i regular.site2.com }
...
    use_backend tcp2http if { req.ssl_sni -i final.regular.site.com }

    default_backend teddycloud


frontend http-in
    bind *:80,[::]:80 v6only
    bind 127.0.0.1:10443 alpn h2,http/1.1 ssl crt /usr/local/etc/haproxy/certs accept-proxy
...
    acl teddycloud hdr(host) tc.example.org
    acl teddycloud_auth http_auth(TeddyCloudUsers)
    http-request auth if teddycloud !teddycloud_auth
    use_backend teddycloud_web if teddycloud
...
    default_backend internalserver


backend tcp2http
    mode tcp
    server haproxy-loopback 127.0.0.1:10443 check send-proxy-v2


backend teddycloud
    mode tcp
    server teddycloud teddycloud:443 no-check


backend teddycloud_web
    mode http
    server teddycloud_web teddycloud:80 no-check
 

backend internalserver
    server internalserver apache:80
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    http-request add-header X-Forwarded-Host %[hdr(Host)] if { ssl_fc }

The cool thing about HAProxy is that it can act as a TCP proxy. The benefit of which is that it does not have to terminate the SSL connection (no unsafe legacy renegotiation with the actual backend, no need to share any certificates). Unfortunatly the only piece of information passed at layer 4 is the SSL connection setup (no certificates or anything here) - the only useful thing is the SNI though.

It would be easy to route to the Teddycloud backend based on the SNI, but here of all things the box does NOT pass an SNI.

Hence, the setup needs to tediously document all hosted domains and route them based on SNI to the actual internal server.
The default routing will be applied to all SSL traffic WITHOUT SNI (= our TonieBoxes) or without specified SNI.

As a bonus I included BasicAuth authentication for the TeddyCloud frontend.

this should also work with traefik and the TLS passthrough

Indeed Traefik does support TCP routing as well.
I don’t know if you can mix TLS termination though.

I’ll try to come up with a Traefik example and post it here.

Hi,
was anyone able to configure Caddy as reverse proxy?

I have configured a normal reverse proxy for my subdomain (by default it creates its own certificates), but no access from the Toniebox appears in the access log.
Switching off auto https and linking the Teddycloud certificates for this subdomain did not help either.

Any further news on this? I am quite interested to host teddycloud on my server and make it available there

You can use nginx or Haproxy as described above.
Just make sure to setup basic auth in the reverse proxy for now.