The nym-bridge binary runs the server side listener for the transports defined by the bridge configuration. The binary can be built using:
cargo build --release -p nym-bridge -p bridge-cfg
# sudo cp target/release/nym-bridge /usr/local/bin/The bridge-cfg tool is provided to assist with key generation and configuration
management -- for more details on automatic configuration see
bridge-cfg/README.md.
This tool assumes that the nym-bridge is going to be run alongside a nym-node
# Try a dry run to preview the configuration changes
bridge-cfg --gen --dry-run -o /etc/nym/bridges.toml
# Allow configuration changes to be persisted
bridge-cfg --gen -o /etc/nym/bridges.tomlA systemd service file is provided to help run the nym-bridge as a daemon
# (make any modifications to the service file)
sudo cp service/nym-bridge.service /etc/systemd/system/
sudo systemctl enable nym-bridge
sudo systemctl start nym-bridgeExample nym-bridge systemd service file
[Unit]
Description=nym-bridge daemon
# Make sure the network is online before this starts
After=NetworkManager.service systemd-resolved.service nym-node.service
# Set a limit to the rate / number of restarts to prevent fail busy loop
# in case of misconfiguration or something
StartLimitBurst=5
StartLimitIntervalSec=30
[Service]
# User=<USER>
# Group=<USER>
# Type=simple
LimitNOFile=65536
ExecStart=/usr/local/bin/nym-bridge
Restart=on-abnormal
RestartSec=2
[Install]
WantedBy=multi-user.targetThe nym-bridge binary (and the default systemd service file) assumes that the bridge configuration file is in a default location (/etc/nym/default-nym-node/bridges.toml), so if the path of the bridge configuration is not the default location, the systemd service can be modified to accommodate it.
[Service]
LimitNOFile=65536
- ExecStart=/usr/local/bin/nym-bridge
+ ExecStart=/usr/local/bin/nym-bridge -c <path to bridge config file>The nym node requires minimal changes. All we need it to do (for now) is to serve the client parameters at a new endpoint in the self-described API.
This requires the changes in nymtech/nym#6035. While these changes are implemented off of develop, they can be pretty easily cherrypicked back to feta. Also they will be merged and squashed to a single commit ASAP.
So for now a manual build of the nym-node is required, however we can easily create a patch release (and build) on feta that includes this change and it will be included in the next major release.
- Nym Bridge Configuration
- Generate keys
- Write configuration file
- Create the associated client parameter file
- Add UFW exception(s)
If running alongside a nym-node
- Add the field to Nym-Node configuration for the path to the client bridge parameter file
$HOME/.nym/nym-nodes/default-nym-node/
├── config
│ ├── (+) bridges.toml
│ ├── (+) client_bridge_params.json
│ └── (Δ) config.toml
└── data
├── aes128ctr_auth_ack
├── aes128ctr_ipr_ack
├── …
├── (+) quic_ed25519_identity.pem
├── (+) tls_ed25519_identity.pem
├── (+) ssh_ed25519_identity.pem
├── …
Generating Keys - The current transports (quic_plain, tls_plain, and ssh_plain) all require an
ED25519 key to secure the bridge transport connection. The key needs to be either base64 encoded in
the identity_key field in the configuration OR written in pkcs8 PEM format with the path provided
in the private_ed25519_identity_key_file field of the configuration. Each transport should use its
own, independently generated key -- bridge-cfg --gen does this for you (see Configure
above); the manual steps below are for anyone who wants to generate the key material by hand instead.
sudo apt-get install openssl
# Generate an ed25519 private key -- repeat per transport, using a distinct file name for each
# (e.g. quic_ed25519_identity.pem, tls_ed25519_identity.pem, ssh_ed25519_identity.pem) so that
# each transport gets its own key rather than sharing one.
openssl genpkey -algorithm Ed25519 -out private_key.pem
mv private_key.pem /home/nym/.nym/nym-nodes/default-nym-node/data/quic_ed25519_identity.pem
# Derive and format the associated ed25519 public key Base64 encoded (used in the id_pubkey field in the client parameters)
openssl pkey -in private_key.pem -pubout | grep -v "\---" | base64 --decode | tail -c 32 | base64For ssh_plain, a second, separate key must also be generated for client_auth_key (the key the
server uses to authenticate the client during the SSH handshake) -- follow the same steps with
another output filename.
The configuration for the nym-bridge runner includes the server side parameters for the running bridge listener(s). When launching the bridge runner the only argument needed is the path to this configuration file.
All of the transports are independent, so for example you could leave the tls_plain transport out of the configuration file - or given that none of the ports collide, you could enable multiple quic_plain listeners if there were a reason to do so.
This file needs saved to be provided to the nym-bridge binary (e.g.
$HOME/.nym/nym-nodes/default-nym-node/config/bridges.toml).
The latest bridge config template for the configuration can be found at the repository root in
bridges.template.toml.
Example Bridge Configuration template
# Nym Bridge Gateway Runner Configuration
#
# [version 0] - this is an initial implementation and the configuration handling will likely change
# going forward. This version is meant to be tightly coupled with a running `nym-node`.
# Path to file containing client parameters associated with the transports defined in this file
client_params_path = "/home/nym/.nym/nym-nodes/default-nym-node/config/client_bridge_params.json"
# Set of public IPs that address the listening host (usually and Ipv4 and IPv6 pair)
public_ips = ["192.168.0.1", "fe80::1"]
[forward]
# Target address where client traffic will be forwarded.
#
# If running in parallel with `nym-node` this should match with your public IP and announced wireguard port.
address = "[::1]:51822"
[[transports]]
transport_type = "quic_plain"
[transports.args]
# Enable stateless retries
stateless_retry = false
# Address to listen on
listen = "[::]:4443"
# Client address to block for sending, be default this is set by the OS on connection handling.
# block = "[2a01::1234]:5000"
# Maximum number of concurrent connections to allow
# connection_limit = 0
# Path to file containing PKCS8 PEM encoded ed25519 identity private key, for use in ED25519 based self signed certs
private_ed25519_identity_key_file = '/home/nym/.nym/nym-nodes/default-nym-node/data/quic_ed25519_identity.pem'
# Base64 encoded Identity Key string. This is used to secure connections using ED25519 self signed
# certificates. Used only if `private_ed25519_identity_key_file` is not provided.
# identity_key = "<base64 encoded identity private key>"
[[transports]]
transport_type = "tls_plain"
[transports.args]
# Address to listen on
listen = "[::]:4443"
# Maximum number of concurrent connections to allow
# connection_limit = 0
# Path to file containing PKCS8 PEM encoded ed25519 identity private key, for use in ED25519 based self signed certs
private_ed25519_identity_key_file = '/home/nym/.nym/nym-nodes/default-nym-node/data/tls_ed25519_identity.pem'
# Base64 encoded Identity Key string. This is used to secure connections using ED25519 self signed
# certificates. Used only if `private_ed25519_identity_key_file` is not provided.
# identity_key = "<base64 encoded identity private key>"
[[transports]]
transport_type = "ssh_plain"
[transports.args]
# Address to listen on
listen = "[::]:4422"
# Path to file containing PKCS8 PEM encoded ed25519 identity private key, used as the SSH host key
private_ed25519_identity_key_file = '/home/nym/.nym/nym-nodes/default-nym-node/data/ssh_ed25519_identity.pem'
# Base64 encoded Identity Key string. Used only if `private_ed25519_identity_key_file` is not provided.
# identity_key = "<base64 encoded ed25519 identity private key>"
# Base64 encoded Identity Key string. The server derives the associated public key from it and
# only accepts `publickey` authentication proving ownership of that exact keypair. This is a
# second, separate key from the host identity above -- generate it independently.
client_auth_key = "<base64 encoded ed25519 identity private key>"Fields requiring manual review:
-
public_ips- the globally routable addresses of the server.public_ips = ['1.1.1.1', 'fe80::1']
-
forward.address- The adress to which traffic will be sent after unwrapping the transport layer. This should be set to a PUBLIC IP of the nym node with the listening wireguard port.address = "1.1.1.1:51822"
-
transports.args.identity_keyORtransports.args.private_ed25519_identity_key_file- Either a base64 encoded Ed25519 private key or the path the a PKCS8 PEM encoded ED25519 private key file. This is the key used to secure the transport connection. Each transport should get its own, independently generated key -- do not point multiple transports at the same key file. If a key was generated using openssl as described above, this is the place for the path to the private key.private_ed25519_identity_key_file = /home/nym/.nym/nym-nodes/default-nym-node/data/quic_ed25519_identity.pem
-
transports.args.client_auth_key(ssh_plainonly) - A second, separate base64 encoded Ed25519 private key (not the host identity key above) that the server uses to authenticate connecting clients via SSHpublickeyauth. This same key must also be given to the client (asclient_auth_keyin the client parameters file, see below).
Given the key material, IPs, ports, and any other parameters defined in the bridge configuration we need to create a file that has all of the parameters that clients need to utilize the protocol.
Once created this file needs saved (e.g.
$HOME/.nym/nym-nodes/default-nym-node/config/client_bridge_params.json). The path in the
nym-bridge configuration needs to point to this file.
For all three transports the id_pubkey field is a base64 encoded ed25519 verifying (public) key,
derived from that transport's own identity key. For ssh_plain, client_auth_key must also be
included -- it's the private key half of the pre-shared identity the server authenticates the
client against (see the client_auth_key note in Bridge Configuration
above), and username must match the server's configured expected_username (ubuntu by default).
Example Client Parameters File
{
"version": "0",
"transports": [
{
"transport_type": "quic_plain",
"args": {
"addresses": ["[2a01:7e00::f03c:95ff:fef8:77f]:4443", "178.79.168.250:4443"],
"id_pubkey": "gyKl6DN9hgdPGhEzdf9gY4Ha2GzrOwSzLCguxeTVTJU=",
"host": "netdna.bootstrapcdn.com"
}
},
{
"transport_type": "ssh_plain",
"args": {
"addresses": ["[2a01:7e00::f03c:95ff:fef8:77f]:4422", "178.79.168.250:4422"],
"id_pubkey": "z2RmwvxjJH1WdKr08bYAoUuMxrTeqXWSPXVAT9IPS7g=",
"username": "ubuntu",
"client_auth_key": "fditK5JfNM/88mLWd3ccbLasSrHA5dw1wj+/+1bfGWk="
}
}
]
}Add the path to the file containing the client bridge parameters to the nym-node configuration
(usually in $HOME/.nym/nym-nodes/default-nym-node/config/config.toml)
# ...
[gateway_tasks.storage_paths]
# Path to sqlite database containing all persistent data: messages for offline clients,
# derived shared keys, available client bandwidths and wireguard peers.
clients_storage = '/home/nym/.nym/nym-nodes/default-nym-node/data/clients.sqlite'
# Path to sqlite database containing all persistent stats data.
stats_storage = '/home/nym/.nym/nym-nodes/default-nym-node/data/stats.sqlite'
# Path to file containing cosmos account mnemonic used for zk-nym redemption.
cosmos_mnemonic = '/home/nym/.nym/nym-nodes/default-nym-node/data/cosmos_mnemonic'
+
+ # Path to file containing client params for nym bridges
+ bridge_client_params = '/home/nym/.nym/nym-nodes/default-nym-node/config/client_bridge_params.json'
##### service providers nym-node config options #####
[service_providers]
# ...