-
Notifications
You must be signed in to change notification settings - Fork 4
feat: add implementation #2
Changes from 4 commits
2455d11
8229eda
a159564
34df221
b679196
cdbc8f3
f99d5a9
a482dce
6ab04d4
0b6238d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
FROM node:lts-buster | ||
|
||
# Install deps | ||
RUN apt-get update && apt-get install -y | ||
|
||
# Get dumb-init to allow quit running interactively | ||
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && chmod +x /usr/local/bin/dumb-init | ||
|
||
# Setup directories for the `node` user | ||
RUN mkdir -p /home/node/app/hop-relay-server/node_modules && chown -R node:node /home/node/app/hop-relay-server | ||
|
||
WORKDIR /home/node/app/hop-relay-server | ||
|
||
# Install node modules | ||
COPY package.json ./ | ||
# Switch to the node user for installation | ||
USER node | ||
RUN npm install --production | ||
|
||
# Copy over source files under the node user | ||
COPY --chown=node:node ./src ./src | ||
COPY --chown=node:node ./README.md ./ | ||
|
||
ENV DEBUG libp2p* | ||
|
||
# Available overrides (defaults shown): | ||
# Server logging can be enabled via the DEBUG environment variable | ||
CMD [ "/usr/local/bin/dumb-init", "node", "src/bin.js"] |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,2 +1,140 @@ | ||||||
# js-libp2p-hop-relay-server | ||||||
A out of the box libp2p relay server with HOP | ||||||
# js-libp2p-relay-server <!-- omit in toc --> | ||||||
|
||||||
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai) | ||||||
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) | ||||||
[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p) | ||||||
[![](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io) | ||||||
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/libp2p/js-libp2p-relay-server/ci?label=ci&style=flat-square)](https://github.com/libp2p/js-libp2p-relay-server/actions?query=branch%3Amaster+workflow%3Aci+) | ||||||
|
||||||
> An out of the box libp2p relay server with HOP | ||||||
|
||||||
## Lead Maintainer <!-- omit in toc --> | ||||||
|
||||||
[Vasco Santos](https://github.com/vasco-santos) | ||||||
|
||||||
## Table of Contents<!-- omit in toc --> | ||||||
|
||||||
- [Background](#background) | ||||||
- [Usage](#usage) | ||||||
- [Install](#install) | ||||||
- [CLI](#cli) | ||||||
- [Docker](#docker) | ||||||
- [SSL](#ssl) | ||||||
- [Debug](#debug) | ||||||
- [Contribute](#contribute) | ||||||
- [License](#license) | ||||||
|
||||||
## Background | ||||||
|
||||||
Libp2p nodes acting as circuit relay aim to establish connectivity between libp2p nodes (e.g. IPFS nodes) that wouldn't otherwise be able to establish a direct connection to each other. | ||||||
|
||||||
A relay is needed in situations where nodes are behind NAT, reverse proxies, firewalls and/or simply don't support the same transports (e.g. go-libp2p vs. browser-libp2p). The circuit relay protocol exists to overcome those scenarios. Nodes with the `auto-relay` feature enabled can automatically bind themselves on a relay to listen for connections on their behalf. | ||||||
|
||||||
You can read more in its [SPEC](https://github.com/libp2p/specs/tree/master/relay). | ||||||
|
||||||
## Usage | ||||||
|
||||||
### Install | ||||||
|
||||||
```bash | ||||||
> npm install --global libp2p-relay-server | ||||||
``` | ||||||
|
||||||
Now you can use the cli command `libp2p-relay-server` to spawn an out of the box libp2p relay server. | ||||||
|
||||||
### CLI | ||||||
|
||||||
After installing the relay server, you can use its binary. It accepts several arguments: `--peerId`, `--listenMultiaddrs`, `--announceMultiaddrs`, `--metricsMultiaddr`, `--disableMetrics`, `--disablePubsubDiscovery` and `--discoveryTopics`. | ||||||
|
||||||
```sh | ||||||
libp2p-relay-server [--peerId <jsonFilePath>] [--listenMultiaddrs <ma> ... <ma>] [--announceMultiaddrs <ma> ... <ma>] [--metricsMultiaddr <ma>] [--disableMetrics] [--disablePubsubDiscovery] [--discoveryTopics <topic> ... <topic>] | ||||||
``` | ||||||
|
||||||
#### PeerId | ||||||
|
||||||
You can create a [PeerId](https://github.com/libp2p/js-peer-id) via its [CLI](https://github.com/libp2p/js-peer-id#cli). | ||||||
|
||||||
```sh | ||||||
vasco-santos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
libp2p-relay-server --peerId id.json | ||||||
vasco-santos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
``` | ||||||
|
||||||
#### Multiaddrs | ||||||
|
||||||
You can specify the libp2p rendezvous server listen and announce multiaddrs. This server is configured with [libp2p-tcp](https://github.com/libp2p/js-libp2p-tcp) and [libp2p-websockets](https://github.com/libp2p/js-libp2p-websockets) and addresses with this transports should be used. It can always be modified via the API. | ||||||
vasco-santos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
```sh | ||||||
libp2p-relay-server --peerId id.json --listenMultiaddrs '/ip4/127.0.0.1/tcp/15002/ws' '/ip4/127.0.0.1/tcp/8000' --announceMultiaddrs '/dns4/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA' '/dns6/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA' | ||||||
vasco-santos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
``` | ||||||
|
||||||
By default it listens on `/ip4/127.0.0.1/tcp/15002/ws` and has no announce multiaddrs specified. | ||||||
|
||||||
#### Metrics | ||||||
|
||||||
Metrics are enabled by default on `/ip4/127.0.0.1/tcp/8003` via Prometheus. This address can also be modified with: | ||||||
|
||||||
```sh | ||||||
libp2p-relay-server --metricsMultiaddr '/ip4/127.0.0.1/tcp/8000' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to clarify this multiaddr restriction as this should be local only, nodeAddress compatible addresses. Perhaps this should just be a port? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, I will change it to be just the port |
||||||
``` | ||||||
|
||||||
Moreover, metrics can also be disabled with: | ||||||
|
||||||
```sh | ||||||
libp2p-relay-server --disableMetrics | ||||||
``` | ||||||
|
||||||
#### Discovery | ||||||
|
||||||
A discovery module [libp2p/js-libp2p-pubsub-peer-discovery](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery) is configured and enabled by default. It can be disabled with: | ||||||
|
||||||
```sh | ||||||
libp2p-relay-server --disablePubsubDiscovery | ||||||
``` | ||||||
|
||||||
This discovery module uses `_peer-discovery._p2p._pubsub` as a topic for enabling peer discovery. However, other topics can be used with: | ||||||
|
||||||
```sh | ||||||
libp2p-relay-server --discoveryTopics '_peer-discovery._app1._pubsub' '_peer_discovery._app2._pubsub' | ||||||
``` | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd just leave configuring this out, keep it simple. It binds to the global space out of the box, so just avoid people doing the wrong thing. IMO if people need to configure this in depth they can use the config as a template. The point of this repo is basically to get people up and running quickly, so we should just reduce the noise. What's the bare minimum I need to do to get this running? The readme should focus on that. I think a consistent PeerId and Announce addresses are the only thing I should actually need to set. I'd prioritize and separate the need to have, from the optional stuff. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I divided them in two now. The required/recommended is in the usage section: Then a new configuration section created for fine tuning of the image |
||||||
|
||||||
### Docker | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are 2 docker sections. Is this necessary? There is definitely duplicate content here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it includes the other configurable options that are not required/recommended as the CLI. I can look into simplifying it a bit, but I think it does not make sense to merge them as they should really be in the same section as the other optional parameters |
||||||
|
||||||
When running the relay server in Docker, you can configure the same parameters via environment variables, as follows: | ||||||
|
||||||
```sh | ||||||
PEER_ID='./id.json' | ||||||
LISTEN_MULTIADDRS='/ip4/127.0.0.1/tcp/15002/ws,/ip4/127.0.0.1/tcp/8000' | ||||||
ANNOUNCE_MULTIADDRS='/dns4/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA,/dns6/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA' | ||||||
METRICS_MULTIADDR='/ip4/127.0.0.1/tcp/8000' | ||||||
DISABLE_METRICS='true' | ||||||
DISABLE_PUBSUB_DISCOVERY='true' | ||||||
DISCOVERY_TOPICS='_peer-discovery._app1._pubsub,_peer_discovery._app2._pubsub' | ||||||
``` | ||||||
|
||||||
Please note that you should expose expose the used ports with the docker run command. The default ports used are `8003` for the metrics and `150003` for the websockets listener | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, I don't see any defaults aside from metrics. The docker commands include them, but there aren't defaults in the code unless I am missing something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, perhaps the example below created confusion. I added now So, the default is in the |
||||||
|
||||||
```sh | ||||||
docker build NAME -t libp2p-relay | ||||||
docker run -p 8003:8003 -p 15002:15002 -p 8000:8000 -e LISTEN_MULTIADDRS='/ip4/127.0.0.1/tcp/15002/ws,/ip4/127.0.0.1/tcp/8000' -d libp2p-relay | ||||||
``` | ||||||
|
||||||
### SSL | ||||||
|
||||||
You should setup an SSL certificate with nginx and proxy to the API. You can use a service that already offers an SSL certificate with the server and configure nginx, or you can create valid certificates with for example [Letsencrypt](https://certbot.eff.org/lets-encrypt/osx-nginx). Letsencrypt won’t give you a cert for an IP address (yet) so you need to connect via SSL to a domain name. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed right now, but it would be cool to see an example dockerfile extending this one, templated with nginx and letsencrypt. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this would be good! I added it in the libp2p production guides README libp2p/js-libp2p#804 (comment) as it should probably be not specific to the relay. We can also link it from here afterwards. |
||||||
|
||||||
With this, you should specify in your relay the announce multiaddrs for your listening transports. This is specially important for browser peers that will leverage this relay, as browser nodes can only dial peers behind a `DNS+WSS` multiaddr. | ||||||
|
||||||
### Debug | ||||||
|
||||||
You can debug the relay by setting the `DEBUG` environment variable. For instance, you can set it to `libp2p*`. | ||||||
vasco-santos marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
## Contribute | ||||||
|
||||||
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-relay-server/issues)! | ||||||
|
||||||
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). | ||||||
|
||||||
[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) | ||||||
|
||||||
## License | ||||||
|
||||||
MIT - Protocol Labs 2020 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,57 @@ | ||
{ | ||
"name": "libp2p-hop-relay-server", | ||
"name": "libp2p-relay-server", | ||
"version": "0.0.0", | ||
"description": "A out of the box libp2p relay server with HOP", | ||
"leadMaintainer": "Vasco Santos <santos.vasco10@gmail.com>", | ||
"main": "src/index.js", | ||
"bin": { | ||
"libp2p-relay-server": "src/bin.js" | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"lint": "aegir lint", | ||
"test": "aegir test -t node", | ||
"test:node": "aegir test -t node", | ||
"build": "aegir build", | ||
"release": "aegir release", | ||
"release-minor": "aegir release --type minor", | ||
"release-major": "aegir release --type major", | ||
"docs": "aegir docs", | ||
"size": "aegir build -b" | ||
}, | ||
"files": [ | ||
"src", | ||
"dist" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/vasco-santos/js-libp2p-hop-relay-server.git" | ||
}, | ||
"keywords": [ | ||
"libp2p" | ||
"libp2p", | ||
"relay", | ||
"auto relay", | ||
"hop" | ||
], | ||
"author": "", | ||
"author": "Vasco Santos <santos.vasco10@gmail.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/vasco-santos/js-libp2p-hop-relay-server/issues" | ||
}, | ||
"homepage": "https://github.com/vasco-santos/js-libp2p-hop-relay-server#readme" | ||
"homepage": "https://github.com/vasco-santos/js-libp2p-hop-relay-server#readme", | ||
"dependencies": { | ||
"libp2p": "libp2p/js-libp2p#0.30.x", | ||
"libp2p-gossipsub": "^0.7.0", | ||
"libp2p-mplex": "^0.10.1", | ||
"libp2p-noise": "^2.0.1", | ||
"libp2p-pubsub-peer-discovery": "^3.0.0", | ||
"libp2p-tcp": "^0.15.1", | ||
"libp2p-websockets": "^0.14.0", | ||
"menoetius": "0.0.2", | ||
"minimist": "^1.2.5", | ||
"multiaddr": "^8.1.1", | ||
"peer-id": "^0.14.2" | ||
}, | ||
"devDependencies": { | ||
"aegir": "^29.1.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#!/usr/bin/env node | ||
|
||
'use strict' | ||
|
||
// Usage: $0 [--peerId <jsonFilePath>] [--listenMultiaddrs <ma> ... <ma>] [--announceMultiaddrs <ma> ... <ma>] | ||
// [--metricsMultiaddr <ma>] [--disableMetrics] [--disablePubsubDiscovery] [--discoveryTopics <topic> ... <topic>] | ||
|
||
/* eslint-disable no-console */ | ||
|
||
const debug = require('debug') | ||
const log = debug('libp2p:relay:bin') | ||
|
||
const fs = require('fs') | ||
const http = require('http') | ||
const menoetius = require('menoetius') | ||
const argv = require('minimist')(process.argv.slice(2)) | ||
|
||
const multiaddr = require('multiaddr') | ||
const PeerId = require('peer-id') | ||
|
||
const { getAnnounceAddresses, getListenAddresses, getDiscoveryTopics } = require('./utils') | ||
const createRelay = require('./index') | ||
|
||
async function main () { | ||
// Metrics | ||
let metricsServer | ||
const metrics = !(argv.disableMetrics || process.env.DISABLE_METRICS) | ||
const metricsMa = multiaddr(argv.metricsMultiaddr || argv.ma || process.env.METRICS_MULTIADDR || '/ip4/0.0.0.0/tcp/8003') | ||
const metricsAddr = metricsMa.nodeAddress() | ||
|
||
// multiaddrs | ||
const listenAddresses = getListenAddresses(argv) | ||
const announceAddresses = getAnnounceAddresses(argv) | ||
|
||
log(`listenAddresses: ${listenAddresses.map((a) => a)}`) | ||
announceAddresses.length && log(`announceAddresses: ${announceAddresses.map((a) => a)}`) | ||
|
||
// Discovery | ||
const pubsubDiscoveryEnabled = !(argv.disablePubsubDiscovery || process.env.DISABLE_PUBSUB_DISCOVERY) | ||
const pubsubDiscoveryTopics = getDiscoveryTopics(argv) | ||
|
||
// PeerId | ||
let peerId | ||
if (argv.peerId || process.env.PEER_ID) { | ||
const peerData = fs.readFileSync(argv.peerId || process.env.PEER_ID) | ||
peerId = await PeerId.createFromJSON(JSON.parse(peerData)) | ||
log('PeerId provided was loaded.') | ||
} else { | ||
peerId = await PeerId.create() | ||
log('You are using an automatically generated peer.') | ||
log('If you want to keep the same address for the server you should provide a peerId with --peerId <jsonFilePath>') | ||
} | ||
|
||
// Create Relay | ||
const relay = await createRelay({ | ||
peerId, | ||
listenAddresses, | ||
announceAddresses, | ||
pubsubDiscoveryEnabled, | ||
pubsubDiscoveryTopics | ||
}) | ||
jacobheun marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
await relay.start() | ||
console.log('Relay server listening on:') | ||
relay.multiaddrs.forEach((m) => console.log(m)) | ||
|
||
if (metrics) { | ||
log('enabling metrics') | ||
metricsServer = http.createServer((req, res) => { | ||
if (req.url !== '/metrics') { | ||
res.statusCode = 200 | ||
res.end() | ||
} | ||
}) | ||
|
||
menoetius.instrument(metricsServer) | ||
|
||
metricsServer.listen(metricsAddr.port, metricsAddr.address, () => { | ||
console.log(`metrics server listening on ${metricsAddr.port}`) | ||
}) | ||
} | ||
|
||
const stop = async () => { | ||
console.log('Stopping...') | ||
await relay.stop() | ||
metricsServer && await metricsServer.close() | ||
process.exit(0) | ||
} | ||
|
||
process.on('SIGTERM', stop) | ||
process.on('SIGINT', stop) | ||
} | ||
|
||
main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the size of this image?
I'd take a look at libp2p/js-libp2p-webrtc-star#223 to see the improvements made there. Buster likely has a lot more than is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very smaller this one! thanks