libp2p / js-libp2p-webrtc-star

libp2p WebRTC transport that includes a discovery mechanism provided by the signalling-star
https://libp2p.io
Other
319 stars 95 forks source link

Documentation does not provide an SSL-friendly setup. #238

Closed 0xjjpa closed 2 years ago

0xjjpa commented 4 years ago

When following 0.27.x libp2p in the browser example, the README describes how to run a signalling server and even points you to this repository (i.e. js-libp2p-webrtc-star). If you run the server (e.g. docker run -p 9090:9090 libp2p/js-libp2p-webrtc-star) and then connect locally (e.g. http://localhost:1234 from parcel index.html), you can see the application up and running. All good so far!

However, whenever you are trying to run the demo behind SSL (e.g. using an online service like Glitch.com or via remote desktop), you will be presented with an SSL error similar to the following one:

Mixed Content: The page at 'https://endurable-eggplant-parmesan.glitch.me/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://34.65.51.50:9090/socket.io/?EIO=3&transport=websocket'. This request has been blocked; this endpoint must be available over WSS.

You can also find the same error if you run parcel index.html --https instead, which is closer to a production setup. In addition, if you try to connect via the browser using a non-local http application, you'll see something like this:

webcrypto.js:12 Uncaught (in promise) Error: Missing Web Crypto API. The most likely cause of this error is that this page is being accessed from an insecure context (i.e. not HTTPS). For more information and possible resolutions see https://github.com/libp2p/js-libp2p-crypto/blob/master/README.md#web-crypto-api
    at Object.exports.get (webcrypto.js:12)
    at Object.exports.generateKey (rsa-browser.js:10)
    at Object.generateKeyPair (rsa-class.js:154)
    at Object.exports.generateKeyPair (index.js:41)
    at Function.exports.create (index.js:207)
    at Function.PeerInfo.create (index.js:47)
    at Function.create (index.js:528)
    at HTMLDocument.<anonymous> (index.js:11)

This can be avoided by providing some instructions to users on how to setup an SSL reverse proxy. For instance, locally one can setup nginx/proxy with a docker-compose.yml file as follows:

version: '3'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./nginx/certs:/etc/nginx/certs
    depends_on:
      - web

  web:
    image: libp2p/js-libp2p-webrtc-star
    environment:
      - VIRTUAL_HOST=localdomain.test
      - VIRTUAL_PORT=9090

Where nginx/certs with the following commands:

$ mkcert localdomain.test
$ mkdir -p nginx/certs
$ cp localdomain.test-key.pem nginx/certs/localdomain.test.key
$ cp localdomain.test.pem nginx/certs/localdomain.test.crt
$ sudo -- sh -c "echo '127.0.0.1 localdomain.test' >> /etc/hosts"

The nginx/certs would look something like this:

➜  $ tree nginx
nginx
└── certs
    ├── hopr.test.crt
    └── hopr.test.key

After running docker-compose up users would see something like the following: image

which can then be used as the actual server.

A similar setup can be achieved on a live server. Either way, it would be ideal if these instructions could be described in your README so beginners could connect easily and check the capabilities of libp2p in the browser. If you think this would be useful, I can happily send a PR with the instructions for the README in addition on how to achieve this on production using something like LE on GCP.

vasco-santos commented 4 years ago

@jjperezaguinaga thanks very much for such a detailed setup. I totally agree that we should make this more clear. Would you like to make a PR for this repo with this? I would like to have a Markdown file with these instructions, and a mention to it in the main README

0xjjpa commented 4 years ago

@vasco-santos Happy to do so! I also think it would be useful to highlight the instructions for “deploy your own node” or even add something like a “Deploy Server” to GCP or AWS so users can also use their own infra instead of just expecting the nodes from libp2p to work. Will do shortly.

0xjjpa commented 4 years ago

@vasco-santos @jacobheun Quick update here. I've created a Terraform module which automates the deployment of a libp2p-webrtc-star server in GCP. You can see its usage here, which powers now https://wrtc-star-001.hoprnet.link/. Everything is automated by a GitHub action which can be seen here. At the moment that setup has a bit of our own infra (e.g. ch datacenter), but would be quite simple to setup in any other datacenter/provider.

For this ticket in particular, perhaps it could be useful to provide an “annex” like “Deployment on SSL using Cloudflare & GCP”. Instead of using Terraform, the average user could use Google's Cloud SDK CLI gcloud and run something like this (defaulted region to Zürich in here):

gcloud compute instances create-with-container wrtc-signaling-star \
--zone=europe-west6-a --machine-type=f1-micro --subnet=default --network-tier=PREMIUM \
--metadata=google-logging-enabled=true --maintenance-policy=MIGRATE \
--tags=http-server,https-server --container-env=PORT=80 \
--boot-disk-size=10GB --boot-disk-type=pd-standard --container-image=libp2p/js-libp2p-webrtc-star:latest \
--container-restart-policy=always

The generated output will produce an IP you can then put behind Cloudflare, and using their Flexible SSL (!) can terminate SSL traffic to allow anyone to connect to it. In this case, running the previous command generated 34.65.66.167, which then in Cloudflare would look like this:

image

Now we have a signaling server behind SSL which can be used in online applications and/or behind https. image

Let me know if this makes sense to you, and I can create a PR with the aforementioned annex.

vasco-santos commented 4 years ago

Hey @jjperezaguinaga

Sorry for the delay, but I wanted to look at this properly first.

First of all, this is super nice and will potentially be important for some users. My biggest concern is the introduction of a lot of concepts/tools that users might not be familiar with, like Terraform, GCP, among others. I usually prefer more iterative approaches for documentation like this. This way, what I would like to see in the beginning of a document for this is a simple configuration using nginx as you provided in the first post of the issue. nginx is usually one of the first tools that developers have contact with regarding deployments. After it, it would come the next steps for more advanced users, including docker/docker-compose, automation and annexes like you suggested (Deployment on SSL using Cloudflare & GCP).

What do you think?

vasco-santos commented 4 years ago

FYI: my goal is to get this documentation into this repo and link it from this larger docs for all libp2p infra https://github.com/libp2p/js-libp2p/pull/718

0xjjpa commented 4 years ago

Hey @vasco-santos, no worries! We appreciate any input you guys can share. We have our own setup and are working on stuff other devs can use in https://github.com/hoprnet/hopr-devops, where we are mounting our app (which uses libp2p underneath) via Docker containers. I agree that for a more generic setup, we can move away from Terraform and GCP, particularly as the learning curve on some of those concepts might be a bit steep for newcomers.

I actually agree with your iterative setup, I already see some work in https://github.com/libp2p/js-libp2p/pull/718, so can add some annexe there. As I've done the nginx setup already locally, I can chip in there.

As a side note, have you successfully deployed bootstrap nodes as Docker images in cloud servers that can successfully dial other nodes using the DHT? I'm facing a bunch of 137 and 139 exit codes when running the nodes when trying to crawl-dial nodes in the network (we have a custom interaction that helps us dial other nodes). This is unrelated to this, but perhaps worth adding in case its something you also have stumbled upon in cloud datacenters.

jacobheun commented 4 years ago

I'm facing a bunch of 137 and 139 exit codes when running the nodes when trying to crawl-dial nodes in the network (we have a custom interaction that helps us dial other nodes).

@jjperezaguinaga can you check your dependencies for stream-to-it? There were some memory leaks there in 0.2.0 that we patched recently, upgrading to 0.2.2 should mitigate the memory related terminations you're seeing.

0xjjpa commented 4 years ago

@jacobheun Thanks! Saw that in one of the issues in the lib, but we have yet to test it. What worked for us was moving away from alpine to buster when creating the Dockerfile. Sadly that doubled the image but for now, it seems to work.

@vasco-santos Let me see if I can add something to libp2p/js-libp2p#718 under 4. describing a quick way to get an SSL certificate w/Let's Encrypt and setting up an nginx load balancer on go-ipfs ports. Will give it a try and send a PR to your PR if successful.

vasco-santos commented 4 years ago

We have our own setup and are working on stuff other devs can use in https://github.com/hoprnet/hopr-devops, where we are mounting our app (which uses libp2p underneath) via Docker containers.

Yes, this can also be super nice for libp2p users. I think there is space for it in the iterative approach.

I actually agree with your iterative setup, I already see some work in libp2p/js-libp2p#718, so can add some annexe there. As I've done the nginx setup already locally, I can chip in there.

My goal is to have the production document for webrtc-star in this module. Then, libp2p/js-libp2p#718 would point to it. The main reason for that is users who will look for such instructions in this repo. The other sections in that PR mean deploying a libp2p node and make more sense in its own repo. What do you think on this?

describing a quick way to get an SSL certificate w/Let's Encrypt and setting up an nginx load balancer on go-ipfs ports. Will give it a try and send a PR to your PR if successful.

Yes please ❤️

0xjjpa commented 4 years ago

@vasco-santos Testing the water in https://github.com/libp2p/js-libp2p/pull/722. For the SSL setup, IMHO we could leverage on @solderjs‘s greenlock.domains to quickly generate the SSL certs when adding a CNAME entry on a given domain. The other alternative could be to ask people to install and run certbot to issue the certs and then provide a sample nginx config to run nginx on top of the go-ipfs daemon. Any preferences?

vasco-santos commented 4 years ago

The nginx + certbot seems the more traditional setup, while greenlock.domains might be the fastest solution. I think we should start with the traditional, but then recommend people solutions that might help them achieve the same with automation/ease, like greenlock.domains and setps like you previously described with terraform.

0xjjpa commented 4 years ago

Perfect, let's go for the nginx + certbot for now.

0xjjpa commented 2 years ago

Seems to have already been completed in #274, thanks!