Skip to content
This repository was archived by the owner on Mar 14, 2023. It is now read-only.

Commit 6defd68

Browse files
feat: add implementation (#2)
* feat: add implementation * chore: apply suggestions from code review Co-authored-by: Jacob Heun <[email protected]>
1 parent 09b8ba5 commit 6defd68

File tree

9 files changed

+537
-16
lines changed

9 files changed

+537
-16
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ name: ci
22
on:
33
push:
44
branches:
5-
- master
5+
- main
66
pull_request:
77
branches:
8-
- master
8+
- main
99

1010
jobs:
1111
check:
@@ -14,13 +14,6 @@ jobs:
1414
- uses: actions/checkout@v2
1515
- run: yarn
1616
- run: yarn lint
17-
- run: yarn build
18-
- uses: gozala/[email protected]
19-
- run: yarn aegir dep-check -- -i aegir
20-
- uses: ipfs/aegir/actions/bundle-size@master
21-
name: size
22-
with:
23-
github_token: ${{ secrets.GITHUB_TOKEN }}
2417
test-node:
2518
needs: check
2619
runs-on: ${{ matrix.os }}

Dockerfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
FROM node:lts-alpine
2+
3+
# Install deps
4+
RUN apk add --update git build-base python3
5+
6+
# Get dumb-init to allow quit running interactively
7+
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
8+
9+
# Setup directories for the `node` user
10+
RUN mkdir -p /home/node/app/hop-relay-server/node_modules && chown -R node:node /home/node/app/hop-relay-server
11+
12+
WORKDIR /home/node/app/hop-relay-server
13+
14+
# Install node modules
15+
COPY package.json ./
16+
# Switch to the node user for installation
17+
USER node
18+
RUN npm install --production
19+
20+
# Copy over source files under the node user
21+
COPY --chown=node:node ./src ./src
22+
COPY --chown=node:node ./README.md ./
23+
24+
ENV DEBUG libp2p*
25+
26+
# Available overrides (defaults shown):
27+
# Server logging can be enabled via the DEBUG environment variable
28+
CMD [ "/usr/local/bin/dumb-init", "node", "src/bin.js"]

README.md

Lines changed: 163 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,163 @@
1-
# js-libp2p-hop-relay-server
2-
A out of the box libp2p relay server with HOP
1+
# js-libp2p-relay-server <!-- omit in toc -->
2+
3+
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
4+
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
5+
[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
6+
[![](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io)
7+
[![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+)
8+
9+
> An out of the box libp2p relay server with HOP
10+
11+
## Lead Maintainer <!-- omit in toc -->
12+
13+
[Vasco Santos](https://github.com/vasco-santos)
14+
15+
## Table of Contents<!-- omit in toc -->
16+
17+
- [Background](#background)
18+
- [Usage](#usage)
19+
- [Install](#install)
20+
- [CLI](#cli)
21+
- [Docker](#docker)
22+
- [SSL](#ssl)
23+
- [Configuration](#configuration)
24+
- [Metrics](#metrics)
25+
- [Discovery](#discovery)
26+
- [Docker](#docker)
27+
- [Debug](#debug)
28+
- [Contribute](#contribute)
29+
- [License](#license)
30+
31+
## Background
32+
33+
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.
34+
35+
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.
36+
37+
You can read more in its [SPEC](https://github.com/libp2p/specs/tree/master/relay).
38+
39+
## Usage
40+
41+
### Install
42+
43+
```bash
44+
> npm install --global libp2p-relay-server
45+
```
46+
47+
Now you can use the cli command `libp2p-relay-server` to spawn an out of the box libp2p relay server.
48+
49+
### CLI
50+
51+
After installing the relay server, you can use its binary. It accepts several arguments: `--peerId`, `--listenMultiaddrs`, `--announceMultiaddrs`, `--metricsPort`, `--disableMetrics` and `--disablePubsubDiscovery`.
52+
53+
```sh
54+
libp2p-relay-server [--peerId <jsonFilePath>] [--listenMultiaddrs <ma> ... <ma>] [--announceMultiaddrs <ma> ... <ma>] [--metricsPort <port>] [--disableMetrics] [--disablePubsubDiscovery]
55+
```
56+
57+
The main configuration you *should* include are the `PeerId` and `Multiaddrs`, which are detailed next. Using a consistent PeerId will ensure your node's identity is consistent across restarts, and the Multiaddrs will allow you to appropriate bind your local and external addresses so that other peers can connect to you.
58+
59+
#### PeerId
60+
61+
You can create a [PeerId](https://github.com/libp2p/js-peer-id) via its [CLI](https://github.com/libp2p/js-peer-id#cli).
62+
63+
Once you have a generated PeerId json file, you can start the relay with that PeerId by specifying its path via the `--peerId` flag:
64+
65+
```sh
66+
peer-id --type=ed25519 > id.json
67+
libp2p-relay-server --peerId ./id.json
68+
```
69+
70+
#### Multiaddrs
71+
72+
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), so you will only be able to specify addresses for these transports.
73+
74+
```sh
75+
libp2p-relay-server --peerId /path/to/peer-id.json --listenMultiaddrs '/ip4/127.0.0.1/tcp/15002/ws' '/ip4/127.0.0.1/tcp/8001' --announceMultiaddrs '/dns4/test.io/tcp' '/dns4/test.io/tcp/443/wss'
76+
```
77+
78+
By default it listens on `/ip4/127.0.0.1/tcp/8000` and `/ip4/127.0.0.1/tcp/15003/ws`. It has no announce multiaddrs specified.
79+
80+
### Docker
81+
82+
When running the relay server in Docker, you can configure the same parameters via environment variables, as follows:
83+
84+
```sh
85+
PEER_ID='/etc/opt/relay/id.json'
86+
LISTEN_MULTIADDRS='/ip4/127.0.0.1/tcp/15002/ws,/ip4/127.0.0.1/tcp/8001'
87+
ANNOUNCE_MULTIADDRS='/dns4/test.io/tcp/443/wss,/dns6/test.io/tcp/443/wss'
88+
```
89+
90+
Please note that you should expose the listening ports with the docker run command. The default ports used are `8003` for the metrics, `8000` for the tcp listener and `150003` for the websockets listener.
91+
92+
Example:
93+
94+
```sh
95+
peer-id --type=ed25519 > id.json
96+
docker build . -t libp2p-relay
97+
docker run -p 8003:8003 -p 15002:15002 -p 8000:8000 \
98+
-e LISTEN_MULTIADDRS='/ip4/127.0.0.1/tcp/8000,/ip4/127.0.0.1/tcp/15002/ws' \
99+
-e ANNOUNCE_MULTIADDRS='/dns4/localhost/tcp/8000,/dns4/localhost/tcp/15002/ws' \
100+
-e PEER_ID='/etc/opt/relay/id.json' \
101+
-v $PWD/id.json:/etc/opt/relay/id.json \
102+
-d libp2p-relay
103+
```
104+
105+
### SSL
106+
107+
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.
108+
109+
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.
110+
111+
## Configuration
112+
113+
Besides the `PeerId` and `Multiaddrs`, this server can also have other configurations for fine tuning.
114+
115+
### Metrics
116+
117+
Metrics are enabled by default on `/ip4/127.0.0.1/tcp/8003` via Prometheus. This port can also be modified with:
118+
119+
```sh
120+
libp2p-relay-server --metricsPort '8008'
121+
```
122+
123+
Moreover, metrics can also be disabled with:
124+
125+
```sh
126+
libp2p-relay-server --disableMetrics
127+
```
128+
129+
### Discovery
130+
131+
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:
132+
133+
```sh
134+
libp2p-relay-server --disablePubsubDiscovery
135+
```
136+
137+
### Docker
138+
139+
On docker you can also specify the configurations above with the following environment variables:
140+
141+
```sh
142+
METRICS_PORT='8008'
143+
DISABLE_METRICS='true'
144+
DISABLE_PUBSUB_DISCOVERY='true'
145+
```
146+
147+
Please note that you should expose expose the used ports with the docker run command.
148+
149+
### Debug
150+
151+
You can debug the relay by setting the `DEBUG` environment variable. For instance, you can set it to `libp2p*`. These logs can be noisy so you may wish to tune the namespaces that are logging, see the [Debug module](https://github.com/visionmedia/debug) for detailed usage.
152+
153+
## Contribute
154+
155+
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-relay-server/issues)!
156+
157+
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
158+
159+
[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md)
160+
161+
## License
162+
163+
MIT - Protocol Labs 2020

package.json

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,57 @@
11
{
2-
"name": "libp2p-hop-relay-server",
2+
"name": "libp2p-relay-server",
33
"version": "0.0.0",
44
"description": "A out of the box libp2p relay server with HOP",
5+
"leadMaintainer": "Vasco Santos <[email protected]>",
56
"main": "src/index.js",
7+
"bin": {
8+
"libp2p-relay-server": "src/bin.js"
9+
},
610
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
11+
"lint": "aegir lint",
12+
"test": "aegir test -t node",
13+
"test:node": "aegir test -t node",
14+
"build": "aegir build",
15+
"release": "aegir release",
16+
"release-minor": "aegir release --type minor",
17+
"release-major": "aegir release --type major",
18+
"docs": "aegir docs",
19+
"size": "aegir build -b"
820
},
21+
"files": [
22+
"src",
23+
"dist"
24+
],
925
"repository": {
1026
"type": "git",
1127
"url": "git+https://github.com/vasco-santos/js-libp2p-hop-relay-server.git"
1228
},
1329
"keywords": [
14-
"libp2p"
30+
"libp2p",
31+
"relay",
32+
"auto relay",
33+
"hop"
1534
],
16-
"author": "",
35+
"author": "Vasco Santos <[email protected]>",
1736
"license": "MIT",
1837
"bugs": {
1938
"url": "https://github.com/vasco-santos/js-libp2p-hop-relay-server/issues"
2039
},
21-
"homepage": "https://github.com/vasco-santos/js-libp2p-hop-relay-server#readme"
40+
"homepage": "https://github.com/vasco-santos/js-libp2p-hop-relay-server#readme",
41+
"dependencies": {
42+
"libp2p": "libp2p/js-libp2p#0.30.x",
43+
"libp2p-gossipsub": "^0.7.0",
44+
"libp2p-mplex": "^0.10.1",
45+
"libp2p-noise": "^2.0.1",
46+
"libp2p-pubsub-peer-discovery": "^3.0.0",
47+
"libp2p-tcp": "^0.15.1",
48+
"libp2p-websockets": "^0.14.0",
49+
"menoetius": "0.0.2",
50+
"minimist": "^1.2.5",
51+
"multiaddr": "^8.1.1",
52+
"peer-id": "^0.14.2"
53+
},
54+
"devDependencies": {
55+
"aegir": "^29.1.0"
56+
}
2257
}

src/bin.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env node
2+
3+
'use strict'
4+
5+
// Usage: $0 [--peerId <jsonFilePath>] [--listenMultiaddrs <ma> ... <ma>] [--announceMultiaddrs <ma> ... <ma>]
6+
// [--metricsPort <port>] [--disableMetrics] [--disablePubsubDiscovery]
7+
8+
/* eslint-disable no-console */
9+
10+
const debug = require('debug')
11+
const log = debug('libp2p:relay:bin')
12+
13+
const fs = require('fs')
14+
const http = require('http')
15+
const menoetius = require('menoetius')
16+
const argv = require('minimist')(process.argv.slice(2))
17+
18+
const PeerId = require('peer-id')
19+
20+
const { getAnnounceAddresses, getListenAddresses } = require('./utils')
21+
const createRelay = require('./index')
22+
23+
async function main () {
24+
// Metrics
25+
let metricsServer
26+
const metrics = !(argv.disableMetrics || process.env.DISABLE_METRICS)
27+
const metricsPort = argv.metricsPort || argv.mp || process.env.METRICS_PORT || '8003'
28+
29+
// multiaddrs
30+
const listenAddresses = getListenAddresses(argv)
31+
const announceAddresses = getAnnounceAddresses(argv)
32+
33+
log(`listenAddresses: ${listenAddresses.map((a) => a)}`)
34+
announceAddresses.length && log(`announceAddresses: ${announceAddresses.map((a) => a)}`)
35+
36+
// Discovery
37+
const pubsubDiscoveryEnabled = !(argv.disablePubsubDiscovery || process.env.DISABLE_PUBSUB_DISCOVERY)
38+
39+
// PeerId
40+
let peerId
41+
if (argv.peerId || process.env.PEER_ID) {
42+
const peerData = fs.readFileSync(argv.peerId || process.env.PEER_ID)
43+
peerId = await PeerId.createFromJSON(JSON.parse(peerData))
44+
log('PeerId provided was loaded.')
45+
} else {
46+
peerId = await PeerId.create()
47+
log('You are using an automatically generated peer.')
48+
log('If you want to keep the same address for the server you should provide a peerId with --peerId <jsonFilePath>')
49+
}
50+
51+
// Create Relay
52+
const relay = await createRelay({
53+
peerId,
54+
listenAddresses,
55+
announceAddresses,
56+
pubsubDiscoveryEnabled
57+
})
58+
59+
await relay.start()
60+
console.log('Relay server listening on:')
61+
relay.multiaddrs.forEach((m) => console.log(m))
62+
63+
if (metrics) {
64+
log('enabling metrics')
65+
metricsServer = http.createServer((req, res) => {
66+
if (req.url !== '/metrics') {
67+
res.statusCode = 200
68+
res.end()
69+
}
70+
})
71+
72+
menoetius.instrument(metricsServer)
73+
74+
metricsServer.listen(metricsPort, '0.0.0.0', () => {
75+
console.log(`metrics server listening on ${metricsPort}`)
76+
})
77+
}
78+
79+
const stop = async () => {
80+
console.log('Stopping...')
81+
await relay.stop()
82+
metricsServer && await metricsServer.close()
83+
process.exit(0)
84+
}
85+
86+
process.on('SIGTERM', stop)
87+
process.on('SIGINT', stop)
88+
}
89+
90+
main()

0 commit comments

Comments
 (0)