# Nym Documentation

@version: 1.20.4
@generated: 2026-05-11
@pages: 148
@source: https://github.com/nymtech/nym/tree/develop/documentation/docs

---
title: Nym Network Architecture: How the Mixnet Works
description: Deep dive into Nym network architecture, cryptographic systems, and how the mixnet provides network-level privacy against end-to-end attackers.
url: https://nym.com/docs/network
---

# The Nym Network

The Nym Network is decentralized privacy infrastructure that protects against **network-level** surveillance. Unlike tools that focus on encrypting message content, Nym protects the metadata surrounding communication: who talks to whom, when, how often, and how much. This metadata is sufficient for observers to map relationships and build behavioural profiles even without access to any message content. See [The Privacy Problem](/network/overview/privacy-problem) for a fuller treatment.

Nym offers two operating modes with different privacy/performance trade-offs, both available through [NymVPN](https://nymvpn.com). Developers can also integrate Mixnet mode directly via the [Nym SDKs](/developers). See [Choosing a Mode](/network/overview/choosing-a-mode) for guidance on which fits a given threat model.

### NymVPN

[NymVPN](https://nymvpn.com) is a subscription-based application that provides access to both modes:
- **dVPN mode** routes traffic through 2 hops using WireGuard with enhanced layer encryption. Fast enough for browsing and streaming, with strong privacy against typical adversaries.
- **Mixnet mode** routes traffic through 5 hops with packet mixing, timing delays, and cover traffic. Every packet is the same size, each hop only sees the next destination, and a constant stream of dummy packets hides when real communication is occurring. Designed for privacy against adversaries capable of observing the entire network.

Both modes use the same underlying infrastructure.

### Developer SDKs

The [Nym SDKs](/developers) allow developers to embed mixnet functionality directly into applications, with the same privacy guarantees as NymVPN's Mixnet mode. SDK usage is currently free for development and testing. The SDKs do **not** provide access to dVPN mode.

## Paying for privacy without losing it

A fundamental weakness of traditional VPNs is that payment records can deanonymize users, since most providers link sessions to account IDs. Nym addresses this with **zk-nyms**: zero-knowledge anonymous credentials that prove payment without revealing any other information. Each credential covers a small chunk of bandwidth and is unlinkable to any other.

When you pay for NymVPN, your payment is converted into a credential that can be split and re-randomized. Each Gateway connection uses a fresh, unlinkable proof; the Gateway verifies that you have paid without learning who you are. Your subscription cannot be linked to your network activity, even by infrastructure operators.

## Further reading

- **Network architecture:** [Overview](/network/overview) · [dVPN Mode](/network/dvpn-mode) · [Mixnet Mode](/network/mixnet-mode) · [Cryptography](/network/cryptography) · [Infrastructure](/network/infrastructure) · [Reference](/network/reference)
- **Application development:** [Developer documentation](/developers)
- **Node operation:** [Operator documentation](/operators/introduction)

---
title: Nym Network Architecture: How the Mixnet Works
description: Deep dive into Nym network architecture, cryptographic systems, and how the mixnet provides network-level privacy against end-to-end attackers.
url: https://nym.com/docs/network
---

# The Nym Network

The Nym Network is decentralized privacy infrastructure that protects against **network-level** surveillance. Unlike tools that focus on encrypting message content, Nym protects the metadata surrounding communication: who talks to whom, when, how often, and how much. This metadata is sufficient for observers to map relationships and build behavioural profiles even without access to any message content. See [The Privacy Problem](/network/overview/privacy-problem) for a fuller treatment.

Nym offers two operating modes with different privacy/performance trade-offs, both available through [NymVPN](https://nymvpn.com). Developers can also integrate Mixnet mode directly via the [Nym SDKs](/developers). See [Choosing a Mode](/network/overview/choosing-a-mode) for guidance on which fits a given threat model.

### NymVPN

[NymVPN](https://nymvpn.com) is a subscription-based application that provides access to both modes:
- **dVPN mode** routes traffic through 2 hops using WireGuard with enhanced layer encryption. Fast enough for browsing and streaming, with strong privacy against typical adversaries.
- **Mixnet mode** routes traffic through 5 hops with packet mixing, timing delays, and cover traffic. Every packet is the same size, each hop only sees the next destination, and a constant stream of dummy packets hides when real communication is occurring. Designed for privacy against adversaries capable of observing the entire network.

Both modes use the same underlying infrastructure.

### Developer SDKs

The [Nym SDKs](/developers) allow developers to embed mixnet functionality directly into applications, with the same privacy guarantees as NymVPN's Mixnet mode. SDK usage is currently free for development and testing. The SDKs do **not** provide access to dVPN mode.

## Paying for privacy without losing it

A fundamental weakness of traditional VPNs is that payment records can deanonymize users, since most providers link sessions to account IDs. Nym addresses this with **zk-nyms**: zero-knowledge anonymous credentials that prove payment without revealing any other information. Each credential covers a small chunk of bandwidth and is unlinkable to any other.

When you pay for NymVPN, your payment is converted into a credential that can be split and re-randomized. Each Gateway connection uses a fresh, unlinkable proof; the Gateway verifies that you have paid without learning who you are. Your subscription cannot be linked to your network activity, even by infrastructure operators.

## Further reading

- **Network architecture:** [Overview](/network/overview) · [dVPN Mode](/network/dvpn-mode) · [Mixnet Mode](/network/mixnet-mode) · [Cryptography](/network/cryptography) · [Infrastructure](/network/infrastructure) · [Reference](/network/reference)
- **Application development:** [Developer documentation](/developers)
- **Node operation:** [Operator documentation](/operators/introduction)

---
title: Nym Network Overview
description: Introduction to the Nym Network, a privacy infrastructure that protects metadata including who communicates with whom, when, and how often.
url: https://nym.com/docs/network/overview
---

# Overview

The Nym Network is a privacy infrastructure that protects metadata: not just message content, but who is talking to whom, when, and how often. This section explains what the network does, why it exists, and how it compares to other approaches.

## In this section

- [The Privacy Problem](/network/overview/privacy-problem): what metadata is, why it matters, and what adversary models Nym is designed against
- [Choosing a Mode](/network/overview/choosing-a-mode): how dVPN and Mixnet mode differ, and guidance on which fits your use case
- [Nym vs Other Systems](/network/overview/comparisons): how Nym compares to VPNs, Tor, I2P, and E2EE

## Network Components

All traffic-routing infrastructure runs on [Nym Nodes](/network/infrastructure/nym-nodes), a single binary that operators configure to serve as an Entry Gateway, Mix Node, or Exit Gateway depending on their setup. Network coordination, token bonding, and the distributed credential system all live on the [Nyx blockchain](/network/infrastructure/nyx), a Cosmos SDK chain whose on-chain topology registry eliminates the need for a centralised directory server.

---
title: The Privacy Problem: Why Metadata Matters
description: Why metadata exposure is a critical privacy threat, how adversaries exploit traffic patterns, and why traditional solutions like VPNs, Tor, and E2EE fall short.
url: https://nym.com/docs/network/overview/privacy-problem
---

# The Privacy Problem

## Metadata

When you communicate over the internet, two types of information are in play:
- The **content** is the actual message, file, or data being sent.
- The **metadata** is everything else: who is talking to whom, when, from where, and how often. Some metadata is visible in every packet (source/destination IPs, timestamps, sizes), whereas other metadata only emerges from patterns over time: interaction frequency, session durations, and behavioural fingerprints that can identify users across sessions. See [Maximum Transmission Units](https://en.wikipedia.org/wiki/Maximum_transmission_unit#MTUs_for_common_media) for one example of what packet sizes reveal.

TLS and end-to-end encryption protect content, which is often the [focus of media attention](https://wire.com/en/blog/whatsapp-end-to-end-encryption-risks). However, most solutions don't protect metadata at all, and some falsely claim to.

Metadata alone is enough to reconstruct who you talk to, when, and from where. Intelligence agencies know this; as former NSA Director Michael Hayden put it, ["We kill people based on metadata."](https://committees.parliament.uk/writtenevidence/36962/html/)

## The adversary models

**Mixnet mode** is designed to protect against **Global Passive Adversaries**: entities that can observe traffic across the entire network at once, such as nation-state level agencies, large corporations with broad network infrastructure, ISPs, or any combination sharing data.

The assumption is worst-case: the adversary monitors all entry and exit points, correlates timing, applies machine learning to traffic patterns, and runs long-term statistical analysis. When Tor launched in 2002, this was considered unrealistic - machine learning and the increase in computation power have made this unfortunately more of a potential reality today.

**dVPN mode** does not defend against timing analysis, but it splits trust across two independent operators and removes payment linkability, which already addresses the biggest weaknesses of traditional VPNs.

For a comparison with VPNs, Tor, and I2P, see [Nym vs Other Systems](/network/overview/comparisons). For help picking a mode, see [Choosing a Mode](/network/overview/choosing-a-mode).

---
title: Choosing Between dVPN and Mixnet Mode
description: When to use NymVPN's dVPN mode for low-latency browsing versus Mixnet mode for metadata protection against traffic analysis.
url: https://nym.com/docs/network/overview/choosing-a-mode
---

# Choosing a Mode

Both modes run on the same Nym infrastructure but defend against different threat models. dVPN mode hides your IP and splits trust across two operators, and Mixnet mode additionally protects traffic patterns against adversaries capable of observing the entire network.

**dVPN mode** routes through 2 hops (Entry Gateway + Exit Gateway) connected via [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/), a WireGuard fork with traffic obfuscation to evade protocol-level detection. Latency is low, but there is no protection against timing analysis.

**Mixnet mode** routes through 5 hops (Entry Gateway, three Mix Node layers, Exit Gateway). Each Mix Node adds a random delay and mixes packets with those of other users. Combined with continuous cover traffic, this makes timing correlation impractical even for an adversary watching the entire network.

## Quick comparison

| | dVPN Mode | Mixnet Mode |
|---|---|---|
| **Hops** | 2 (Entry + Exit Gateway) | 5 (Entry + 3 Mix Nodes + Exit) |
| **Timing protection** | No | Yes (random delays per hop) |
| **Cover traffic** | No | Yes (constant dummy packets) |
| **Protects against** | ISPs, websites, advertisers, passive observers | Global passive adversaries, timing correlation, traffic analysis |
| **Access** | [NymVPN](https://nymvpn.com) | NymVPN and [Nym SDKs](/developers) |

## Use dVPN mode when

- Latency matters: browsing, streaming, downloads, video calls
- Your concern is ISPs, advertisers, and websites tracking you, not nation-state surveillance
- You want decentralized trust and payment privacy without the overhead of mixing

## Use Mixnet mode when

- Metadata exposure is dangerous: journalism, activism, whistleblowing, legal work
- Your adversary might be watching traffic across multiple network points
- Added latency is an acceptable trade for unlinkability and unobservability

## For developers

The [Nym SDKs](/developers) only expose **Mixnet mode**. dVPN mode is specific to the NymVPN application.

There are two integration models:

**Proxy** (traffic exits to the internet, analogous to Tor's exit relay model):
```
Your App --> Entry --> Mix Nodes --> Exit --> Internet
```

**End-to-end** (Sphinx-encrypted the entire way, traffic stays within the Mixnet):
```
Your App --> Entry --> Mix Nodes --> Exit --> Nym Client
```

See the [integration overview](/developers/integrations) for guidance on choosing between them.

---
title: Nym vs VPNs, Tor, I2P, and E2EE
description: How the Nym Network compares to traditional VPNs, Tor, I2P, and end-to-end encryption in terms of privacy guarantees, metadata protection, and threat models.
url: https://nym.com/docs/network/overview/comparisons
---

# Nym vs Other Systems

There are several existing approaches to network privacy, each with different assumptions about who the adversary is and what they can do.

## Nym vs VPNs

A traditional VPN creates an encrypted tunnel between your device and a VPN server, hiding your IP from destination websites and encrypting traffic from local observers like your ISP. The fundamental limitation is that the VPN provider itself sees all your traffic (every site you visit, when you visit it, how long you stay) and can log this voluntarily or be compelled to by legal process, with your payment information linking your account directly to your activity.

Nym's dVPN mode splits this trust across two independent operators so that the Entry Gateway knows your IP but not your destination, the Exit Gateway knows your destination but not your IP, and neither can build a complete picture. Payment is handled through [zk-nyms](/network/cryptography/zk-nym), making subscriptions unlinkable to activity.

Nym's mixnet mode goes further by adding timing obfuscation and cover traffic, which no traditional VPN offers; see [Mixnet Mode](/network/mixnet-mode) for details.

## Nym vs Tor

[Tor](https://www.torproject.org/) is the best-known anonymous overlay network, routing traffic through three relays using Onion encryption so that no single relay sees both source and destination. It was designed in an era when global passive adversaries were considered unrealistic, and its [architecture](https://2019.www.torproject.org/about/overview.html.en) reflects that: packets flow through without delays and there is no cover traffic, which means an adversary watching both ends of a circuit can try and correlate timing to deanonymise users.

Nym's mixnet addresses this by adding random delays at each Mix Node to break timing correlations, cover traffic so observers can't tell when real communication is occurring, per-packet routing rather than Tor's per-session circuits (so there's no long-lived path to observe), and a blockchain-based topology instead of Tor's centralised directory authority.

The tradeoff is latency: Tor is faster because it doesn't add mixing delays, so it may be a better fit for general browsing where timing protection isn't needed. Nym's mixnet is designed for threat models where the adversary can perform traffic analysis.

## Nym vs I2P

[I2P](https://geti2p.net/) replaces Tor's centralised directory authority with a [distributed hash table](https://geti2p.net/en/docs/how/network-database), which improves decentralisation but introduces its own attack surface: DHT-based routing is vulnerable to eclipse attacks and Sybil attacks on the routing table. Like Tor, I2P provides no timing protection, so packets flow without delays or cover traffic.

Nym uses a blockchain-based topology registry rather than a DHT, which avoids the known attack vectors around DHT-based routing (e.g. eclipse attacks, Sybil attacks on the routing table). The mixing and cover traffic on top of that address the timing analysis gap that I2P shares with Tor.

## Nym vs end-to-end encryption

End-to-end encryption systems like [Signal](https://signal.org/docs/) encrypt messages on your device so that only the recipient can decrypt them, and the server never sees the content. But E2EE does nothing for metadata: the server still sees who you communicate with, when, how often, and how much, which on its own is enough to map relationships and infer sensitive activity.

Nym and E2EE are complementary: E2EE protects message content, Nym protects the metadata around it (who, when, how much). Using Signal over the Nym mixnet, for instance, would protect both message content and the communication metadata around it.

For a practical breakdown of when to use dVPN vs Mixnet mode, see [Choosing a Mode](/network/overview/choosing-a-mode).

## Further reading

- [What is WireGuard?](https://nym.com/blog/what-is-wireguard-vpn)
- [VPN Tunnels Explained](https://nym.com/blog/vpn-tunnels)
- [Tor Project: How Tor Works](https://2019.www.torproject.org/about/overview.html.en)
- [Tor Protocol Specification](https://spec.torproject.org/tor-spec/)
- [I2P: How It Works](https://geti2p.net/en/docs/how/tech-intro)

---
title: dVPN Mode
description: How Nym's decentralized VPN mode routes traffic through two independent gateways, splitting trust so no single operator sees both your identity and destination.
url: https://nym.com/docs/network/dvpn-mode
---

# dVPN Mode

dVPN mode is a 2-hop decentralized VPN available through [NymVPN](https://nymvpn.com). Traffic is routed through two independent gateways rather than a single VPN provider's server, so no single operator ever sees both who you are and what you're doing.

## How it works

```
User --> Entry Gateway --> Exit Gateway --> Internet
```

Your device wraps each packet in two layers of encryption, one per gateway. The Entry Gateway strips the outer layer and forwards a packet it cannot read; the Exit Gateway strips the inner layer and sends the plaintext request to the destination. Responses follow the reverse path. The Entry Gateway therefore knows your IP address but not the destination, while the Exit Gateway knows the destination but not the sender.

## Privacy guarantees

dVPN mode hides your IP from destination servers and splits trust across two operators. It does not add timing obfuscation or cover traffic. Packets are forwarded immediately, so an adversary watching both gateways could still correlate timing to link your requests. If you need protection against traffic analysis, see [Mixnet Mode](/network/mixnet-mode).

## Performance

Added latency is comparable to traditional VPNs, and WireGuard keeps cryptographic overhead low, so browsing, streaming, and downloads are not noticeably affected.

## Technical details

- [dVPN Protocol](/network/dvpn-mode/protocol): protocol stack and encryption details
- [Censorship Resistance](/network/dvpn-mode/censorship-resistance): AmneziaWG and DPI evasion

## Further reading

- [Introducing AmneziaWG for NymVPN](https://nym.com/blog/introducing-amneziawg-for-nymvpn): censorship resistance
- [What Is a Double VPN?](https://nym.com/blog/double-vpn): multi-hop privacy explained
- [Building a Decentralized WireGuard VPN](https://nym.com/blog/building-decentralized-wireguard-vpn): architecture decisions
- [What is NymVPN?](https://nym.com/blog/what-is-nymvpn): general overview

---
title: dVPN Protocol Stack and Encryption
description: Technical details of Nym dVPN mode's protocol layers: nested WireGuard tunnels, split-knowledge architecture, and packet format tradeoffs.
url: https://nym.com/docs/network/dvpn-mode/protocol
---

# dVPN Protocol

Cryptographic details on this page will be updated for the Lewes Protocol release. For the current algorithm overview, see the [Nym Trust Center: Cryptography](https://nym.com/trust-center/cryptography).

This page covers the technical details of dVPN mode's protocol stack and encryption.

## Protocol layers

dVPN mode uses two nested WireGuard tunnels. The client establishes an inner tunnel to the Exit Gateway and an outer tunnel to the Entry Gateway, where the inner tunnel is created first and the outer tunnel encapsulates it.

```
+-----------------------------------------+
|           Application Data              |
+-----------------------------------------+
|  Inner WireGuard tunnel (Client → Exit) |
+-----------------------------------------+
|  Outer WireGuard tunnel (Client → Entry)|
+-----------------------------------------+
|              UDP/IP                      |
+-----------------------------------------+
```

The Entry Gateway decrypts only the outer tunnel and forwards the inner tunnel, still fully encrypted, to the Exit Gateway. The Exit Gateway decrypts the inner tunnel and forwards traffic to its destination. Because the Entry Gateway never holds keys for the inner tunnel, it is cryptographically excluded from the payload.

## Encryption

Both tunnels use standard WireGuard cryptography: Curve25519 for key exchange, ChaCha20-Poly1305 for authenticated encryption, and BLAKE2s for hashing. Each tunnel derives independent session keys, providing 256-bit security with modern, well-audited primitives.

## Packet format

dVPN mode uses standard WireGuard packet framing: packets are not padded to a uniform size. Packet sizes may vary and could in principle leak information about content types (video streams have different size patterns than text messages). This is a deliberate tradeoff: uniform padding would add overhead and reduce throughput, which conflicts with dVPN mode's goal of low-latency, high-throughput connectivity. For uniform packet sizes, use [mixnet mode](/network/mixnet-mode), which wraps all traffic in fixed-size Sphinx packets.

## Connection lifecycle

When connecting, the client first selects Entry and Exit Gateways based on latency, location preference, or random selection. It then presents a zk-nym credential to the Entry Gateway for anonymous authentication. The credential proves payment without revealing identity; it is re-randomized for each connection and cannot be linked to previous usage.

Once authenticated, the client establishes both WireGuard tunnels: first the inner tunnel keyed with the Exit Gateway, then the outer tunnel keyed with the Entry Gateway. Traffic flows through both hops until the session ends.

## Security properties

The protocol provides forward secrecy: new session keys are derived for each connection, so compromising long-term keys does not expose past sessions. WireGuard's key rotation provides additional forward secrecy within sessions.

The nested-tunnel architecture enforces split knowledge. The Entry Gateway knows your IP but cannot decrypt the inner tunnel, so it sees neither your destinations nor your payload. The Exit Gateway decrypts the inner tunnel and sees your destinations but never learns your IP. Neither gateway can correlate the two.

Replay protection comes from WireGuard's counter-based mechanism and from zk-nym serial numbers that prevent credential reuse.

## Relationship to mixnet mode

dVPN mode shares infrastructure with mixnet mode. Both use the same Entry and Exit Gateways and the same credential system. The difference is in how traffic is handled: mixnet mode routes through three additional Mix Node layers with delays and cover traffic using fixed-size [Sphinx packets](/network/cryptography/sphinx), while dVPN mode routes directly between gateways using WireGuard. The two modes are distinguishable at the protocol level due to their different packet formats and traffic patterns.

In anonymous (5-hop) mode, NymVPN routes traffic through the full mixnet to the Exit Gateway's [IP Packet Router](/network/infrastructure/exit-services#ip-packet-router), which tunnels raw IP packets to the internet. See [Exit Gateway Services](/network/infrastructure/exit-services) for how the IPR and Network Requester work.

This shared infrastructure means improvements to Gateways and credentials benefit both modes.

---
title: Censorship Resistance in dVPN Mode
description: How AmneziaWG obfuscation, QUIC transport mode, and Stealth API Connect help Nym dVPN users evade deep packet inspection and protocol blocking.
url: https://nym.com/docs/network/dvpn-mode/censorship-resistance
---

# Censorship Resistance

dVPN mode incorporates several techniques to help users connect in restrictive network environments where VPN protocols are actively detected and blocked.

## The problem: protocol fingerprinting

Deep Packet Inspection (DPI) systems deployed by ISPs and governments can identify VPN protocols by their handshake patterns, packet sizes, and timing characteristics. Standard WireGuard, for instance, has a recognisable handshake initiation pattern that DPI rules can match against. Once identified, connections can be throttled or blocked entirely.

This is not a theoretical concern: countries including China, Russia, Iran, and others actively deploy DPI to restrict VPN usage.

## AmneziaWG

dVPN mode uses [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/), a fork of WireGuard that adds obfuscation techniques to make the protocol harder to fingerprint.

AmneziaWG modifies the WireGuard handshake by introducing decoy packets before the handshake initiation. These decoy packets disrupt DPI rules that rely on matching the standard WireGuard handshake sequence. The actual WireGuard protocol behaviour is preserved; the modifications sit around the handshake rather than replacing it, so all of WireGuard's security properties (Curve25519 key exchange, ChaCha20-Poly1305 encryption, forward secrecy) remain intact.

## Limitations

AmneziaWG raises the bar for censors relying on simple protocol fingerprinting, but it doesn't help against deeper analysis: statistical fingerprinting of packet timing and sizes, IP-based blocking of known Gateway addresses, or active probing where the censor sends packets to suspected VPN servers to confirm their identity.

## QUIC transport mode

QUIC transport mode wraps the WireGuard/AmneziaWG connection inside a [QUIC](https://datatracker.ietf.org/doc/html/rfc9000) layer, so the traffic looks like standard HTTPS/HTTP3 to DPI systems rather than a VPN tunnel. Since QUIC is now used by a significant portion of regular web traffic (over 30% of Cloudflare's traffic in 2023 was HTTP/3 over QUIC), blocking it outright would break large parts of the web for everyone, making it an unattractive target for censors.

QUIC transport applies to the Entry Gateway connection only (the first hop). Not all Gateways support it yet; enabling QUIC in the NymVPN app will filter the Gateway list to those that do. Because the QUIC wrapper adds overhead, it can reduce speeds slightly, so it's worth leaving disabled unless you're in a censored environment or having connectivity issues.

## Stealth API Connect

Even if a user can establish a VPN tunnel, censors can also block access to the API that the NymVPN app needs to discover Gateways and fetch network state in the first place. Stealth API Connect addresses this by routing the app's API requests through a mechanism that is harder to identify and block, so the app can bootstrap its connection to the Nym network even in environments where the Nym API endpoints are actively censored.

## Limitations

These techniques are layered: AmneziaWG obfuscates the handshake, QUIC disguises the tunnel as regular web traffic, and Stealth API Connect protects the initial API discovery. Together they cover several common censorship methods, but none of them are guarantees. Censorship resistance is an ongoing arms race, and new techniques will be documented here as they ship.

## Further reading

- [Introducing AmneziaWG for NymVPN](https://nym.com/blog/introducing-amneziawg-for-nymvpn)
- [AmneziaWG documentation](https://docs.amnezia.org/documentation/amnezia-wg/)
- [What is QUIC? Censorship-Resistant Internet Connections](https://nym.com/blog/what-is-quic)
- [What is QUIC transport mode in NymVPN?](https://support.nym.com/hc/en-us/articles/39648047741457-What-is-QUIC-transport-mode-in-NymVPN)
- [What is Stealth API Connect in NymVPN?](https://support.nym.com/hc/en-us/articles/39652289741329-What-is-Stealth-API-connect-in-NymVPN)
- [NymVPN's roadmap for censorship resistance](https://nym.com/blog/NymVPN-Roadmap-for-censorship-resistance-2025)

---
title: Mixnet Mode
description: How Nym's Mixnet mode works: 5-hop routing through Mix Nodes with random delays, packet reordering, and cover traffic for unlinkability and unobservability.
url: https://nym.com/docs/network/mixnet-mode
---

# Mixnet Mode

Mixnet mode routes traffic through 5 hops: an Entry Gateway, three layers of Mix Nodes, and an Exit Gateway. Each mixing layer adds random delays, reorders packets, and injects cover traffic. Available through [NymVPN](https://nymvpn.com) and the [Nym SDKs](/developers).

## How it works

```
User --> Entry --> Mix L1 --> Mix L2 --> Mix L3 --> Exit --> Internet
                    |           |           |
                  delay       delay       delay
```

Each Mix Node strips one layer of [Sphinx](/network/cryptography/sphinx) encryption to learn the next hop, holds the packet for a random delay, then forwards it. No node ever sees both the origin and the final destination. The client also continuously sends [cover traffic](/network/mixnet-mode/cover-traffic) - dummy packets cryptographically indistinguishable from real ones - so an observer sees a constant stream of identical packets regardless of whether any real communication is taking place.

## Privacy properties

- **Unlinkability**: the random delays and reordering at each Mix Node destroy the timing signal an observer would need to correlate incoming and outgoing packets, or to connect successive packets from the same user. See [Packet Mixing](/network/mixnet-mode/mixing).
- **Unobservability**: because cover traffic is constant, an observer cannot determine when a user is active or what fraction of the traffic is real. See [Cover Traffic](/network/mixnet-mode/cover-traffic).
- **Resistance to traffic analysis**: uniform Sphinx packet sizes prevent content-type fingerprinting, and per-packet routing eliminates the long-lived circuits that make other anonymity networks susceptible to end-to-end correlation. See [Traffic Flow](/network/mixnet-mode/traffic-flow).

## Performance

The three mixing layers add additional latency. This is acceptable for messaging, file transfers, and most API calls, but unsuitable for real-time applications like video calling. For those, [dVPN mode](/network/dvpn-mode) is more appropriate.

Updated latency measurements will be published after the Lewes Protocol release.

## Further reading

The following pages cover mixnet internals in detail:

- [Loopix Design](/network/mixnet-mode/loopix) explains the academic foundation of Nym's Mixnet design
- [Traffic Flow](/network/mixnet-mode/traffic-flow) shows the packet journey with diagrams
- [Cover Traffic](/network/mixnet-mode/cover-traffic) explains how dummy packets provide unobservability
- [Packet Mixing](/network/mixnet-mode/mixing) covers timing delays and their importance
- [Anonymous Replies](/network/mixnet-mode/anonymous-replies) describes SURBs for bidirectional communication

---
title: Loopix Design
description: The academic Loopix mixnet design behind Nym: stratified topology, continuous-time mixing with exponential delays, and cover traffic loops for unlinkability and unobservability.
url: https://nym.com/docs/network/mixnet-mode/loopix
---

# Loopix Design

The Nym mixnet is based on the [Loopix](https://arxiv.org/pdf/1703.00536) design, with modifications for decentralized operation and economic incentives.

## The insight

Traditional mixnets focus on hiding "who messages whom," but this alone is insufficient, as adversaries observing message volume and timing over time can still infer private information. If you always message the same friend at the same time, patterns emerge. If you go silent when traveling, that's information too.

Loopix was designed to provide both **unlinkability** (hiding who talks to whom) and **unobservability** (hiding when and how much communication occurs). The name comes from its use of "loop" cover traffic that circulates through the network.

## Stratified topology

The network uses a layered architecture. Traffic flows through Entry Gateways, three Mix Node layers, and Exit Gateways. Each node connects only to adjacent layers. Path selection is independent per-message, unlike Tor's per-session circuits.

This structure prevents observations about which paths are used together and limits the damage any single compromised node can cause.

## Continuous-time mixing

Unlike batch mixnets that collect messages and release them periodically, Loopix uses continuous-time mixing, where each message is delayed independently according to an exponential distribution and then forwarded as soon as its delay expires.

This approach offers optimal anonymity for a given mean latency. The exponential distribution has a key property: if two messages arrive at different times, they have equal probability of leaving in either order. An adversary watching input and output timing gains no information about which input became which output.

Continuous mixing also means lower latency overall since messages don't wait for batches to fill.

## Cover traffic loops

Connected clients and nodes continuously generate dummy packets that travel in loops through the network back to the sender. These packets are indistinguishable from real traffic: same size, same encryption, same timing distribution.

Loop traffic ensures minimum anonymity even when few users are active, hides when real communication starts and stops, and enables detection of active attacks (if loop packets fail to return, a network fault or active interference is likely).

## Nym's modifications

The Nym implementation extends Loopix in several ways: replacing the trusted directory server with the Nyx blockchain for decentralized topology management, incentivising node operation with NYM token rewards rather than relying on volunteers, and adding zk-nyms for privacy-preserving payment, which the original academic design did not address.

## Security guarantees

The combination of continuous-time mixing and cover traffic provides provable guarantees. The anonymity set (the set of users who could have sent a given message) grows unboundedly over time. Even messages with short delays have large anonymity sets because of the exponential distribution.

An adversary observing the entire network cannot determine who is communicating with whom, cannot tell when real communication is occurring, and gains no advantage from statistical analysis because the traffic patterns are designed to be indistinguishable from random.

For the full formal analysis, see the [Loopix paper](https://arxiv.org/pdf/1703.00536) and the [Nym Whitepaper](https://nym.com/nym-whitepaper.pdf).

---
title: Traffic Flow
url: https://nym.com/docs/network/mixnet-mode/traffic-flow
---

# Traffic Flow

This page walks through how packets travel through the mixnet, from sending client to destination.

This describes the 5-hop mixnet flow. For the 2-hop dVPN mode, see [dVPN Protocol](/network/dvpn-mode/protocol).

## Overview

The Nym mixnet uses source routing: the sender chooses the complete route before sending. This means the sender constructs a Sphinx packet with layered encryption, where each layer contains routing information for one hop.

## Client to Entry Gateway

On connection, the Nym client registers with a particular Entry Gateway. This Gateway becomes part of the client's Nym address and is where incoming messages are delivered.

The client continuously sends packets to the Entry Gateway over a WebSocket connection. This stream includes both real messages and cover traffic at a constant rate. When the application has data to send, the client encrypts it as Sphinx packets and slots them into the stream. When there is no data, cover packets flow instead.

```mermaid
sequenceDiagram
    box Local Machine
        participant App as Application
        participant Client as Nym Client
    end
    participant Gateway as Entry Gateway

    Gateway->>Client: Key Exchange

    loop Continuous Traffic
        Client->>Gateway: Cover packet
        Client->>Gateway: Cover packet
        App-->>Client: Data to send
        Client->>Client: Encrypt as Sphinx
        Client->>Gateway: Real packet
        Client->>Gateway: Cover packet
    end
```

## Through the Mix Nodes

The Entry Gateway forwards packets into the three Mix Node layers. At each hop, the node decrypts its layer of the Sphinx packet to learn the next destination, verifies the HMAC to ensure integrity, applies a random delay, and forwards to the next hop.

The delay is critical. Without it, timing would correlate inputs to outputs. With exponential random delays, packets are reordered and the timing relationship is destroyed.

```mermaid
---
config:
  theme: neo-dark
---
sequenceDiagram
    participant Entry as Entry Gateway
    participant M1 as Mix Layer 1
    participant M2 as Mix Layer 2
    participant M3 as Mix Layer 3
    participant Exit as Exit Gateway

    Entry->>M1: Sphinx Packet
    M1->>M1: Decrypt layer
    M1->>M1: Verify HMAC
    M1->>M1: Random delay
    M1->>M2: Sphinx Packet
    M2->>M2: Decrypt layer
    M2->>M2: Verify HMAC
    M2->>M2: Random delay
    M2->>M3: Sphinx Packet
    M3->>M3: Decrypt layer
    M3->>M3: Verify HMAC
    M3->>M3: Random delay
    M3->>Exit: Sphinx Packet
```

## Exit Gateway to Destination

The Exit Gateway handles the final hop. For traffic destined for external services, it decrypts the packet and forwards to the destination, then packages responses back into Sphinx packets for the return journey.

For traffic destined for another Nym client, the Exit Gateway delivers to that client's registered Gateway, which holds the message until the recipient comes online.

## The complete picture

Putting it together, a packet travels through five hops with encryption removed and delays applied at each Mix Node layer:

```mermaid
---
config:
  theme: neo-dark
---
sequenceDiagram
    box Sender
        participant App1 as Application
        participant C1 as Nym Client
    end

    box Mixnet
        participant Entry as Entry GW
        participant M1 as Mix L1
        participant M2 as Mix L2
        participant M3 as Mix L3
        participant Exit as Exit GW
    end

    box Receiver
        participant C2 as Nym Client
        participant App2 as Application
    end

    App1->>C1: Send data
    C1->>C1: Create Sphinx packet
    C1->>Entry: Encrypted packet
    Entry->>M1: Forward
    M1->>M1: Decrypt, delay
    M1->>M2: Forward
    M2->>M2: Decrypt, delay
    M2->>M3: Forward
    M3->>M3: Decrypt, delay
    M3->>Exit: Forward
    Exit->>C2: Deliver
    C2->>C2: Decrypt final layer
    C2->>App2: Received data
```

## External services

When sending to an external service rather than another Nym client, the Exit Gateway acts as a proxy. It extracts the destination from the decrypted packet, makes the request on your behalf, and routes responses back through the network. The destination service sees the Exit Gateway's IP, not yours.

## Peer-to-peer

For applications where all parties run Nym clients, traffic stays entirely within the mixnet. Both sides enjoy full privacy protection, and [SURBs](/network/mixnet-mode/anonymous-replies) enable anonymous bidirectional communication without either party learning the other's address.

---
title: Cover Traffic
description: How constant dummy packet streams hide real communication patterns in the Nym mixnet, achieving unobservability even against global network observers.
url: https://nym.com/docs/network/mixnet-mode/cover-traffic
---

# Cover Traffic

Cover traffic consists of dummy packets that hide when real communication is occurring, providing unobservability: an adversary cannot determine whether a user is actively communicating.

## The problem

Even with perfect encryption and mixing, traffic analysis can reveal information. An adversary can see how much data you're sending, when you're sending it, and detect patterns over time. Regular silence followed by bursts of activity reveals your schedule, and consistent traffic volumes to certain destinations reveal ongoing relationships.

## The solution

Cover traffic maintains a constant rate of packet transmission. When you have real data to send, it replaces a cover packet in the stream. When you have nothing to send, cover packets flow anyway. To an observer, the traffic looks identical either way.

```
Without cover traffic:
              |         |||        |
Time ---------+---------+++---------+------>
            Idle    Activity    Idle
                    (visible)

With cover traffic:
    ||||||||||||||||||||||||||||||||||||||
Time -------------------------------------->
         Constant rate (activity hidden)
```

The cover packets are real Sphinx packets with valid encryption, just with empty payloads. They travel through the network exactly like real packets, get mixed at each hop, and are discarded at their destination. No node along the way can tell whether a packet contains real data or is cover traffic.

## Loop traffic

Cover packets follow complete routes through the network back to the sender. These "loops" serve multiple purposes: they provide traffic for mixing with others' cover traffic and they can detect active attacks. If loop packets stop returning, a network fault or active interference is likely.

Mix nodes also generate their own cover traffic, ensuring minimum traffic levels even when few users are active. This provides baseline anonymity guarantees regardless of network load.

## How it's generated

Traffic follows a Poisson process with a configurable rate parameter. Inter-packet times are exponentially distributed: random, but with a known average rate. This distribution provides maximum entropy (uncertainty) for a given mean rate, which translates to optimal privacy properties.

## Tradeoffs

More cover traffic provides better unobservability but uses more bandwidth and, when zk-nyms are enabled, more credential value. Less cover traffic reduces costs but may allow some inference about activity patterns.

The default parameters balance privacy and resource usage. Applications with heightened privacy requirements can increase the cover traffic rate; applications where unobservability is less critical can reduce it.

## What cover traffic defeats

Cover traffic prevents volume analysis (how much you communicate), timing analysis (when you communicate), and behavioral profiling (your communication patterns over time). Combined with packet mixing, it ensures that even an adversary watching the entire network cannot learn about your communication behavior with currently known methods.

---
title: Packet Mixing and Random Delays
description: How Mix Nodes use exponential random delays to reorder packets and break timing correlations, preventing traffic analysis by network observers.
url: https://nym.com/docs/network/mixnet-mode/mixing
---

# Packet Mixing

Packet mixing breaks timing correlations by adding random delays at each Mix Node. It's the core mechanism that prevents traffic analysis.

## The problem

Without mixing, an observer watching a node could correlate inputs and outputs. If packets leave on a FIFO (First In First Out) basis, even with encryption hiding contents, the timing relationship reveals which input became which output.

## The solution

Each Mix Node adds a random delay before forwarding. Packets don't flow through in order; they're held for variable times and released in a different sequence than they arrived. An observer sees packets going in and packets coming out, but cannot match them.

```
Input sequence:  A B C D E
                 | | | | |
                 v v v v v
              [   Mixing   ]
                 | | | | |
                 v v v v v
Output sequence: C A E B D
```

The delays follow an exponential distribution. This choice is mathematically optimal: if two packets arrive at times t₀ and t₁, they have equal probability of leaving in either order, regardless of when they arrived. The adversary gains no information from timing observations.

## Why exponential delays

The exponential distribution is memoryless: the probability of a packet leaving in the next moment does not depend on how long it has already waited, so an adversary cannot narrow down possibilities by noting how long packets have been in the node.

Any other delay distribution leaks information; fixed delays would let adversaries match arrivals to departures by timing, and uniform distributions would create windows where matches become more likely.

## Continuous vs batch mixing

Older mixnet designs collected packets into batches and shuffled them before release. This has problems: latency is unpredictable since you wait for batches to fill, bandwidth is inefficient due to bursty traffic, and the anonymity set is limited to the batch size.

Continuous-time mixing processes each packet independently. Latency is predictable (the mean delay is configurable), bandwidth is used efficiently, and the anonymity set is unbounded: it includes all packets that have ever passed through, weighted by time.

## The aggregate effect

With three Mix Node layers, each applying random delays, the overall effect is thorough reordering. Packets entering the mixnet in sequence exit in a completely different order. The timing relationship between sending and receiving is destroyed.

These delays account for the additional latency of mixnet mode relative to dVPN mode.

Updated latency measurements will be published after the Lewes Protocol release.

## Combined with cover traffic

Mixing and cover traffic are complementary. Cover traffic ensures there are always packets to mix, even during low activity, while mixing ensures that real and cover packets become interleaved and indistinguishable. Together they provide both unlinkability and unobservability.

---
title: Anonymous Replies with SURBs
description: How Single Use Reply Blocks (SURBs) enable anonymous bidirectional communication in the Nym mixnet without revealing the sender's address.
url: https://nym.com/docs/network/mixnet-mode/anonymous-replies
---

# Anonymous Replies

SURBs (Single Use Reply Blocks) enable anonymous bidirectional communication. A receiver can reply to a sender without learning the sender's identity or address.

## The problem

In a typical mixnet scenario, Alice sends a message to Bob and wants a reply, but if Bob sends directly to Alice's Nym address, he learns it. This defeats the purpose of anonymous communication; Bob now knows Alice's identity for future contact, and due to how Nym's [addressing scheme](/network/reference/addressing.md) works, this means that Bob knows which Gateway node Alice's client is using.

## How SURBs work

Alice creates SURBs (encrypted routing headers) and includes them with her message to Bob. Each SURB contains a complete route back to Alice, encrypted so that Bob cannot read it. Bob attaches his reply to a SURB and sends the resulting packet into the mixnet. It travels through the encoded route and arrives at Alice, but Bob never learns where it went.

A SURB contains the address of the first hop (Alice's Entry Gateway), encrypted routing headers for the path back to Alice, and a key to encrypt the reply payload. The routing headers are layered like a Sphinx packet; each hop can only see the next destination.

## Single use

Each SURB can only be used once. This prevents replay attacks and ensures forward secrecy. For conversations requiring multiple exchanges, Alice sends multiple SURBs with her initial message.

SURB validity is tied to key rotation. Node keys rotate on an odd/even schedule with a default validity of 24 epochs (roughly 25 hours at the current 1-hour epoch length). After that window, the routing keys a SURB was built with are no longer accepted. Clients automatically purge stale SURBs and request fresh ones. Reply keys also expire after 24 hours independently of rotation cycles.

## SURB replenishment

If Bob's reply is larger than the available SURBs can carry, he uses one SURB to request more. Alice receives the request, generates additional SURBs, and sends them to Bob. This adds round-trip latency but ensures conversations can continue regardless of reply size.

```mermaid
---
config:
  theme: neo-dark
---
sequenceDiagram
    participant Alice
    participant Mixnet
    participant Bob

    Alice->>Mixnet: Message + 5 SURBs
    Mixnet->>Bob: Message + 5 SURBs
    Bob->>Bob: Reply needs 10 SURBs
    Bob->>Mixnet: "Need more SURBs" (uses 1 SURB)
    Mixnet->>Alice: SURB request
    Alice->>Mixnet: 10 more SURBs
    Mixnet->>Bob: Additional SURBs
    Bob->>Mixnet: Reply (uses SURBs)
    Mixnet->>Alice: Reply received
```

## Sender tags

For sessions with multiple messages, Alice includes a randomly generated sender tag with her SURBs. This helps Bob organize SURBs from multiple conversations without revealing anything about Alice's identity; the tag is random and unlinkable to her address.

## Security considerations

There's a known attack where a malicious receiver hoards SURBs and sends them all back simultaneously, attempting to correlate traffic patterns at the sender's Gateway. This attack requires active participation (not just passive observation), and provides limited information even if successful. It's not a passive surveillance technique; the attacker must be specifically targeting you and willing to spend resources.

## Comparison to Tor onion addresses

Tor's onion addresses allow indefinite replies but require the recipient to run a hidden service. SURBs are single-use but require no service; they're generated on-demand per message. SURBs also benefit from the mixnet's timing protection, which onion addresses don't have.

---
title: Nym Network Cryptography
description: Overview of the cryptographic systems powering Nym: transport encryption, Sphinx packet format, per-hop encryption, and zk-nym anonymous credentials.
url: https://nym.com/docs/network/cryptography
---

# Cryptography

The Nym Network relies on several cryptographic systems working together. This section covers the algorithms, packet formats, and credential systems that provide privacy guarantees.

## What's covered

[Sphinx Packets](/network/cryptography/sphinx) explains the packet format that enables layered encryption and anonymous routing. Each Sphinx packet contains routing information encrypted in layers, where each hop can only decrypt its own layer.

[zk-nyms](/network/cryptography/zk-nym) covers the anonymous credential system that separates payment from usage. This is how you can pay for network access without that payment being linkable to your activity.

---
title: Sphinx Packet Format
description: How Sphinx packets provide layered encryption for anonymous mixnet routing, with fixed-size payloads, per-hop key derivation, and integrity verification via HMACs.
url: https://nym.com/docs/network/cryptography/sphinx
---

# Sphinx

Sphinx is the cryptographic packet format used for all mixnet traffic. It provides layered encryption where each hop can only decrypt its own routing information, ensuring that no single node knows both the source and destination of a packet.

## How Sphinx works

When a client sends a message through the mixnet, it constructs a Sphinx packet with multiple encryption layers, one for each hop in the route. The outermost layer is encrypted for the first hop (Entry Gateway), the next layer for the second hop (Mix Node Layer 1), and so on until the innermost layer contains the actual payload encrypted for the recipient.

At each hop, the node uses its private key to decrypt its layer, revealing the address of the next hop and a new Sphinx packet to forward. The node cannot see any other routing information or the payload contents.

## Packet structure

All Sphinx packets have a fixed payload size of 2048 bytes. This uniformity is critical: if packets varied in size, nodes could infer their position in the route or correlate packets by size.

The packet contains a header with encrypted routing information for each hop, HMACs to verify integrity at each layer, and the encrypted payload. The header uses a clever "onion" structure where processing at each hop reveals only the next hop's information while maintaining constant size through padding.

## Integrity verification

Each layer includes an HMAC (Hash-based Message Authentication Code) that the receiving node verifies before processing, which prevents malicious nodes from modifying packet contents en route. If the HMAC doesn't match, the packet is dropped.

The payload uses Lioness wide-block encryption, which means any modification to any part of the payload invalidates the entire payload. This prevents bit-flipping attacks where an adversary might try to modify specific bytes.

## Key derivation

For each hop, the client performs an ECDH key exchange using the node's public key and an ephemeral key embedded in the packet header. This shared secret is then used with HKDF to derive the symmetric keys for that layer's encryption and HMAC.

The ephemeral key is "blinded" at each hop so that successive nodes cannot correlate packets by the key value. Each node sees a different ephemeral key even though they're mathematically related.

## Message fragmentation

Messages larger than a single Sphinx payload are split into fragments. Each fragment travels independently through the network, potentially taking different routes. The recipient reassembles the fragments into the original message.

## External implementation

Nym uses the [`sphinx-packet`](https://github.com/nymtech/sphinx) crate for core Sphinx operations. This crate handles packet construction, header encryption, layer processing, and the mathematical operations for key blinding.

## References

- [Sphinx paper](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf): Original specification and security proofs
- [Elle Mouton's Sphinx explainer](https://ellemouton.com/posts/sphinx/): Detailed walkthrough of packet construction
- [Nym Whitepaper §4](https://nym.com/nym-whitepaper.pdf): Sphinx in the context of Nym

---
title: What are zk-nyms?
url: https://nym.com/docs/network/cryptography/zk-nym
---

# What are zk-nyms?

The zk-nym scheme enables the creation and use of unlinkable, rerandomisable anonymous access credentials that are 'spent' with Gateways in order to anonymously prove that someone has paid for Mixnet access. This implementation incorporates elements of both the [Coconut Credential](https://arxiv.org/pdf/1802.07344) and [Offline Ecash](https://arxiv.org/pdf/2303.08221) schemes.

As outlined in the [overview](./zk-nym/zk-nym-overview) on the next page, zk-nyms allow for users to pay for Mixnet access in a manner that is **unlinkable to their payment account**; even with pseudonymous cryptocurrencies or fiat. This solves one of the fundamental privacy problems with the majority of VPNs and dVPNs in production today: the linkability of a user's session with their payment information, which can in the majority of cases be easily used to deanonymise them, either at the behest of an authority or by the service operators themselves.

> The current zk-nym scheme is non-generic in that it is only used for gating Mixnet access. A generic scheme based on zk-nyms is being actively researched in order to facilitate more generic and customisable anonymous credentials for other applications and services.

## Motivations
Most of the time, when we build system security, we think of _who_ questions:

- Has Alice identified herself (authentication)?
- Is Alice allowed to take a specific action (authorisation)?

However, _who_ is not necessarily a question we want to be asking when designing a system with anonymous access control. This scheme allows us to instead consider questions of _rights_, namely:

- Does the entity taking this action have a right to do _X_?

This allows a different kind of security. Most networked services do not need to know _who_ is making a request, only whether the requester has the _right to use_ the system.

The zk-nym scheme allows for this move to take place. Credentials are generated cooperatively by decentralised, trustless systems, and once the credentials are generated, they can be _re-randomized_; entirely new credentials, which no one has ever seen before, can be presented to the ingress point of the Nym Network, and validated without being linkable back to the signatures produced by the Quorum of credential signers used to generate them, or any credentials previously used by an entity wanting access. These properties allow zk-nyms to act as something like cryptographic bearer tokens generated by decentralised systems. The tokens can be mutated so that they are not traceable, but still verified with the original permissions intact.

> TL;DR: Users present cryptographic claims encoded inside the credentials to get secure access to resources despite the systems verifying credential usage not being able to know who they are.

### Re-randomisation vs pseudonymity
We stand on the shoulders of giants. Ten years ago, Bitcoin showed the way forward by allowing people to control resource access without recourse to _who_ questions. Rather, in Bitcoin and succeeding blockchains, a private key proves a _right to use_.

But as we can now see, private keys in blockchain systems act only as a minor barrier to finding out _who_ is accessing resources. A Bitcoin or Ethereum private key is effectively a long-lived pseudonym which is easily traceable through successive transactions.

**zk-nyms allows us to build truly private systems rather than pseudonymous ones.**

## Features
Specifically, zk-nym is an implementation of a blinded, re-randomizable, selective disclosure threshold credential signature scheme.

Let's say you have a `message` with the content `This credential controls X` in hand. In addition to the normal `sign(message, secretKey)` and `verify(message, publicKey)` functions present in other signature schemes like RSA, the zk-nym credential scheme adds the following:

1. _[Blind signatures](https://en.wikipedia.org/wiki/Blind_signature)_ - disguises message content so that the signer can't see what they're signing. This defends users against signers: the entity that signed can't identify the user who created a given credential, since they've never seen the message they're signing before it's been _blinded_ (turned into seemingly random binary data). The scheme uses zero-knowledge proofs so that the signer can sign confidently without seeing the unblinded content of the message.

2. _Re-randomizable signatures_ - take a signature, and generate a brand new signature that is valid for the same underlying message `This credential controls X`. The new bitstring in the re-randomized signature is equivalent to the original signature but not linkable to it. So a user can generate multiple zk-nyms from a single credential source, unlinkable to any previous "shown" zk-nym. But the underlying content of the re-randomized credential is the same (including for things like double-spend protection). This once again protects the user against the signer, because the signer can't trace the signed message that they gave back to the user when it is presented. It also protects the user against the relying party that accepts the signed credential. The user can generate multiple re-randomized credentials repeatedly, and although the underlying message is the same in all cases, there's no way of tracking them by watching the user present the same credential multiple times.

3. _Selective disclosure of attributes_ - allows someone with the public key to verify some, but not all, parts of a message. So you could for instance selectively reveal parts of a signed message to some people, but not to others. This is a very powerful property of the scheme which is to be explored more in future work, potentially leading to diverse applications: voting systems, anonymous currency, privacy-friendly KYC systems, etc.

4. _[Threshold issuance](https://en.wikipedia.org/wiki/Threshold_cryptosystem)_ - allows signature generation to be split up across multiple nodes and decentralized, so that either all signers need to sign (_n of n_ where _n_ is the number of signers) or only a threshold number of signers need to sign a message (_t of n_ where _t_ is the threshold value).

Taken together, these properties provide privacy for applications when it comes to generating and using signatures for cryptographic claims. If you compare it to existing tech, the closest analogy in conventional systems is a decentralized, privacy-preserving [JWT](https://jwt.io/).

---
title: Generating and using zk-nym anonymous credentials
url: https://nym.com/docs/network/cryptography/zk-nym/zk-nym-overview
---

# Generating and using zk-nym anonymous credentials

  zk-nyms are already used in production by [NymVPN](https://nymvpn.com) to unlink subscription payments from network activity. The entire credential lifecycle described on this page (key generation, issuance, spending) happens transparently within the NymVPN application. SDK integrations currently connect to the Mixnet without requiring credentials.

Generation of zk-nyms involves the following actors / pieces of infrastructure:
- **Requester needing a zk-nym** for example a single user using the NymVPN app, or a company purchasing zk-nyms to distribute to their app users, in the instance of an app integrating a Mixnet client via one of the SDKs. The Requester is represented by a Bech32 address on the Nyx blockchain.
- [NymAPI](/network/infrastructure/nyx#nym-api) instances working together on signature generation and spent credential validation, referred to as the **NymAPI Quorum**. Members of the Quorum are a subset of the Nyx chain Validator set (other tasks they perform include a multisig used for triggering reward payouts to the Network Infrastructure Node Operators and maintaining the global Bloom Filter for double-spend protection).
- **OrderAPI**: an API creating crypto/fiat to `NYM` swaps and then depositing the NYM tokens in a smart contract managed by the NymAPI Quorum for payment verification. Implementation details of the API will be released in the coming months.

Generation happens in 3 distinct stages:
- Key Generation & payment
- Issue credential
- Generate unlinkable zk-nyms for Nym Network access

From the Requester's perspective this happens transparently, producing an unlinkable, rerandomisable anonymous proof-of-payment credential (a zk-nym) that grants Mixnet access without linking usage to payment information. A single credential can be split into multiple smaller zk-nyms, so a Requester purchases bandwidth in bulk and spends it incrementally across different ingress Gateways as needed.

## Key Generation & Payment
- First, a Cosmos [Bech32 address](https://docs.cosmos.network/sdk/latest/guides/reference/bech32#performance-address-caching) is created for the Requester. This is used to identify themselves when interacting with the OrderAPI via signed authentication tokens. **This is the only identity that the OrderAPI is able to see, and is not able to link this to the zk-nyms that will be generated.** This identity never leaves the Requester's device and there is no email or any personal details needed for signup. If a Requester is simply 'topping up' their subscription, the creation of the address is skipped as it already exists.
- The Requester also generates an ed25519 keypair: this is used to identify and authenticate them in the case of using zk-nyms across several devices as an individual user. However, **this is never used in the clear**: these keys are used as private attribute values within generated credentials which are verified via zero-knowledge and not publicly exposed.

- The Requester can then interact with various payment backends to pay for their zk-nyms with crypto, fiat options, or natively with NYM tokens.
- Payment options will trigger the OrderAPI. This will:
  - Create a swap for `<PAYMENT_AMOUNT>` to `NYM` tokens.
  - Deposit these tokens with the NymAPI Quorum via a CosmWasm smart contract deployed on the Nyx blockchain.
- The Requester sends a request to each member of the Quorum requesting a zk-nym credential. This request is signed with their private key and includes the transaction hash of the NYM deposit into the deposit contract, performed either by themselves or the OrderAPI.

## Issue zk-nym
At this point, NYM tokens have been deposited into the smart contract controlled by the Quorum's multisig and a zk-nym has been requested. Next, each member of the Quorum who responds to the Requester's request for a zk-nym checks the validity and returns a partial blinded signature - a 'partial signed credential' ('PSC') - signed with part of the master key (since this is a threshold cryptosystem, not all members of the Quorum must respond to create a zk-nym, only enough to pass the threshold). The process looks like this:

- Members of the Quorum perform several checks to verify the request is valid:
  - They verify the signature sent as part of the request is valid and that the request was made in the last 48 hours.
  - They verify that the amount requested matches the amount deposited in the transaction, the hash of which was signed by the Requester's ed25519 key and sent as part of the request.
- Members then create a PSC from their fragment of the master key generated and split amongst them at the beginning of the Quorum in the initial DKG ceremony.
  - The member also creates a `key:value` entry in their local cache with the transaction hash as the key, and the PSC + encrypted signature as the value. This is used later for zk-nym validation and is cleaned after a predefined timeout.
- These PSCs are given back to the Requester after setting up a secure channel via DH key exchange, with each replying Quorum member also sending their public key for verification that the returned PSC was signed by them.

Once the Requester has received over the threshold number of PSCs they can assemble them into a 'ticketbook' of 'tickets' - spendable credentials - signed by the master key. The Requester never learns this master key (it is a private attribute) but the credential can be verified by the Quorum as being valid by checking for a proof that the credential's private attribute - the value of the master key - is valid.

![](/images/network/deposit-generate.png)

## Spend zk-nym to Access Mixnet
- Once the ticketbook has been aggregated from the PSCs returned from > threshold of Quorum members, smaller 'ticket' credentials can be generated from it, accounting for smaller chunks of bandwidth which can be 'spent' with ingress Gateways. This occurs entirely offline, on the device of the zk-nym Requester. See pages on the scheme's [unlinkability](unlinkability) and [rerandomisation and incremental spending](./rerandomise) features for further information on this.
- This ticket is later presented to the Quorum by the Gateway that collected it, which is used to calculate reward percentages given to Nym Network infrastructure operators by the Quorum, with payouts triggered by their multisig wallet. Both ingress Gateways and the Quorum use spent tickets when engaging in [double spending protection](./double-spend-prot).

![](/images/network/use-zknym.png)

---
title: Rerandomisation & Incremental Spend
url: https://nym.com/docs/network/cryptography/zk-nym/rerandomise
---

# Rerandomisation & Incremental Spend

Each ticket will not be valid for the entire amount of data that the ticketbook aggregated from the PSCs is; if the aggregated ticketbook is worth (e.g.) 10GB of Mixnet data, each ticket will be worth far less (e.g. 100MB). This amount will be globally uniform in order to avoid situations where differently sized tickets allow for patterns to emerge.

  The `nym-cli` examples below are for illustration only and do not reflect how credentials are accessed in production. The specific figures (ticket counts, bandwidth amounts) are illustrative; production values may differ, though individual ticket sizes are uniform across the network.

## Why a 'ticketbook', not individual 'tickets', and why not spend them all at once?
This is to account for the need for a client to change their ingress Gateway, either because the Gateway itself has gone down / is not offering the required bandwidth, or because a user might simply want to split their traffic across multiple Gateways for extra privacy.

Clients are therefore not tied to a particular Gateway they have spent their entire subscription with. If an ingress Gateway goes down, or the client simply wants to use a different one, remaining tickets can be spent with any other Gateway.

Going back to the `nym-cli` tool to illustrate this; we can generate multiple unlinkable tickets from a single ticketbook aggregated from PSCs:

```sh
❯ ./nym-cli ecash generate-ticket --credential-storage storage.db --provider 6qidVK21zpHD298jdDa1RRpbRozP29ENVyqcSbm6hQrG --full
TICKETBOOK DATA:
4Ys9pzUf9MPxX4s5RASyrRoY9fPk1a1kFuPBP2jm2L5PyUy535yPEfjHAfpUTC1Lf2d155TmjukvcDycQYfBSDfhEUJM4J3qPNfG3B5aQEEkefESZp3CM5AEnAu1AEyhpepbYw6BuXokiNcmaYtq3yJQbA4KicKP8FowoRzKHmXpJoUqY8wYQughGfdtXgr3rVaZmK21X51P1NL2UW1aCE512WWfy6P1LJHByWywT3qVw28Z83

generating payment information for 50 tickets. this might take a while!...
AVAILABLE TICKETS
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+
| index | binary data                                                                                                                                                   | spend status       |
+============================================================================================================================================================================================+
| 0     | 4kgKyJLq1zQuk9r9AbEFHPqD8mDuxsLSjgo9XW4Lf7EqGSbgfNsWSEcTbRPEMFLzpstbX5azsA3opFh851h4g5qCG2qE3Luwqua4GG2ebJhk91rvEc5JPctbVQxL62fkfQ6svdcNp…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 1     | 4kefQqViRZd5YezMHH1FTcgUGPK2E2ivfmwgf59exvsnR8tsb5aJtGVwpA7wAJT6icPeo8jtDwDZ3WMPJxL3VRLiakAQr79zh7ixM89gowg3ChHEy6ewmHcT7T6RFkZFsMCMj1CNd…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 2     | 4kxaKdBxyFzJ8gxSZCh1v3wBfN7JvnCJuoJ4MWqkkMHtt2XgRKbDmHCv5ZxtA57Qk8LC3NDMBmqjADvY34mAPdT3tLBL4uxse9ASa227Ji96dwgxvfbpvLXSSr5o4vuPRV9K7UfpJ…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 3     | 4kdYwUJwXyxZBLQXextd4GsU2MATjzArVq5Ec459fTXyrm6q3vxurWULzBMpV5UjcmjJtnw1zFqt7f8Ydu5gyxwAVXP3Nwpn83ouguv2n4YrUewZCvFAqQYXgahhhaQGp6RxK2Arh…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
...

| 46    | 4kg8bfQ7kGgq5TkkqXagpAEu95gmGT4i7NKbaxJtp2gRgWRrQZM1rxaDAzAxfghoM6PFNbYgKsnLD4MF8HtXW3p92CnPBjswzJ1EbtsMGpgDER3CYFt2ivAhMAVXFziF5UjVJXhpa…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 47    | 4kipbH5Fqt5E9hFMynm9vzFh5FkxKRdHrSEiiJWDwmg3mASctR61sXoFD5u5ZMBwGdvz9sWsRfrpR4MX2NNfRhC85aUxqtkAv3hXZiCLtE1pUC54Cq7YXHyv2XTNKpvuFZs2GmwYg…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 48    | 4kxYZ26HXvxVhh4quHXeCUyQokydeF5wkwUi8fMx6P3uoMvuiPaNP1SJTbYnaQEFFtF6U4dGop6QckUYvbtwQFoGJTJesHFHTDtHbshj5Dg8DwbyaHuAR86zGwYMUPved4XKUTMLa…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 49    | 4kb6zmPebRxjKLVicctq2whvANjWJMoohiPBMr21cT4xj78nvXmJEK8EB4PpqQVFo6ddU9uzuer5ggQZNZgETX2VXBzymBYNzXBuXjLJi1WRdAiASqWz5Hv5im1TJh4XBE4mxKo8Q…1057bytes remaining | NOT SPENT |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+
```

---
title: Unlinkability
url: https://nym.com/docs/network/cryptography/zk-nym/unlinkability
---

# Unlinkability

Each time a credential is requested by an ingress Gateway to prove that a client has purchased data to send through the Mixnet the Requester's device will produce a ticket. This is a rerandomised value that is able to be verified as being legitimate (in that it was created by a valid root ticketbook) but **not linked to any other tickets**, either previously generated or to be generated in the future. This feature also allows for a single ticketbook to allow access to be split across multiple ingress Gateways / connections and [incrementally spent](./rerandomise) over time.

The functionality included in the following code block examples were added to the [nym-cli tool](/developers/tools/nym-cli) for illustrative purposes only: this is not necessarily how credentials will be accessed in the future.

The numbers used in this high level overview are for illustration purposes only. The figures used in production will potentially vary. Note that individual zkNym sizes will be uniform across the Network.

```sh
❯ ./nym-cli ecash generate-ticket --credential-storage storage.db --provider 6qidVK21zpHD298jdDa1RRpbRozP29ENVyqcSbm6hQrG --ticket-index=3
TICKETBOOK DATA:
4Ys9pzUf9MPxX4s5RASyrRoY9fPk1a1kFuPBP2jm2L5PyUy535yPEfjHAfpUTC1Lf2d155TmjukvcDycQYfBSDfhEUJM4J3qPNfG3B5aQEEkefESZp3CM5AEnAu1AEyhpepbYw6BuXokiNcmaYtq3yJQbA4KicKP8FowoRzKHmXpJoUqY8wYQughGfdtXgr3rVaZmK21X51P1NL2UW1aCE512WWfy6P1LJHByWywT3qVw28Z83

attempting to generate payment for ticket 3...

PAYMENT FOR TICKET 3:
VfZAuVRRHekQYMvFevNAZmPPuwMAfEhTBY8TXatBysbrNXAg8euEGPpJvdbhNfQSznBb9nRSeBUSVoNTToSA6Uj5dXmJ7oE2rCB439DarLMWHWYfQNhw6yhWJhcg6bt7ebBYTs3vVeQgSB5kYuifzJF4QQmK6uJyTNPvpV1J6V8M32PBkGT3JpVB3GUGZiksETf7TaF9wAhMo2QAMxw5ZvaQVve5ea7Mane6cfb2Gx69SRff5zDfEQvKqKnyyZje4SGZgWUeHWVLhRjg4KMTJ3JcsHxEqj2k5qeGeyBbgzcuEtCpYvaytsz7nuZGJsT4Z87gB5Zq4NGuDmekuN977eRJvua2dASNWeHiAzVyvnS7ARN5cdUjjYKYiWgHaYrHGsv26WTDeiu4U3sdJMrLHGFY5ihX7f8sTZqD6Wx5AWjQNbEtKaVHymDogfLcwGCC42gQ2yhKfPUaWJ8H4yMB65YBDXGjATaUzcDmJcZKx8g31j2uTVNSFUesd5CRNEEcTNW7cSFFCishCD3T4eV9SuyZyEXAZ48pazPzc1BysBNHEXQNUEtEAZTKmpghC2pihhfDub6LnMJPo9DDdhCULCbcWbGAPc1vPekPaWvk7wrUTGwp5xoNUhQLW3MeJzMvrMSsqLdursCKB4h4Tk272WCStCPQwAKMYoxjWvMzxoUTTWCkhLKHruMtsehRnai4vhu13jbui6ji1F389gfazm4ctth2s4Yw3H3SaPtRETBfZNvZ7n5UV1MD6Q3qin92gT65iqXEi4zRN3woYcK6ZehiSvgUksdEFAUSxNMgNXKtHEYDS6kA37tn5JdBa2Ex2jLudFfhg6JBM226ZKyj65o6feYPgbJAR3jMCmQRHe6DSFb4aH895EowNMjfGUhwhmnbYB1djp7iFXxPP7575NAerhxEQ1WFnxTfoX7pu1Vc9YZb5priCAVbATCaDkECJsdedM45Vx96Jc6E5NWqD98RhMsPimVJkSfYJmRxH9qugica6WonFFb2YLvXYyhoBA1VHBcRqZJ5KHitS5AegYSoYprUfubMzcYo2hGVEQkGKAsFq6jZgCsbJoGLXt3No317vcowB5f3hqT9FjASHAzW2j8uJ9RRzX7XtrPhArwx4EyPgYzrvgG7xcenoSgQt8poa7aYky56eZTKHVUZgUEt6St32MjcivMvmNdWiAHHDc2ZxzTJHgeuCckX7n19vQ3XNLuXv9oGKNNCi8kHnT4tUnnGXNAWXWuyBgZKWUL8u3y41iW6dLYK3Pw5zfpKZTrq3q3bTLJRN5LnnUuFVnWsC3SNqa6VAAvhTGR9PzxLk8C6HeLP2AsYPpqeQwbaL3Ks6tvPdob3tQPWRBGL4uiKtNZ23tRYZGZLYFWZK7psRSZg5AETejKxztVzAuYovpVUiDq71o331tjqWWV1SzWT13Rd1uwz6nHtsjgao2863YaizKARcYr1j9MKtNfDs483yho6i7tbCRR9M4CPLqdiKEaRyVC1FP4F3sejA6nZTuAA35JWUzX6BBj7wgdypMLdMmmtcCZm3bRrF3GvJJs67U8JWRc6dnoGUDaD7rUu
```

Now lets generate another ticket to spend either topping up once the previous one's data allowance has been used, or with another Gateway. Notice that the `ticket-index` is the same: this is generated from the same aggregated credential as the one above!

```sh
❯ ./nym-cli ecash generate-ticket --credential-storage storage.db --provider 6qidVK21zpHD298jdDa1RRpbRozP29ENVyqcSbm6hQrG --ticket-index=3
TICKETBOOK DATA:
4Ys9pzUf9MPxX4s5RASyrRoY9fPk1a1kFuPBP2jm2L5PyUy535yPEfjHAfpUTC1Lf2d155TmjukvcDycQYfBSDfhEUJM4J3qPNfG3B5aQEEkefESZp3CM5AEnAu1AEyhpepbYw6BuXokiNcmaYtq3yJQbA4KicKP8FowoRzKHmXpJoUqY8wYQughGfdtXgr3rVaZmK21X51P1NL2UW1aCE512WWfy6P1LJHByWywT3qVw28Z83

attempting to generate payment for ticket 3...

PAYMENT FOR TICKET 3:
Vev3SmwWtH5vbnejX5Zzc1EcxXAgveqHpKNN8arxXaWLhFcEpdcZ6n7qr3NrQUNURWsK2AsUiX8aSiGSjMPEY3iDE3aDYnjYERVow8RKUmQiYSKvz7v9cEJxt97JAHBfu9WYNHXTnLFSJwWuFtBdzY5dzPdzGckFenGCysa1ZBHGADHChDVXKoPHXxpn5qyJxmi48coUQDptR64QgkCeQ8RRZ396Lxw2NKFSjqavCMMDVm3g1rW7cYyPanBhkoAUzPU9KXX1rtmhD6F9gV89mGZ8fm7ByDuKuYU28seLQ7GkVKkhNeRW9XxbjSiyscTnMUzJ24R5VbSdr141BaquUHezdUTzmA2EjAtcyyiVrCMV13cc96CRbMXENP2soUzckFnh1qPnrfKCvX4JYkztq7UgPT2mZEnSTDW4C6Z2NVCNBPNLqUSYrU4id8Jzcp1mBxqJjdYcQ7P5fWJbT5Q9NAq44PCgfXpsUkNoj35QVQvKXKLb5oNGqnua5YC1WBPcENcpS7ZPWpk2hwe8VK4gNgnwQtWH2RPmWbvBREAV97vS1vKNHJyry9sD2PiMJGSmBnb1bKsGxR9UQN3YvRsdGHzyJHzAMTzxbFJBqMPmxjSHJR4UdwzhB81Ludu1RAffTvecWFxmWH5bNymCQjw3wey7Uequcxgyy8KAWYDzvHGwCZQbHQXghsYREiqquZWaa8hX3iTNBFUtEk8PRVT78MoFNdeBWNjsLr8zyZ5EGnf4kqmw3a91g5p5vywf6e3LgMu19VHjPSNtKMNXiatkPEVjsCuCppmV4sB7FsdKKWcMUSWLsdmrDBg9PStHr7NaJRzLL5E91gvysmB36Nob9cHeHSZj3wM4NVVjFfZeRqQf4bi7ahfXjeeBetgDpqx7JcbU6tTN4JpcGUpp7fp4MhTq7MeVQMLweGUVLqewKgAGzCvEmrK6dzLd3U1P9vkAAVZ3cCAKUywnHGxoxDeEfexP1g1EqJLtKNZVKPf7hSMWqGhoQ36K7y5GnyZ5YhQ7jcDME9orm5w4StoxoDdCPcjbakKG7UaTHuhd7tU1mUffXcEvVerkXoQK9SEaKvGks21RBhW86aHUzJWVbkiDzdaqjJWbmzLV8FKvNxNyzucoH2rq8LiHRMZfV1H3SkVSa4j2Ktw7ZGoQfdj8DgekxXSR2nHPfhybzKYXTBqFo2ACisxkjR4rXr9Xo6eYywQhQ1MP6aYgYCAXFGHPoFf7kx7Jns5sWvHRBdaMF65zeFF2m5NDuMWETtLgFfsyNgR84vfSqTfzj2gsUykRei7q9N4LKmiDwBALTAEcTvZpLtXBjc8JaB9PUeBw7DoSiSK376sGrQ9F6ZGTngXACNz1TbvYhtau4bDa6KC2Qn7wmoyrphpn7TtM1jdwGBxLcaEEWZKQHvWVfTyL2itjqnrcAZkxYdCj56oQYwpWfKQk3zJEUA6SYHqyJjaLNVK6u25j7969EWjdpTsJ8qSsZgXi3T7dQqiwintZbUUUKRq7egN1SGVnA6Wup91uKrYUWEWMqVu4g8ipmRsLD9iXHHr3yA21Cka7pqk1FxR9BFTAnkk1
```

These are both generated by the _same_ underlying ticketbook and used in a way that they cannot be tied to each other. An ingress Gateway might (for instance) get 100 connection requests from 100 Nym clients, each validated with a ticket. It has no way of knowing whether these are all from the same single subscription, or 100 different ones.

---
title: Double Spend Protection
url: https://nym.com/docs/network/cryptography/zk-nym/double-spend-prot
---

# Double Spend Protection

Double spend protection in the context of zk-nym is a balancing act between speed, reliability, and UX. There are two possible modes for protecting against attempted double spending of zk-nyms:

- Online: The online approach mandates that ingress Gateways instantly deposit zk-nyms received from clients to the NymAPI Quorum for verification. Once verified by the Quorum, the ingress Gateway is paid proportional to the amount of bandwidth 'spent' with the zk-nym, and proceeds to grant the client access to the network.
- Offline: In contrast, the offline approach involves the periodic submission of collected zk-nyms by ingress Gateways to the Quorum, instead of an instant check. Subsequently, the Quorum nodes perform checks to detect any instances of double-spending and identify the public key associated with such occurrences, whereas the ingress Gateways only do a simple check to check that _that particular_ zk-nym had not been spent with itself before.

> The zk-nym system takes the **offline** approach.

## Offline Approach: Pros & Cons
The advantages of the offline approach are manifold:
- Immediate access to the Nym network upon zk-nym submission, eliminating any delays in service provisioning until payments are deposited and verified as would occur in the online approach.
- Alleviates performance strain on ingress Gateways and Quorum members, serving as a more efficient method compared to the online counterpart. By moving computationally intense work to the Quorum, this means that Gateway nodes are able to be run on less powerful machines, meaning more operators can more easily run them (and cover their costs) and thus increase the overall number and spread of Gateways around the globe.
- Moreover, the offline approach can circumvent the potential issue of overwhelming the blockchain with the serial numbers of spent coins.

However, the offline approach introduces certain limitations.
- Ingress Gateways accept zk-nyms without preemptively checking for instances of double spending thus making them susceptible to unknowingly accepting double-spent credentials.
- Any potential repercussions against double spenders can only be implemented once the user requests a new credential for their zk-nym Generator (aka they have to 'top up' and buy more bandwidth allowance), assuming they haven't altered their identifier (the Bech32 address).

An exploitable scenario arises from these limitations:
- A malicious user purchases bandwidth and aggregates a valid zk-nym credential in the standard way, worth $10 of crypto/fiat. Subsequently, the malicious user proceeds to sell the credential to 100 users for $1 each, allowing each user to generate zk-nym tickets of 100MB from this **valid** credential. Under the offline approach, entry nodes forego double-spending checks; so long as the clients all used different ingress Gateways, all 100 users could access the network without obtaining a subscription. As bandwidth consumption is tracked locally between client and ingress node, and each zk-nym ticket is rerandomised, there is no way that ingress Gateways would know that the zk-credential used by the client has been shared with other parties. This loophole highlights the need for stringent measures to counter such potential abuses within the system, without creating either speed bottlenecks (in the case of the Online model) or impacting the anonymity of the system. We can, however, mitigate this problem without doing either of these things.

## Solution to Offline Double Spending
To efficiently prevent the fraudulent use of tickets within the Nym network, a two-tiered solution is in place that combines (1) the immediate detection of double-spending attempts at the level of individuals ingress Gateways and (2) subsequent identification and blacklisting of offending clients at the Quorum level.

### Entry Node Implementation: Real-Time Ticket Validation
Each spent zk-nym ticket contains as an attribute a unique serial number, which is revealed in plaintext to the respective ingress Gateway. Each Gateway has a copy of a [Bloom Filter](https://www.geeksforgeeks.org/bloom-filters-introduction-and-python-implementation/) - on receiving a ticket, it will check against its copy of a local database to check whether this serial number has already been seen. If so, it rejects the ticket as being double-spent and the client's connection request is rejected. If not, it will add the serial number to its local DB.

> Since each time a zk-nym credential is rerandomised its serial number is changed, the serial number being shared in no way identifies a client or user.

Each Gateway will periodically share their serial numbers with the Quorum and refresh their copy of the Bloom Filters from the Quorum, in order to refresh the global list shared by all ingress Gateways and the Quorum. See the step below for more on this.

> Crucially, ingress Gateways refrain from extensive computations to identify the original ticket owner, and avoids broadcasting information about the double-spending attempt to other ingress Gateways. The entry node is also not involved in any global blacklisting process of the clients. The sole purpose of this check is to swiftly identify any attempts at double-spending and add the seen ticket's serial number to the local DB cache.

### Nym-API Implementation: Blacklisting and Penalties for Double-Spenders
All Gateways periodically forward the collected tickets to the Quorum, enabling them to pinpoint and blacklist any clients who double spend. Upon receiving the tickets, the Quorum appends all the incoming serial numbers to the global list of spend zk-nym serial numbers and proceed with the identification process for any malicious users engaging in double-spending.

This identification phase involves looking for instances of double spending, identifying the id of the double-spending client, and blacklisting this client by its id. Subsequently, when this client requests a new credential, their plaintext public identifier is included in the request. The Quorum then checks if this identifier is blacklisted. If it is, a new credential is not issued. Furthermore, since the PSCs are only attainable after depositing NYM as payment, the Quorum has the authority to withhold the deposited NYMs as a punitive measure for any detected instances of double-spending.

---
title: Nym Network Infrastructure
description: Overview of the Nym Network's decentralized infrastructure: independently operated nodes coordinated by the Nyx blockchain for routing, key management, and credential issuance.
url: https://nym.com/docs/network/infrastructure
---

# Infrastructure

The Nym Network runs on decentralized infrastructure: a set of independently operated nodes coordinated by the Nyx blockchain, where no single party controls routing, key management, or credential issuance.

## In this section

- [Nyx Blockchain](/network/infrastructure/nyx): the Cosmos SDK chain that maintains the node registry, manages token economics, and hosts the smart contracts for credentials and rewards
- [Nym Nodes](/network/infrastructure/nym-nodes): the unified `nym-node` binary that operates as Entry Gateways, Mix Nodes, or Exit Gateways depending on network demand

---
title: Nyx Blockchain
description: How the Nyx Cosmos SDK blockchain coordinates the Nym Network by maintaining node topology, managing NYM token economics, and hosting smart contracts for credentials and rewards.
url: https://nym.com/docs/network/infrastructure/nyx
---

# Nyx Blockchain

Nyx is a Cosmos SDK blockchain that coordinates the Nym Network. It maintains the topology of active nodes, manages token economics, and hosts the smart contracts that power the credential system.

To interact with the chain, see [Interacting with Nyx](/developers/chain). To run a Validator, see the [Operator Documentation](/operators/nodes/validator-setup).

## Role in the network

The blockchain serves several functions, including maintaining the **topology registry**: the list of active nodes and their public keys. This eliminates the need for a centralized directory server and prevents attacks that plague peer-to-peer directory systems.

It manages **token economics**, where the NYM token is a native token of the chain, used for staking, rewards, and credential payments. Validators secure the chain via proof-of-stake consensus.

And it hosts **smart contracts** for mixnet coordination and the zk-nym credential system.

## Validators

Nyx Validators run the `nyxd` binary to maintain the blockchain. They process transactions, execute smart contracts, and participate in consensus. A subset of validators also run Nym API instances for credential issuance.

## Nym API

For setup instructions, see the [Nym API Operator Guide](/operators/nodes/validator-setup/nym-api).

The Nym API is operated by a subset of validators forming the "Quorum." This group performs network monitoring: sending test packets through the mixnet and calculating reliability scores for nodes. More critically, it handles credential issuance, generating the partial blind signatures that form zk-nyms.

The Quorum uses threshold cryptography. No single member can issue credentials alone. The system remains functional even if some members are offline. This distributes trust across multiple independent parties.

## Smart contracts

The Nyx chain is CosmWasm-enabled. The **Mixnet Contract** stores bonded node information, provides network topology for client routing, and tracks delegations and rewards. The **Vesting Contract** manages NYM token vesting schedules. The **zk-nym Contract** tracks deposits for credential generation and manages the blacklist for double-spend attempts.

Contract addresses for different networks can be queried via the [Nym API](/apis/nym-api).

## Querying the chain

The [Nym API](/apis/nym-api) provides HTTP endpoints for querying network topology, node status, rewards, and credential information. For direct contract interaction, see the [Developer Documentation](/developers/chain).

---
title: Nym Nodes
url: https://nym.com/docs/network/infrastructure/nym-nodes
---

# Nym Nodes

All traffic-routing infrastructure runs on the `nym-node` binary. This unified binary operates in different modes (Entry Gateway, Mix Node, or Exit Gateway), simplifying deployment and enabling future dynamic role assignment.

To run a node, see the [Operator Documentation](/operators/introduction).

## Node modes

**Entry Gateways** are the user's first point of contact with the network. They accept WebSocket connections from clients, verify zk-nym credentials to confirm payment, and store messages for clients that go offline. Entry Gateways know the client's IP address but cannot see message contents or final destinations.

**Mix Nodes** form the three mixing layers that provide core privacy. They receive Sphinx packets, remove one encryption layer, verify integrity, apply a random delay, and forward to the next hop. Mix Nodes cannot determine their position in the route and cannot link incoming packets to outgoing packets.

**Exit Gateways** handle traffic leaving the mixnet. They run two proxy services: the [Network Requester](/network/infrastructure/exit-services#network-requester) (a SOCKS proxy for application-layer requests) and the [IP Packet Router](/network/infrastructure/exit-services#ip-packet-router) (a raw IP tunnel used by NymVPN and smolmix). Exit Gateways can see destination addresses but cannot identify the original sender. See [Exit Gateway Services](/network/infrastructure/exit-services) for details.

## Unified binary

The various components were originally separate binaries but have been consolidated into a single `nym-node` binary where the role is specified at runtime. This simplifies operation and makes configuration consistent across roles.

In the future, nodes will automatically switch modes based on network conditions. Operators won't need to manually set whether a node is a Gateway or Mix Node; the network will assign modes dynamically each epoch.

## Nym clients

For client setup, see the [Developer Documentation](/developers/clients/socks5).

Clients are the user-side software that connects to the network. They discover network topology from the blockchain, register with an Entry Gateway, construct Sphinx packets with layered encryption, generate cover traffic, and handle acknowledgements and retransmission.

Client types include native Rust clients, WASM clients for browsers, the SOCKS5 proxy client, and the NymVPN client. The NymVPN client supports both dVPN and mixnet modes.

## Running infrastructure

The current deployment includes {stats.nodes} active nodes across {stats.locations} countries, operated by independent parties worldwide. This includes {stats.mixnodes} Mix Nodes and {stats.exit_gateways} Exit Gateways. Running a node requires meeting minimum hardware specifications, bonding NYM tokens as collateral, and maintaining high uptime for rewards.

---
title: Exit Gateway Services: Network Requester & IP Packet Router
description: The two proxy services running on Nym Exit Gateways, the Network Requester (SOCKS proxy) and the IP Packet Router (raw IP tunneling), how they work, what they see, and who uses them.
url: https://nym.com/docs/network/infrastructure/exit-services
---

# Exit Gateway Services

Exit Gateways are where traffic leaves the Nym network and reaches the wider internet. Each Exit Gateway runs two distinct proxy services that handle different kinds of outbound traffic:

- **Network Requester (NR)**, an application-layer SOCKS proxy
- **IP Packet Router (IPR)**, a raw IP tunnel with address allocation

Both services run on every Exit Gateway. Which one handles your traffic depends on how you connect.

## Network Requester

The Network Requester is a SOCKS4/4a/5 proxy. Clients send SOCKS-formatted requests through the mixnet, and the NR makes the corresponding connection on their behalf: resolving hostnames, opening TCP connections, and relaying data.

```text
Client → mixnet → Exit Gateway (NR) → SOCKS connect → destination
                                    ← relay response ←
```

Because it operates at the application layer, the NR:
- Resolves DNS on behalf of the client (the client sends hostnames, not IPs)
- Opens individual TCP connections per SOCKS request
- Can enforce allow/deny lists on destination hosts and ports
- Sees the destination hostname and port, but not the contents if TLS is used

**Used by:** the [SDK's SOCKS client](/developers/rust/mixnet), [standalone SOCKS5 client](/developers/clients/socks5), and [mixFetch](/developers/typescript#mixfetch) (which wraps SOCKS requests in a browser-friendly `fetch` API).

## IP Packet Router

The IP Packet Router operates at the IP layer. Instead of proxying individual connections, it allocates a virtual IP address to the client and routes raw IP packets between the client and the internet, functioning as a tunnel endpoint.

```text
Client → mixnet → Exit Gateway (IPR) → raw IP packets → destination
                                      ← raw IP packets ←
```

On connection, the IPR:
1. Allocates an IPv4/IPv6 address pair to the client
2. Accepts raw IP packets (TCP, UDP, or any IP protocol) from the client via the mixnet
3. Sends them to the internet from the gateway's own IP address
4. Routes response packets back through the mixnet to the client

Because it operates at the IP layer, the IPR:
- Does not resolve DNS; the client handles its own DNS (either via clearnet or by sending DNS queries as UDP packets through the tunnel)
- Handles any IP protocol, not just TCP: UDP, ICMP, etc.
- Sees raw IP packets, including destination IPs and ports
- Does not see contents if the client uses TLS or another encryption layer

In both services, traffic between the Exit Gateway and the destination travels as **normal internet traffic**. The mixnet protects sender anonymity (the destination sees the gateway's IP, not yours), but does not encrypt the final hop. Use TLS or another end-to-end encryption layer to protect payload confidentiality.

**Used by:** [NymVPN anonymous mode](/network/dvpn-mode/protocol) (5-hop mixnet routing to the IPR), and [`smolmix`](/developers/smolmix) (programmatic `TcpStream`/`UdpSocket` access to the IPR via the Rust SDK).

## Comparison

| | Network Requester | IP Packet Router |
|---|---|---|
| **Layer** | Application (SOCKS) | IP (raw packets) |
| **Protocols** | TCP only | TCP, UDP, any IP protocol |
| **DNS** | Resolved by the NR | Client resolves its own |
| **Client gets** | Proxied connections | An allocated IP address |
| **Connection model** | Per-request | Persistent tunnel |
| **Used by** | SDK SOCKS client, mixFetch | NymVPN (anonymous mode), smolmix |

## Trust model

Both services share the same fundamental trust property: **the Exit Gateway can see destinations but not senders.** The mixnet's layered encryption ensures that the Exit Gateway cannot determine who sent a given packet; it only knows where it's going.

Specifically, the Exit Gateway:
- **Can see:** destination IP/hostname, destination port, unencrypted payload content, traffic volume and timing at the exit hop
- **Cannot see:** the sender's IP address, the sender's Nym address, which Entry Gateway the traffic entered through
- **Cannot determine:** the linkage between different requests from the same sender (unless the payload itself contains identifying information)

The sender's identity is protected by the mixnet's 5-hop routing, Sphinx encryption, cover traffic, and packet mixing. The Exit Gateway is the last hop: it decrypts the final Sphinx layer and sees the destination, but the chain of Mix Nodes between Entry and Exit has destroyed any timing or ordering correlation.

---
title: Nym Network Reference
description: Technical specifications and protocol details for the Nym Network: addressing format, epoch timing, and the hop-by-hop acknowledgement system.
url: https://nym.com/docs/network/reference
---

# Reference

Technical specifications and protocol details that apply across the Nym Network regardless of mode.

## In this section

- [Addressing](/network/reference/addressing): the `identity.encryption@gateway` address format and how routing works
- [Epochs](/network/reference/epochs): time divisions in the network, reward distribution, and topology reshuffling
- [Acknowledgements](/network/reference/acks): the hop-by-hop packet delivery confirmation system

---
title: Nym Network Addressing
description: How Nym addresses work: the identity.encryption@gateway format, key components, routing mechanics, and privacy considerations for client addressing.
url: https://nym.com/docs/network/reference/addressing
---

# Addressing

All clients and nodes in the Nym Network have an address that uniquely identifies them for routing.

## Address format

A Nym address has three parts separated by dots and an @ symbol:

```
<user-identity-key>.<user-encryption-key>@<gateway-identity-key>
```

The **identity key** identifies the client for routing purposes and is derived from the client's Ed25519 keypair and base58-encoded for readability.

The **encryption key** is the public key used to encrypt the final layer of Sphinx packets destined for this client. Only the client holding the corresponding private key can decrypt messages addressed to them.

The **gateway key** identifies which Gateway holds messages for this client. When you connect, your client registers with a specific Entry Gateway, and that Gateway's identity becomes part of your address.

## Example

```
DguTcdkWWtDyUFLvQxRdcA8qZhardhE1ZXy1YCC7Zfmq.Dxreouj5RhQqMb3ZaAxgXFdGkmfbDKwk457FdeHGKmQQ@4kjgWmFU1tcGAZYRZR57yFuVAexjLbJ5M7jvo3X5Hkcf
```

## How routing works

When sending to a Nym address, the sender extracts the Gateway key and constructs a Sphinx packet with that Gateway as the final hop. The Gateway receives the packet, identifies the recipient by their identity key, and delivers the message (or stores it if the recipient is offline).

## Privacy considerations

The address reveals which Gateway you use and your public keys. It doesn't reveal your IP address or private keys. Multiple clients can use the same Gateway, so the Gateway key alone doesn't identify you.

For persistent identity across sessions, store your keypairs and re-register with the same Gateway. For ephemeral identity, generate new keys each session.

---
title: Epochs in the Nym Network
description: How epochs organize time in the Nym Network: reward distribution, topology reshuffling, SURB validity windows, and future automatic role assignment.
url: https://nym.com/docs/network/reference/epochs
---

# Epochs

Time in the Nym Network is organized into epochs: discrete periods during which certain network operations occur. The current epoch length is one hour.

## What happens at epoch boundaries

**Reward distribution** calculates performance metrics for each node and distributes NYM token rewards based on routing reliability and uptime, ensuring that nodes successfully forwarding packets earn more than those with poor performance.

**Topology rerandomization** shuffles the arrangement of nodes in each layer. This prevents long-term route prediction attacks and limits the damage from any compromised nodes. Nodes may also enter or leave the active set based on uptime monitoring and stake changes.

## Future changes

In upcoming releases, epochs will trigger automatic role assignment. Nodes will switch between Mix Node and Gateway roles based on network demand, without operators needing to manually configure roles.

## SURB validity

SURBs are tied to key rotation cycles. Node keys rotate on an odd/even schedule with a default validity of 24 epochs. A SURB remains usable for `(validity_epochs + 1) * epoch_duration`, roughly 25 hours at the current 1-hour epoch. After that, the routing keys it was built with are no longer accepted by the network. Clients automatically purge stale SURBs and request fresh ones.

## Querying epoch information

Current epoch data is available through Nyx blockchain queries and Nym API endpoints.

---
title: Packet Acknowledgements
description: How the Nym Network uses hop-by-hop acknowledgements and retransmission to ensure reliable packet delivery despite network congestion or node failures.
url: https://nym.com/docs/network/reference/acks
---

# Acknowledgements

The Nym Network uses acknowledgements to ensure reliable packet delivery. When a node receives a packet, it sends an ack back to the sender. If no ack arrives within a timeout, the packet is retransmitted.

## How it works

The sender transmits a packet and waits for acknowledgement. The receiver processes the packet and sends an ack. If the sender receives the ack, the packet is marked as delivered. If not, the sender retransmits.

This happens automatically at each hop. If a client sends 100 packets to a Gateway and only receives 95 acks, it retransmits the 5 missing packets. The same mechanism operates between all nodes in the route.

## Why it matters

Network conditions can cause packet loss: congestion, temporary failures, connectivity issues. Without acks and retransmission, lost packets would mean lost messages. The acknowledgement system ensures reliable delivery despite imperfect network conditions.

## Scope

Acknowledgements operate hop-by-hop between adjacent nodes. They confirm that packets reached the next hop, not that they reached the final destination. End-to-end delivery confirmation for anonymous communication is handled separately through [SURBs](/network/mixnet-mode/anonymous-replies).

## Implementation

This is handled entirely by the Nym binaries. Developers and operators don't need to implement or configure acknowledgements; the system handles packet loss transparently.

**Lewes Protocol:** The upcoming Lewes release will introduce changes to how acknowledgements are handled. The current hop-by-hop ACK mechanism described above may be revised as part of broader protocol improvements. Details will be documented here once the changes are finalised.

---
title: Licensing
url: https://nym.com/docs/network/licensing
---

# Licensing

As a general approach, licensing follows this pattern:

* [Nym Documentation](https://nym.com/docs) by [Nym Technologies](https://nym.com) is licensed under [CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) ![CC](/images/cc-icons/cc.svg) ![BY](/images/cc-icons/by.svg) ![NC](/images/cc-icons/nc.svg) ![SA](/images/cc-icons/sa.svg)

* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)

* Used libraries and different components are [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) or [MIT](https://mit-license.org/)

For accurate information, please check individual files.

---
title: Code of Conduct
url: https://nym.com/docs/network/coc
---

# Code of Conduct

We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.

Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all.

Please be kind and courteous. There’s no need to be mean or rude.

Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.

Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.

We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behaviour that excludes people in socially marginalized groups.

Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Rust moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.

Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.

---
title: Nym Developer Portal: SDKs & Tools
description: Developer documentation for building privacy-enhanced applications on the Nym mixnet. Covers Rust SDK, TypeScript SDK, blockchain interaction & CLI tools.
url: https://nym.com/docs/developers
---

# Developer Documentation

Build applications that protect user metadata using the Nym Mixnet. This section covers SDK integration, blockchain interaction, and developer tools.

## Where to start

**Choosing an integration approach:** read [Integrations](/developers/integrations) to understand the architectural trade-offs (native SDK vs proxy vs mixFetch), then pick your path:

- **[Rust SDK](/developers/rust):** full-featured SDK with message passing, `AsyncRead`/`AsyncWrite` streams, and client pooling. Start with the [Tour](/developers/rust/tour).
- **[`smolmix`](/developers/smolmix):** standalone crate providing `TcpStream` and `UdpSocket` over the Mixnet via a userspace IP stack. Drop-in compatible with `tokio-rustls`, `hyper`, `tungstenite`, and the rest of the async Rust ecosystem. Also serves as the core for companion crates that plug into specific frameworks (e.g. hyper connectors, DNS resolvers).
- **[TypeScript SDK](/developers/typescript):** browser and Node.js SDK for mixFetch, Mixnet client, and smart contract interaction.
- **[Standalone Clients](/developers/clients):** language-agnostic SOCKS5 and WebSocket proxies for piping traffic through the Mixnet without an SDK.

## Blockchain interaction

The Nym Network is coordinated by the [Nyx blockchain](/network/infrastructure/nyx). To query chain state, submit transactions, or interact with smart contracts, see [Chain Interaction](/developers/chain).

## API reference

Auto-generated API specs for Nym infrastructure endpoints are in the [APIs section](/apis/introduction).

---
title: Nym Developer Portal: SDKs & Tools
description: Developer documentation for building privacy-enhanced applications on the Nym mixnet. Covers Rust SDK, TypeScript SDK, blockchain interaction & CLI tools.
url: https://nym.com/docs/developers
---

# Developer Documentation

Build applications that protect user metadata using the Nym Mixnet. This section covers SDK integration, blockchain interaction, and developer tools.

## Where to start

**Choosing an integration approach:** read [Integrations](/developers/integrations) to understand the architectural trade-offs (native SDK vs proxy vs mixFetch), then pick your path:

- **[Rust SDK](/developers/rust):** full-featured SDK with message passing, `AsyncRead`/`AsyncWrite` streams, and client pooling. Start with the [Tour](/developers/rust/tour).
- **[`smolmix`](/developers/smolmix):** standalone crate providing `TcpStream` and `UdpSocket` over the Mixnet via a userspace IP stack. Drop-in compatible with `tokio-rustls`, `hyper`, `tungstenite`, and the rest of the async Rust ecosystem. Also serves as the core for companion crates that plug into specific frameworks (e.g. hyper connectors, DNS resolvers).
- **[TypeScript SDK](/developers/typescript):** browser and Node.js SDK for mixFetch, Mixnet client, and smart contract interaction.
- **[Standalone Clients](/developers/clients):** language-agnostic SOCKS5 and WebSocket proxies for piping traffic through the Mixnet without an SDK.

## Blockchain interaction

The Nym Network is coordinated by the [Nyx blockchain](/network/infrastructure/nyx). To query chain state, submit transactions, or interact with smart contracts, see [Chain Interaction](/developers/chain).

## API reference

Auto-generated API specs for Nym infrastructure endpoints are in the [APIs section](/apis/introduction).

---
title: Integrating With Nym
description: Choose an integration path for sending application traffic through the Nym mixnet, depending on your runtime environment and architecture.
url: https://nym.com/docs/developers/integrations
---

# Integrating With Nym

Any application that integrates with Nym sends its traffic through the Mixnet via a Nym client. The right integration path depends on two factors: **environment** and **architecture**.

## Environment

Different runtimes have different transport constraints: a browser cannot open raw sockets or access the filesystem, while a desktop app can.

- **Native / Desktop**: full access to system networking and persistent storage. Use the [Rust SDK](/developers/rust) or [`smolmix`](/developers/smolmix).
- **Browser**: restricted to WebSockets, Web Transport, and `fetch`, with HTTPS-only mixed content rules and no filesystem access. Use the [TypeScript SDK](/developers/typescript).

## Architecture

The second factor is whether you control both sides of the communication.

**End-to-end (E2E)**: both sides run Nym clients. All traffic stays Sphinx-encrypted the entire way. Appropriate for peer-to-peer setups or any case where you control both endpoints.

**Proxy**: only the client side runs Nym. Traffic exits the Mixnet at an Exit Gateway and continues to the destination as normal internet traffic. Appropriate when connecting to third-party services (blockchain RPCs, external APIs) that you do not control. For Rust, [`smolmix`](/developers/smolmix) provides `TcpStream` and `UdpSocket` types that work as drop-in replacements for their tokio equivalents.

In proxy mode, the last hop from Exit Gateway to the remote host travels as standard internet traffic. This is weaker than E2E against a global passive adversary, but still provides timing obfuscation and sender-receiver unlinkability.

See the [Native / Desktop](/developers/native) and [Browser](/developers/browsers) pages for the specific modules available in each environment.

---
title: Native and Desktop App Integration
description: Integrate privacy into native desktop apps and CLIs using the Nym Rust SDK. Choose between end-to-end mixnet messaging or TCP proxy approaches.
url: https://nym.com/docs/developers/native
---

# Native / Desktop Apps

Desktop apps and CLIs integrate with two broad approaches: embedding Nym clients on both sides of the communication (E2E), or using the Mixnet as a proxy to reach external services.

## Mixnet End-To-End
Both sides of your app run Nym clients. All traffic stays Sphinx-encrypted the entire way. Works for peer-to-peer setups or any case where you control both ends.

![](/images/developers/nym-arch-client-to-client.png)

| SDK Module | What it does | Status | Links |
|---|---|---|---|
| **Stream** | `AsyncRead + AsyncWrite` byte streams multiplexed over the mixnet, the closest analogue to TCP sockets | Recommended | [docs](/developers/rust/stream) · [tutorial](/developers/rust/stream/tutorial) |
| **Mixnet** | Raw message API and `MixnetClient` for full control over the communication model | Stable | [docs](/developers/rust/mixnet) · [tutorial](/developers/rust/mixnet/tutorial) |
| **Client Pool** | Pre-connected client pool for bursty workloads | Stable | [docs](/developers/rust/client-pool) |
| **TcpProxy** | Localhost TCP sockets that proxy traffic through the mixnet | Unmaintained | [docs](/developers/rust/tcpproxy) |

**TcpProxy is unmaintained.** Use the [Stream module](/developers/rust/stream) for new projects.

## Mixnet-As-Proxy
For cases where you only control the client side and need to reach a third-party service such as a blockchain RPC or remote API.

![](/images/developers/nym-arch-ip-routing.png)

Traffic is Sphinx-encrypted until the Exit Gateway, where it's unwrapped into HTTPS ([Network Requester](/network/infrastructure/exit-services#network-requester)) or raw IP ([IP Packet Router](/network/infrastructure/exit-services#ip-packet-router)). The last hop to the remote host **travels as normal internet traffic**. Use TLS or another encryption layer to protect the final hop.

| Standalone Crate | What it does | Links |
|---|---|---|
| **`smolmix`** | Userspace IP tunnel providing `TcpStream` and `UdpSocket` over the mixnet, compatible with the entire async Rust ecosystem. Also serves as the core for companion crates that plug into specific frameworks (e.g. hyper connectors, DNS resolvers) | [docs](/developers/smolmix) |

| SDK Module | What it does | Links |
|---|---|---|
| **SOCKS Client** | SOCKS4/4a/5 proxy via the Exit Gateway's Network Requester. Works with any SOCKS-capable application without code changes, just point it at the local proxy | [docs](/developers/rust/mixnet) |

---
title: Browser-Based App Integration
description: Build privacy-preserving browser apps with mixFetch and the Nym WASM SDK. Route HTTP requests and messages through the mixnet from the browser.
url: https://nym.com/docs/developers/browsers
---

# Browser-Based Apps

Browsers are a restricted environment: communication is limited to WebSockets, Web Transport, and WebRTC; mixed content policies enforce HTTPS-only; and there is no access to the filesystem or system calls. The main obstacle for routing traffic through the Mixnet is the lack of access to browser TLS negotiation or the CA certificate store from JavaScript.

Two integration options are available, both delivered as packages bundled into your web application.

![](/images/developers/nym-browser-arch.png)

| Module | What it does | Links |
|---|---|---|
| **mixFetch** | Drop-in `fetch` replacement. Routes HTTP(S) requests via Exit Gateways with an embedded CA store for browser-to-destination TLS over the Mixnet | [docs](/developers/typescript#mixfetch) · [example](/developers/typescript/playground/mixfetch) |
| **WASM Client** | Sphinx packets and cover traffic in WASM, sent over WebSocket to the Entry Gateway. Messaging mode only (text/binary payloads), runs in a web worker | [docs](/developers/typescript#mixnet-client) · [example](/developers/typescript/playground/traffic) |

`mixFetch` currently supports a maximum of 10 concurrent in-flight requests. `mixFetchv2`, which will function as a general-purpose userspace IP stack, is in development.

The WASM Client does not support IP packet routing (IPR) or stream-like APIs. For HTTP(S) requests from the browser, use `mixFetch`. Standard browser CSP and mixed content restrictions (HTTPS only) apply to the WebSocket connection.

---
title: Nym Client Message Queue and Cover Traffic
description: How the Nym client queues messages, sends cover traffic via Poisson processes, and manages Sphinx packet streams to prevent timing attacks.
url: https://nym.com/docs/developers/concepts/message-queue
---

# Message Queue

    Although useful for understanding how the Nym Client works internally, this information is only of practical use if you are using the [`Mixnet`](/developers/rust/mixnet) module of the Rust SDK and interacting with the client at a low level. Most of this is abstracted away by the [`Stream`](/developers/rust/stream) module (`AsyncRead + AsyncWrite` channels) and the [`TcpProxy`](/developers/rust/tcpproxy) module (TCP tunnelling with message ordering).

## Sphinx Packet Streams
Clients, once connected to the Mixnet, **are always sending traffic into the Mixnet**; as well as the packets that you as a developer are sending from your application logic, they send [cover traffic](/network/mixnet-mode/cover-traffic) at a constant rate defined by a Poisson process. This is part of the network's mitigation of timing attacks.

There are two constant streams of sphinx packets leaving the client at the rate defined by the Poisson process.
- one that is solely cover traffic
- one that sends a mixture of cover and 'real' traffic

```mermaid
---
config:
  theme: neo-dark
  layout: elk

title: Cover Traffic Stream
---
sequenceDiagram
    box Local Machine
        participant App Logic
        participant Nym Client
    end
    participant Entry Gateway

    loop Cover Traffic Stream
        Nym Client->>Nym Client: Delay
        Nym Client->>Entry Gateway: Cover traffic
    end

```

```mermaid
---
config:
  theme: neo-dark
  layout: elk

title: Mixed Stream
---
sequenceDiagram
    box Local Machine
        participant App Logic
        participant Nym Client
    end
    participant Entry Gateway

    loop Cover + Real Traffic Stream
        Nym Client->>Nym Client: Check internal queue + delay
        Nym Client->>Entry Gateway: Cover traffic
        alt Packets with App Payload
            App Logic-->>Nym Client: Send(bytes): add to internal queue
            Nym Client->>Nym Client: Check internal queue: bytes to send
            Nym Client->>Nym Client: Encrypt & packetise bytes
            Nym Client->>Entry Gateway: Real Packets
            Nym Client->>Nym Client: Check internal queue: bytes to send
            Nym Client->>Nym Client: Encrypt & packetise bytes
            Nym Client->>Entry Gateway: Real Packets
            Nym Client->>Nym Client: Check internal queue: queue empty
        end
        Nym Client->>Nym Client: Delay
        Nym Client->>Entry Gateway: Cover traffic
    end
```

> Since Sphinx packets are indistinguishable to an external observer, the only difference between 'real' and cover traffic is whether the payload is empty or not. This can be only known to the eventual receiver of the packet.

## What does `send()` do then?

When passing a message to a client (however you do it, either piping messages from an app to a standalone client or via one of the `send` functions exposed by the SDKs), you are **putting that message into the queue** to be source encrypted and sent in the future, in order to ensure that traffic leaving the client does so in a manner that to an external observer is uniform / does not create any 'burst' or change in traffic timings that could aid traffic analysis.

## Note on Client Shutdown
Accidentally dropping a client before your message has been sent is something that is possible and should be avoided (see the [troubleshooting guide](/developers/rust/mixnet/troubleshooting) for more on this) but is easy to avoid simply by remembering to:
- keep your client process alive, even if you are not expecting a reply to your message
- (in the case of the SDKs) properly disconnecting your client in order to make sure that the message queue is flushed of Sphinx packets with actual payloads.

---
title: smolmix: TCP/UDP Over the Nym Mixnet
description: A userspace IP tunnel that provides standard TcpStream and UdpSocket types over the Nym mixnet. Drop-in compatible with async tokio Rust ecosystem.
url: https://nym.com/docs/developers/smolmix
---

# smolmix

`smolmix` is a TCP/UDP tunnel over the Nym mixnet. It uses a userspace network stack [`smoltcp`](https://docs.rs/smoltcp/latest/smoltcp/) to provide `TcpStream` and `UdpSocket` types that work with the async [`tokio`](https://docs.rs/tokio) Rust ecosystem e.g. [`tokio-rustls`](https://docs.rs/tokio-rustls), [`hyper`](https://docs.rs/hyper), [`tokio-tungstenite`](https://docs.rs/tokio-tungstenite), etc.

The `TcpStream` type implements tokio's `AsyncRead`/`AsyncWrite` traits and `UdpSocket` provides `send_to`/`recv_from` for datagrams.

```text
┌──────────────────────────────────────────────────────────────┐
│  Your application (TLS, HTTP, WebSocket, DNS, etc.)          │
│       └─ smolmix::TcpStream / UdpSocket                      │
│            └─ smoltcp (userspace TCP/IP)                     │
│                 └─ Nym mixnet → IPR exit gateway → internet  │
└──────────────────────────────────────────────────────────────┘
```

Traffic exits the mixnet at an [IPR (Internet Packet Router)](/network/infrastructure/exit-services#ip-packet-router) exit gateway. The exit IP is the gateway's, not yours.

## Runtime and platform support
### Other runtimes
`smolmix` currently requires `tokio`. The internal pipeline is tokio-based: the bridge task that shuttles packets to the mixnet, the Nym SDK's `MixnetClient`, and the [`tokio-smoltcp`](https://docs.rs/tokio-smoltcp) reactor that drives the userspace TCP/IP stack all run on the tokio runtime.

This means `smolmix` is not compatible with alternative async runtimes like [`smol`](https://docs.rs/smol) or [`async-std`](https://docs.rs/async-std) out of the box. If you need to use `smolmix` from another runtime, the [`async-compat`](https://docs.rs/async-compat) crate can bridge the gap.

### Non-native `smolmix`
A WASM version of `smolmix` is planned for a future release.

## Installation

Add `smolmix` to your `Cargo.toml`:

```toml
[dependencies]
smolmix = "1.21.0"
nym-bin-common = { version = "1.21.0", features = ["basic_tracing"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

`tokio` is a transitive dependency of smolmix, but you need to enable `rt-multi-thread` (smolmix spawns multiple tasks internally) and `macros` (for `#[tokio::main]`).

`nym-bin-common` is optional but recommended: it sets up [`tracing`](https://docs.rs/tracing) logging so you can see mixnet connection progress.

**Minimum Rust version:** {RUST_MSRV}+

### From Git

For unreleased changes, import directly from the repository:

```toml
smolmix = { git = "https://github.com/nymtech/nym", branch = "develop" }
```

## When to use smolmix

| | smolmix | Stream module | mixFetch | SOCKS client |
|---|---|---|---|---|
| **Layer** | Transport (TCP/UDP) | Message (multiplexed streams) | HTTP | TCP (SOCKS proxy) |
| **Controls both sides?** | No (proxy mode) | Yes (E2E) | No (proxy mode) | No (proxy mode) |
| **API** | `TcpStream`, `UdpSocket` | `AsyncRead + AsyncWrite` | `fetch()` drop-in | SOCKS4/5 protocol |
| **Composability** | Full: TLS, HTTP, WebSocket, DNS, etc. stack on top | Byte streams only | HTTP(S) only | Application-dependent |
| **Best for** | Reaching external services from Rust with standard networking | Peer-to-peer / E2E protocols between Nym clients | Browser HTTP requests | Legacy apps with SOCKS support |

## Security model

Traffic is Sphinx-encrypted inside the mixnet, but between the exit gateway and the remote host it travels as **normal internet traffic**. Always encrypt the final hop with TLS ([`rustls`](https://docs.rs/rustls)), Noise Protocol ([`snow`](https://docs.rs/snow)), etc.

### What's protected

| Segment | Mixnet encryption | What's visible |
|---|---|---|
| Your machine → mixnet entry | Sphinx (layered) | Entry gateway sees your IP but not the destination |
| Inside the mixnet (entry + 3 mix layers + exit) | Sphinx (layered) | Each node only knows prev/next hop |
| Exit gateway (IPR) | Sphinx removed, raw IP packet exposed | IPR sees destination IP + port. Payload depends on your application layer (see below). |
| IPR → remote host | None (Sphinx is mixnet-only) | Remote host sees IPR's IP, not yours |

The Sphinx encryption is the **mixnet transport layer**: it protects packets as they traverse the mix nodes. At the exit gateway, the Sphinx layers are stripped and the original IP packet is forwarded to the destination. This is analogous to how a Tor exit node or VPN endpoint unwraps its tunnel.

**What's inside that IP packet is entirely up to you.** If you connect with TLS (as in the [TCP example](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/tcp.rs)), the IPR sees encrypted TLS ciphertext going to a destination IP: it knows *where* but not *what*. If you send plaintext HTTP, the IPR can read the full request and response.

### Trust boundaries

- **You trust the mixnet** to provide unlinkability between sender and receiver. This is enforced cryptographically by the Sphinx packet format and mixing.
- **You trust the IPR exit gateway** in the same way you trust a VPN exit or Tor exit node: it can inspect your raw IP packets. The difference is that the IPR doesn't know *who* is sending the traffic (the mixnet hides your identity).
- **Application-layer encryption closes the gap.** TLS, Noise Protocol, or any authenticated encryption ensures the IPR only sees ciphertext. It can see destination IP and port, but not payload content.

### Comparison with other privacy tools

| | smolmix | Tor | VPN |
|---|---|---|---|
| **Exit node sees traffic?** | Yes (encrypt it) | Yes (encrypt it) | Yes (encrypt it) |
| **Exit node knows sender?** | No (mixnet hides identity) | No (onion routing) | Yes (VPN provider knows) |
| **Timing analysis resistance** | Strong (mixing, cover traffic) | Weak (low-latency) | None |
| **UDP support** | Yes | No (TCP only) | Yes |

## Examples

Runnable examples in [`smolmix/core/examples/`](https://github.com/nymtech/nym/tree/develop/smolmix/core/examples). Each is self-contained; read the `//!` doc comments at the top of each file for a walkthrough.

```sh
cargo run -p smolmix --example <name>
```

All examples accept `--ipr <ADDRESS>` to target a specific exit node (pass a `Recipient` address to `Tunnel::builder().ipr_address()`).

| Example | Source | What it demonstrates |
|---|---|---|
| UDP | [`udp.rs`](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/udp.rs) | DNS lookup via [`hickory-proto`](https://docs.rs/hickory-proto), sending a raw UDP query to `1.1.1.1:53` through the mixnet |
| TCP | [`tcp.rs`](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/tcp.rs) | HTTPS request via [`hyper`](https://docs.rs/hyper) + [`tokio-rustls`](https://docs.rs/tokio-rustls). Fetches Cloudflare's `/cdn-cgi/trace` to show that the exit IP differs from clearnet |
| WebSocket | [`websocket.rs`](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/websocket.rs) | WebSocket echo via [`tokio-tungstenite`](https://docs.rs/tokio-tungstenite) + [`tokio-rustls`](https://docs.rs/tokio-rustls). Full TCP → TLS → WebSocket stack composing over smolmix |
| UDP multi | [`udp_multi.rs`](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/udp_multi.rs) | Multiple DNS lookups with timeout handling + NTP time sync, all over mixnet UDP |
| TCP download | [`tcp_download.rs`](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/tcp_download.rs) | DNS-over-mixnet + multi-request HTTP/1.1 download over a single keep-alive connection, the full real-world pattern |
| WebSocket multi | [`websocket_multi.rs`](https://github.com/nymtech/nym/blob/develop/smolmix/core/examples/websocket_multi.rs) | Burst echo (varying message sizes) + idle survival probes with clearnet baseline. Sustained multi-message WebSocket usage over the mixnet |

## Architecture

The internal stack (smoltcp reactor, device adapter, bridge task, packet flow) is documented in [`ARCHITECTURE.md`](https://github.com/nymtech/nym/blob/develop/smolmix/core/src/ARCHITECTURE.md). This is also the crate-level documentation on docs.rs.

## API reference

Full API documentation is available on [docs.rs/smolmix](https://docs.rs/smolmix).

---
title: Nym Rust SDK: Privacy Apps for the Mixnet
description: Rust SDK reference for building privacy applications on the Nym mixnet. Covers the Mixnet client, Stream multiplexing, Client Pool, and code examples.
url: https://nym.com/docs/developers/rust
---

# Rust SDK

All modules share a common `MixnetClient` that manages gateway connections, Sphinx packet encryption, routing, and cover traffic.

Full API reference: [**docs.rs/nym-sdk**](https://docs.rs/nym-sdk/latest/nym_sdk/)

For an overview of what the SDK can do, see the **[Tour](./rust/tour)**. For setup instructions, see [Installation](./rust/importing).

## Modules

- **[Stream](./rust/stream)**: multiplexed `AsyncRead + AsyncWrite` byte streams over the Mixnet. **If you're used to TCP sockets, start here.**

- **[Mixnet](./rust/mixnet)**: raw message payloads, independently routed, no connections or ordering. Use this when you want full control over the communication model.

- **[Client Pool](./rust/client-pool)**: keeps ready-to-use `MixnetClient` instances warm for bursty workloads.

- **[TcpProxy](./rust/tcpproxy)** *(deprecated)*: TCP socket proxying with session management and message ordering. Use Stream for new projects.

- **[FFI](./rust/ffi)**: Go and C/C++ bindings.

---
title: Tour of the Rust SDK
url: https://nym.com/docs/developers/rust/tour
---

# Tour of the Rust SDK

A quick walkthrough of the most important things you can do with `nym-sdk`. Each section shows working code and links to the module that covers it in depth.

**The Mixnet is not like regular internet networking**: there are no persistent connections, no guaranteed message ordering, and no TCP underneath. At its core, the Mixnet is a message-based anonymity network: you send individual payloads that are Sphinx-encrypted, mixed through multiple nodes, and independently reconstructed at the destination.

The raw [message API](./mixnet) therefore works differently from what most developers expect. The [Stream module](./stream) bridges this gap by providing `AsyncRead + AsyncWrite` byte streams on top of the Mixnet. If you are coming from socket-based networking, start with streams.

## Send a raw message payload

The message API gives you direct access to the Mixnet's native communication model: individually addressed payloads with no connections and no ordering guarantees. This is useful when you want full control, but it's not how most networking code works:

```rust
use nym_sdk::mixnet::{self, MixnetMessageSender};

#[tokio::main]
async fn main() {
    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    let addr = *client.nym_address();
    println!("Connected: {addr}");

    // Send a message to ourselves
    client
        .send_plain_message(addr, "hello mixnet!")
        .await
        .unwrap();

    // Receive it (filter empty SURB management messages)
    if let Some(msgs) = client.wait_for_messages().await {
        for msg in msgs.iter().filter(|m| !m.message.is_empty()) {
            println!("Got: {}", String::from_utf8_lossy(&msg.message));
        }
    }

    // Always disconnect for clean shutdown
    client.disconnect().await;
}
```

The message is Sphinx-encrypted, mixed across 5 nodes, and reconstructed on arrival. The whole round trip takes a few seconds.

Next: [Mixnet module](./mixnet) | [Tutorial: Send Your First Private Message](./mixnet/tutorial)

## Reply anonymously with SURBs

Every received message carries a `sender_tag`, an opaque token that lets you reply **without knowing the sender's Nym address**. Replies travel back through pre-built Single Use Reply Blocks (SURBs):

```rust
// After receiving a message...
let tag = received_msg.sender_tag.expect("message includes sender tag");
client.send_reply(tag, "anonymous reply!").await.unwrap();
```

The replying side never learns where the reply is going, enabling anonymous communication without mutual identity disclosure.

## Open a bidirectional stream

If you're used to working with TCP sockets, this is where you'll feel at home. The [Stream module](./stream) provides persistent, bidirectional byte channels that implement tokio's `AsyncRead + AsyncWrite`, so any code that works with sockets works with `MixnetStream`:

```rust
use nym_sdk::mixnet;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() {
    let mut sender = mixnet::MixnetClient::connect_new().await.unwrap();
    let mut receiver = mixnet::MixnetClient::connect_new().await.unwrap();
    let recv_addr = *receiver.nym_address();

    // Receiver creates a listener (activates stream mode)
    let mut listener = receiver.listener().unwrap();

    // Sender opens a stream to the receiver
    let mut out = sender.open_stream(recv_addr, None).await.unwrap();

    // Receiver accepts it
    let mut inc = listener.accept().await.unwrap();

    // Standard tokio I/O: write, flush, read
    out.write_all(b"hello stream").await.unwrap();
    out.flush().await.unwrap();

    let mut buf = vec![0u8; 1024];
    let n = inc.read(&mut buf).await.unwrap();
    println!("{}", String::from_utf8_lossy(&buf[..n]));

    drop(out);
    drop(inc);
    sender.disconnect().await;
    receiver.disconnect().await;
}
```

Activating stream mode (by calling `listener()` or `open_stream()`) disables message-based methods like `send_plain_message()` and `wait_for_messages()`. A single client operates in one mode at a time.

Next: [Stream module](./stream) | [Tutorial: Build a Private Echo Server](./stream/tutorial)

## Use a client pool for bursty traffic

Creating a `MixnetClient` takes several seconds (gateway handshake, key generation, topology fetch). The [Client Pool](./client-pool) pre-creates clients in the background so they're ready when you need them:

```rust
use nym_sdk::client_pool::ClientPool;

#[tokio::main]
async fn main() {
    let pool = ClientPool::new(3); // maintain 3 clients in reserve
    let bg = pool.clone();
    tokio::spawn(async move { bg.start().await });

    // Wait for pool to fill, then grab a ready client
    tokio::time::sleep(std::time::Duration::from_secs(15)).await;

    if let Some(client) = pool.get_mixnet_client().await {
        println!("Got client: {}", client.nym_address());
        client.disconnect().await;
    }

    pool.disconnect_pool().await;
}
```

Clients are consumed, not returned; the pool creates replacements automatically.

Next: [Client Pool module](./client-pool) | [Tutorial: Handle Bursty Traffic](./client-pool/tutorial)

## Persist your identity

By default, `connect_new()` creates ephemeral keys that are discarded on disconnect. To keep the same Nym address across restarts, use the builder with on-disk storage:

```rust
use nym_sdk::mixnet::{MixnetClientBuilder, StoragePaths};
use std::path::PathBuf;

let storage = StoragePaths::new_from_dir(
    &PathBuf::from("/tmp/my-nym-client")
).unwrap();

let client = MixnetClientBuilder::new_with_default_storage(storage)
    .await
    .unwrap()
    .build()
    .unwrap()
    .connect_to_mixnet()
    .await
    .unwrap();

// This address is the same every time you run with the same path
println!("Persistent address: {}", client.nym_address());
```

## Where to go next

- [Installation](./importing): add `nym-sdk` to your project
- [Mixnet Tutorial](./mixnet/tutorial): send, receive, and reply with SURBs
- [Stream Tutorial](./stream/tutorial): build a private echo server
- [Client Pool Tutorial](./client-pool/tutorial): handle bursty traffic
- [API Reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/): type details, method signatures, architecture docs

---
title: Install the Nym Rust SDK
description: Add nym-sdk to your Rust project from Git or crates.io. Covers version requirements, minimum Rust version, and current feature gate status.
url: https://nym.com/docs/developers/rust/importing
---

# Installation

```toml
[dependencies]
nym-sdk = "1.21.0"
```

**Minimum Rust version:** {RUST_MSRV}+

### From Git

You can also import directly from Git if you want unreleased changes:

```toml
# development branch (latest changes, may be unstable)
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "develop" }

# latest stable release
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
```

**No feature gates yet.** Importing `nym-sdk` pulls in everything (mixnet, tcp_proxy, client_pool, etc.) and their full dependency trees. Cargo feature flags are planned.

---
title: Nym Rust SDK: Mixnet Messaging Module
description: Use the Nym Rust SDK Mixnet module to send messages through the mixnet. Covers builder patterns, custom topologies, SOCKS proxy, and anonymous replies.
url: https://nym.com/docs/developers/rust/mixnet
---

# Mixnet Module

The `mixnet` module is the core of the Nym SDK. It provides [`MixnetClient`](https://docs.rs/nym-sdk/latest/nym_sdk/mixnet/struct.MixnetClient.html) for connecting to the Nym Mixnet, sending messages through Sphinx packet encryption and 5-hop routing, and receiving reconstructed messages on the other side.

Messages are individually routed through the Mixnet with no guaranteed ordering or persistent connections. If you want familiar socket-like I/O (`read`/`write`), use the [Stream module](./stream) instead. See the [Tour](./tour) for how the two approaches compare.

## Two operating modes

The client operates in one of two mutually exclusive modes:

**Message mode** (default): send and receive raw message payloads:
```rust
use nym_sdk::mixnet::{self, MixnetMessageSender};

let mut client = mixnet::MixnetClient::connect_new().await.unwrap();

// Send a message
client.send_plain_message(*client.nym_address(), "hello").await.unwrap();

// Receive messages
if let Some(msgs) = client.wait_for_messages().await {
    for msg in msgs {
        println!("Got: {}", String::from_utf8_lossy(&msg.message));
    }
}

client.disconnect().await;
```

**Stream mode:** persistent `AsyncRead + AsyncWrite` channels. See the [Stream module](./stream) for details.

Stream mode is activated by calling `open_stream()` or `listener()`. Once active, message-mode methods return `Error::StreamModeActive`. This is a one-way transition.

## API reference

- [API reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/mixnet/): full architecture documentation, all types, builder methods, traits, and configuration options
- [Examples on GitHub](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples): runnable examples covering simple send/receive, builder patterns, custom topologies, SOCKS proxy, anonymous replies, and more

Run any example with:
```sh
cargo run --example <example_name>
```

## Next steps

- [Tutorial: Send your first private message](./mixnet/tutorial): step-by-step guide covering sending, receiving, SURBs, and persistent identity
- [Troubleshooting](./mixnet/troubleshooting): common issues with logging, empty messages, and client lifecycle
- [Stream module](./stream): if you need persistent bidirectional byte channels

---
title: Mixnet Tutorial: Send Your First Private Message
description: Step-by-step Rust tutorial to connect to the Nym mixnet, send and receive messages, reply anonymously with SURBs, and persist client identity.
url: https://nym.com/docs/developers/rust/mixnet/tutorial
---

# Tutorial: Send Your First Private Message

By the end of this tutorial you'll have a working program that sends a Sphinx-encrypted message to itself through the Nym Mixnet, receives it, and replies anonymously using SURBs. The later sections cover persistent identity and concurrent send/receive.

**You'll need:** Rust {RUST_MSRV}+ and an internet connection (clients connect to the live Mixnet).

## Step 1: Set up the project

```sh
cargo init nym-mixnet-demo
cd nym-mixnet-demo
```

Add dependencies to `Cargo.toml`:

```toml
[dependencies]
nym-sdk = "1.21.0"
nym-bin-common = { version = "1.21.0", features = ["basic_tracing"] }
tokio = { version = "1", features = ["full"] }
```

## Step 2: Connect and send

Replace the contents of `src/main.rs`:

```rust
use nym_sdk::mixnet::{self, MixnetMessageSender};

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    // connect_new() creates an ephemeral client: keys are generated in
    // memory and discarded on disconnect.
    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    let our_address = client.nym_address();
    println!("Connected: {our_address}");

    // The message is Sphinx-encrypted and mixed across 5 nodes.
    // send_plain_message only blocks until the message is queued;
    // encryption and mixing happen in background tasks.
    client
        .send_plain_message(*our_address, "hello from the mixnet!")
        .await
        .unwrap();

    println!("Sent, waiting for arrival...");
```

`setup_tracing_logger()` shows what the SDK is doing under the hood: gateway connections, topology fetches, Sphinx packet encryption. If the output is too verbose, comment out the line or filter with `RUST_LOG=warn cargo run`.

## Step 3: Receive

```rust
    // wait_for_messages() returns the next batch of incoming messages.
    // Filter empty messages: these are SURB replenishment requests.
    let message = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };

    println!("Received: {}", String::from_utf8_lossy(&message.message));
```

## Step 4: Reply anonymously

Every message includes a `sender_tag`, an opaque `AnonymousSenderTag` that lets you reply **without knowing the sender's address**. The SDK bundles SURBs (Single Use Reply Blocks) with every outgoing message by default:

```rust
    let sender_tag = message.sender_tag.expect("should have sender tag");

    // send_reply uses the SURB: the sender's address is never revealed.
    client.send_reply(sender_tag, "hello back, anonymously!").await.unwrap();

    let reply = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };

    println!("Reply: {}", String::from_utf8_lossy(&reply.message));

    client.disconnect().await;
}
```

## Step 5: Run it

```sh
RUST_LOG=info cargo run
```

```
Connected: 8gk4Y...@2xU4d...
Sent, waiting for arrival...
Received: hello from the mixnet!
Reply: hello back, anonymously!
```

## Going further: persist your identity

The ephemeral client above generates a new address on every run. To keep the same address across restarts, use `MixnetClientBuilder` with on-disk storage:

```rust
use nym_sdk::mixnet::{self, MixnetMessageSender, StoragePaths};

#[tokio::main]
async fn main() {
    // Keys are generated on first run, then loaded from disk on subsequent runs.
    let paths = StoragePaths::new_from_dir("./my-client-data").unwrap();

    let mut client = mixnet::MixnetClientBuilder::new_with_default_storage(paths)
        .await
        .unwrap()
        .build()
        .unwrap()
        .connect_to_mixnet()
        .await
        .unwrap();

    let our_address = client.nym_address();
    println!("Address: {our_address}");

    // Same API as before: send, receive, SURB reply.
    client
        .send_plain_message(*our_address, "hello from persistent client!")
        .await
        .unwrap();
    println!("Sent, waiting for arrival...");

    let message = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };
    println!("Received: {}", String::from_utf8_lossy(&message.message));

    let sender_tag = message.sender_tag.expect("should have sender tag");
    client.send_reply(sender_tag, "anonymous reply!").await.unwrap();

    let reply = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };
    println!("Reply: {}", String::from_utf8_lossy(&reply.message));

    // Always disconnect for clean shutdown: background tasks need to be
    // stopped and state files flushed.
    client.disconnect().await;
}
```

Run it twice; the address stays the same.

## Going further: send and receive from different tasks

Add `futures` to your `Cargo.toml`:

```toml
futures = "0.3"
```

Use `split_sender()` to get a clone-able send handle for use in separate tasks:

```rust
use futures::StreamExt;
use nym_sdk::mixnet::{self, MixnetMessageSender};

#[tokio::main]
async fn main() {
    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    let addr = *client.nym_address();

    // split_sender() returns a clone-able MixnetClientSender.
    let sender = client.split_sender();

    // Spawn a receiver: the original client implements futures::Stream.
    let rx = tokio::spawn(async move {
        if let Some(msg) = client.next().await {
            println!("Received: {}", String::from_utf8_lossy(&msg.message));
        }
        client.disconnect().await;
    });

    // Spawn a sender on a different task.
    let tx = tokio::spawn(async move {
        sender.send_plain_message(addr, "hello from another task!").await.unwrap();
    });

    tx.await.unwrap();
    rx.await.unwrap();
}
```

## What's happening underneath

`connect_new()` generates an ephemeral identity (ed25519 + x25519 keypair), fetches the current network topology, selects a gateway, and opens a persistent WebSocket connection. `send_plain_message()` wraps the payload in Sphinx packets, layered encryption where each of the 5 Mix Nodes can only decrypt one layer and learn the next hop, never the full route. `wait_for_messages()` drains a local queue fed by the gateway; messages arrive out of order by design, to defeat timing analysis.

SURBs (Single Use Reply Blocks) are pre-computed return routes bundled with each outgoing message. The recipient uses them to reply without learning the sender's address. Each is single-use; the SDK replenishes them automatically.

`split_sender()` clones the send channel while the original client retains the receive side. Both halves can run on separate tokio tasks without synchronization.

## Complete code

### Ephemeral client

New address on every run, good for quick experiments:

```rust
use nym_sdk::mixnet::{self, MixnetMessageSender};

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    let our_address = client.nym_address();
    println!("Connected: {our_address}");

    client
        .send_plain_message(*our_address, "hello from the mixnet!")
        .await
        .unwrap();
    println!("Sent, waiting for arrival...");

    let message = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };
    println!("Received: {}", String::from_utf8_lossy(&message.message));

    let sender_tag = message.sender_tag.expect("should have sender tag");
    client.send_reply(sender_tag, "hello back, anonymously!").await.unwrap();

    let reply = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };
    println!("Reply: {}", String::from_utf8_lossy(&reply.message));

    client.disconnect().await;
}
```

### Persistent identity

Same address across restarts. Use this for real applications:

```rust
use nym_sdk::mixnet::{self, MixnetMessageSender, StoragePaths};

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    let paths = StoragePaths::new_from_dir("./my-client-data").unwrap();

    let mut client = mixnet::MixnetClientBuilder::new_with_default_storage(paths)
        .await
        .unwrap()
        .build()
        .unwrap()
        .connect_to_mixnet()
        .await
        .unwrap();

    let our_address = client.nym_address();
    println!("Address: {our_address}");

    client
        .send_plain_message(*our_address, "hello from persistent client!")
        .await
        .unwrap();
    println!("Sent, waiting for arrival...");

    let message = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };
    println!("Received: {}", String::from_utf8_lossy(&message.message));

    let sender_tag = message.sender_tag.expect("should have sender tag");
    client.send_reply(sender_tag, "anonymous reply!").await.unwrap();

    let reply = loop {
        if let Some(msgs) = client.wait_for_messages().await {
            if let Some(msg) = msgs.into_iter().find(|m| !m.message.is_empty()) {
                break msg;
            }
        }
    };
    println!("Reply: {}", String::from_utf8_lossy(&reply.message));

    client.disconnect().await;
}
```

---
title: Mixnet Module Examples
description: Runnable Rust examples for the Nym mixnet module: sending messages, SURB anonymous replies, MixnetClientBuilder, persistent storage, and parallel send/receive.
url: https://nym.com/docs/developers/rust/mixnet/examples
---

# Examples

Runnable examples in [`sdk/rust/nym-sdk/examples/`](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples). Each file is self-contained with step-by-step comments.

```bash
cargo run --example <NAME>
```

| Example | Source | What it demonstrates |
|---|---|---|
| Simple | [`simple.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/simple.rs) | Send a message to yourself and print it |
| SURB Reply | [`surb_reply.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/surb_reply.rs) | Anonymous replies using `AnonymousSenderTag` and `send_reply()` |
| Builder | [`builder.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/builder.rs) | Using `MixnetClientBuilder` with ephemeral keys |
| Builder with Storage | [`builder_with_storage.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/builder_with_storage.rs) | Persisting keys to disk with `StoragePaths` |
| Parallel Send/Receive | [`parallel_sending_and_receiving.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/parallel_sending_and_receiving.rs) | Using `split_sender()` for concurrent tasks |
| Sandbox Testnet | [`sandbox.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/sandbox.rs) | Connecting to the Sandbox testnet instead of mainnet |
| Bandwidth Credential | [`bandwidth.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/bandwidth.rs) | Acquiring a bandwidth credential for paid mixnet access |
| Custom Topology | [`custom_topology_provider.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/custom_topology_provider.rs) | Implementing the `TopologyProvider` trait to filter or customize node selection |
| Overwrite Topology | [`manually_overwrite_topology.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/manually_overwrite_topology.rs) | Manually constructing a topology with hardcoded nodes |
| Control Requests | [`control_requests.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/control_requests.rs) | Sending service provider control requests (health, version, binary info) |
| Custom Storage | [`manually_handle_storage.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/manually_handle_storage.rs) | Implementing custom storage backends for keys, gateways, and credentials |

---
title: Mixnet Module Troubleshooting
description: Solutions for common Nym Rust SDK issues: client disconnect errors, empty SURB messages, verbose logging, and database lock problems.
url: https://nym.com/docs/developers/rust/mixnet/troubleshooting
---

# Troubleshooting

Common issues and how to resolve them.

## Always disconnect your client

You should always **manually disconnect your client** with `client.disconnect().await`. The client writes to a local DB and manages SURB storage, so it needs to shut down gracefully. Failing to do this can lead to the errors described below.

## Waiting for non-empty messages

When listening for a response, you may receive empty messages. These are SURB replenishment requests: the remote side asking for more reply SURBs. Filter them out:

```rust
let mut message = None;
while let Some(new_message) = client.wait_for_messages().await {
    if !new_message.is_empty() {
        message = new_message.into_iter().next();
        break;
    }
}
```

Prefer `client.next().await` (from the `futures::StreamExt` trait, not the Nym Stream module) over `client.wait_for_messages().await`; it returns one message at a time which is easier to work with. You'll need `use futures::StreamExt;` in scope.

## Verbose `task client is being dropped` logging

### On client shutdown (expected)

When calling `client.disconnect().await`, the client logs that its background tasks are shutting down. This is normal and expected.

Control log verbosity with `RUST_LOG`:

```sh
RUST_LOG=warn cargo run --example simple
```

### Not on client shutdown (unexpected)

If you see these messages unexpectedly, you may be killing the client process too early. See the next section.

## Accidentally killing your client process too early

If you see errors like `Polling shutdown failed: channel closed` or panics about `action control task has died`, your client is being dropped before it finishes sending.

`send_plain_message()` is async, but **it only blocks until the message is placed in the client's internal queue**, not until it's actually sent into the Mixnet. After queuing, the client still needs to route-encrypt the message and interleave it with cover traffic.

Make sure the program stays alive long enough. In practice this means awaiting a response or calling `sleep` before disconnecting:

```rust
// Send a message
client.send_plain_message(recipient, "hello").await.unwrap();

// Wait for the reply (keeps the client alive)
if let Some(received) = client.wait_for_messages().await {
    for r in received {
        println!("Received: {}", String::from_utf8_lossy(&r.message));
    }
}

// Always disconnect gracefully
client.disconnect().await;
```

## Lots of `duplicate fragment received` messages

`WARN` level logs about duplicate fragments are caused by Mixnet-level packet retransmission: the original and the retransmitted copy both arrive. This is not a bug in your client logic.

---
title: Stream Module: AsyncRead/AsyncWrite Over the Mixnet
description: The Nym Stream module provides persistent, bidirectional byte channels over the mixnet with standard Rust AsyncRead and AsyncWrite traits.
url: https://nym.com/docs/developers/rust/stream
---

# Stream Module

The Mixnet is fundamentally message-based: no persistent connections, no guaranteed ordering, no TCP. The default [message API](./mixnet) works at this level, sending individual payloads independently through Mix Nodes. This is effective for privacy but unlike how most networking code is structured.

The **Stream module** bridges the gap by providing persistent, bidirectional byte channels that behave like TCP sockets. Each `MixnetStream` implements [`AsyncRead`](https://docs.rs/tokio/latest/tokio/io/trait.AsyncRead.html) and [`AsyncWrite`](https://docs.rs/tokio/latest/tokio/io/trait.AsyncWrite.html), so `tokio::io::copy`, codecs, `BufReader`/`BufWriter`, and any other async I/O consumer work without modification. **If you're coming from socket-based networking, start here.**

All streams are multiplexed over a single `MixnetClient`. A background router task reads a small header on each incoming message and dispatches the payload to the correct stream by ID, so multiple concurrent streams require no additional connections or gateways.

## How it works

The two sides of a stream connection follow a client/server pattern:

1. **Opener** calls `client.open_stream(recipient, surbs)`. This generates a random `StreamId`, registers the stream locally, and sends an `Open` message through the Mixnet.
2. **Listener** calls `listener.accept()`, which blocks until an `Open` arrives, registers the new stream, and returns a `MixnetStream` ready for reading and writing.
3. Both sides read and write using standard `AsyncRead`/`AsyncWrite`. Bytes are wrapped in a 16-byte LP frame header (stream ID, message type, sequence number), routed through the Mixnet, and demultiplexed on arrival.
4. **Cleanup** happens on `drop`. The stream deregisters from the local router. No close message is sent over the wire, since a close could race ahead of in-flight data.

```text
┌─────────────────────────────────────────────────────────┐
│                      MixnetClient                       │
│                                                         │
│  ┌──────────────┐   ┌──────────────┐                    │
│  │ MixnetStream │   │ MixnetStream │  ...               │
│  │  (peer A)    │   │  (peer B)    │                    │
│  └──────┬───────┘   └──────┬───────┘                    │
│         │writes            │writes                      │
│         ▼                  ▼                            │
│  ┌─────────────────────────────────┐                    │
│  │     ClientInput.input_sender    │                    │
│  └──────────────┬──────────────────┘                    │
│                 │                                       │
│                 ▼                                       │
│           ── mixnet ──                                  │
│                 │                                       │
│                 ▼                                       │
│  ┌─────────────────────────────────┐                    │
│  │     reconstructed_receiver      │                    │
│  └──────────────┬──────────────────┘                    │
│                 │                                       │
│                 ▼                                       │
│  ┌─────────────────────────────────┐                    │
│  │           Router task           │                    │
│  │  decode header → dispatch by ID │                    │
│  └──┬──────────────────────────┬───┘                    │
│     │ Open messages            │ Data messages          │
│     ▼                          ▼                        │
│  ┌──────────────┐   ┌──────────────────┐                │
│  │MixnetListener│   │ StreamMap lookup │                │
│  │  .accept()   │   │ → per-stream tx  │                │
│  └──────────────┘   └──────────────────┘                │
└─────────────────────────────────────────────────────────┘
```

## Complete example

A minimal example with two clients on the same machine: one opens a stream to the other, sends a message, and reads a reply.

```rust
use nym_sdk::mixnet;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::time::Duration;

const TIMEOUT: Duration = Duration::from_secs(60);

#[tokio::main]
async fn main() {
    // Connect two ephemeral clients
    let mut sender = mixnet::MixnetClient::connect_new().await.unwrap();
    let mut receiver = mixnet::MixnetClient::connect_new().await.unwrap();
    let receiver_addr = *receiver.nym_address();

    // The receiver creates a listener (activates stream mode)
    let mut listener = receiver.listener().unwrap();

    // The sender opens a stream to the receiver's Nym address
    let mut outbound = sender.open_stream(receiver_addr, None).await.unwrap();

    // The receiver accepts the incoming stream
    let mut inbound = tokio::time::timeout(TIMEOUT, listener.accept())
        .await
        .expect("timed out")
        .expect("listener closed");

    // Send data and read it back, just like a TCP socket
    outbound.write_all(b"hello from sender").await.unwrap();
    outbound.flush().await.unwrap();

    let mut buf = vec![0u8; 1024];
    let n = tokio::time::timeout(TIMEOUT, inbound.read(&mut buf))
        .await
        .expect("timed out")
        .expect("read failed");
    println!("Receiver got: {}", String::from_utf8_lossy(&buf[..n]));

    // Reply back through the same stream
    inbound.write_all(b"hello from receiver").await.unwrap();
    inbound.flush().await.unwrap();

    let n = tokio::time::timeout(TIMEOUT, outbound.read(&mut buf))
        .await
        .expect("timed out")
        .expect("read failed");
    println!("Sender got: {}", String::from_utf8_lossy(&buf[..n]));

    // Streams deregister on drop, then disconnect clients
    drop(outbound);
    drop(inbound);
    sender.disconnect().await;
    receiver.disconnect().await;
}
```

The receiver replies via **reply SURBs** (Single Use Reply Blocks) and never learns the sender's Nym address.

## When to use streams vs messages

| | Messages | Streams | TcpProxy |
|---|---|---|---|
| **Pattern** | Raw message payloads | Persistent bidirectional channels | TCP socket proxying |
| **API** | `send_plain_message()` / `wait_for_messages()` | `AsyncRead` + `AsyncWrite` | Localhost TCP socket |
| **Multiplexing** | N/A | Multiple streams per client | One client per TCP connection |
| **Ordering** | No guarantees | Sequence-based reordering | Session-based ordering |
| **Best for** | Simple notifications, one-shot requests | Interactive protocols, streaming data, any code expecting async I/O | Wrapping existing TCP applications |
| **Status** | Stable | New | Deprecated |

**Streams and messages are mutually exclusive.** Once you call `open_stream()` or `listener()`, the message-based API (`send_plain_message`, `wait_for_messages`) is permanently disabled on that client. This is a one-way transition: there is no switching back without disconnecting and reconnecting. See the [`stream_mode_guard.rs` example](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/stream_mode_guard.rs) for details.

## Next steps

- [Tutorial: Build a private echo server](./stream/tutorial): server and client communicating over streams
- [Architecture](./stream/architecture): wire protocol, router task, data flow, stream cleanup, and known limitations
- [Examples](./stream/examples): annotated walkthroughs of the SDK examples (multi-stream, idle timeout, throughput testing)

---
title: Stream Tutorial: Build a Private Echo Server
description: Step-by-step Rust tutorial to build an echo server and client communicating through the Nym mixnet using AsyncRead and AsyncWrite streams.
url: https://nym.com/docs/developers/rust/stream/tutorial
---

# Tutorial: Build a Private Echo Server

In this tutorial you'll build two programs: a server that listens for incoming streams and echoes back whatever it receives, and a client that opens a stream, sends data, and reads the echo. Both communicate through the Nym Mixnet using `AsyncRead` and `AsyncWrite`, just like TCP sockets.

## What you'll learn

- Setting up a `MixnetListener` to accept incoming streams
- Opening an outbound stream with `open_stream()`
- Reading and writing with standard tokio I/O traits
- How streams are multiplexed over a single `MixnetClient`
- Clean shutdown and stream lifecycle

## Prerequisites

- Rust toolchain ({RUST_MSRV}+)
- A working internet connection (clients connect to the live Nym Mixnet)

## Step 1: Set up the project

```sh
cargo init nym-echo
cd nym-echo
rm src/main.rs
```

Add dependencies to `Cargo.toml`:

```toml
[dependencies]
nym-sdk = "1.21.0"
nym-bin-common = { version = "1.21.0", features = ["basic_tracing"] }
tokio = { version = "1", features = ["full"] }
rand = "0.8"
```

## Step 2: Build the echo server

The server connects a `MixnetClient`, creates a listener, and accepts streams in a loop. Each stream gets its own task that reads data and writes it back.

Create `src/bin/server.rs`:

```rust
use nym_sdk::mixnet;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    // Connect to the Mixnet
    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    println!("Echo server listening at: {}", client.nym_address());

    // Create a listener: this activates stream mode.
    // From this point, message-based methods are disabled.
    let mut listener = client.listener().unwrap();

    // Accept streams in a loop
    loop {
        let mut stream = match listener.accept().await {
            Some(s) => s,
            None => {
                println!("Listener closed");
                break;
            }
        };

        let stream_id = stream.id();
        println!("Accepted stream {stream_id}");

        // Spawn a task to handle each stream concurrently
        tokio::spawn(async move {
            let mut buf = vec![0u8; 32_000];

            loop {
                let n = match stream.read(&mut buf).await {
                    Ok(0) => break,     // EOF: stream closed
                    Ok(n) => n,
                    Err(e) => {
                        eprintln!("Stream {stream_id} read error: {e}");
                        break;
                    }
                };

                let data = &buf[..n];
                println!("Stream {stream_id} received {n} bytes");

                // Echo it back
                if let Err(e) = stream.write_all(data).await {
                    eprintln!("Stream {stream_id} write error: {e}");
                    break;
                }
                stream.flush().await.unwrap();
            }

            println!("Stream {stream_id} closed");
        });
    }
}
```

**`listener()` can only be called once per client.** It takes exclusive ownership of the inbound message channel. A second call returns `Error::ListenerAlreadyTaken`.

## Step 3: Build the client

The client connects, opens a stream to the server, sends a few messages, reads back the echoes, and disconnects.

Create `src/bin/client.rs`:

```rust
use nym_sdk::mixnet::{self, Recipient};
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

const TIMEOUT: Duration = Duration::from_secs(60);

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    // Read the server's Nym address from the command line
    let server_addr: Recipient = std::env::args()
        .nth(1)
        .expect("Usage: client <SERVER_NYM_ADDRESS>")
        .parse()
        .expect("Invalid Nym address");

    // Connect to the Mixnet
    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    println!("Client address: {}", client.nym_address());

    // Open a stream to the server.
    // The second argument (None) uses the default number of reply SURBs.
    let mut stream = client.open_stream(server_addr, None).await.unwrap();
    println!("Stream opened: {}", stream.id());

    // Give the Open message time to traverse the mixnet and reach the server.
    // open_stream() returns immediately after sending. It doesn't wait for
    // the server to accept. Writing too soon risks the data arriving before
    // the Open, which the server would drop.
    tokio::time::sleep(Duration::from_secs(5)).await;

    // Send three payloads of different sizes and verify the echo.
    // Random bytes show that streams are binary-safe, not just text.
    let sizes = [320, 25_000, 1280];

    for (i, &size) in sizes.iter().enumerate() {
        let payload: Vec<u8> = (0..size).map(|_| rand::random::<u8>()).collect();
        println!("Sending message {} ({size} bytes)", i + 1);

        stream.write_all(&payload).await.unwrap();
        stream.flush().await.unwrap();

        // Read the echo
        let mut buf = vec![0u8; 32_000];
        let n = tokio::time::timeout(TIMEOUT, stream.read(&mut buf))
            .await
            .expect("timed out waiting for echo")
            .expect("read failed");

        assert_eq!(&buf[..n], &payload[..], "echo mismatch on message {}", i + 1);
        println!("Received echo: {n} bytes ok");
    }

    // Drop the stream to deregister it from the router
    drop(stream);

    // Disconnect the client
    client.disconnect().await;
    println!("Done!");
}
```

## Step 4: Run it

In one terminal, start the server:

```sh
RUST_LOG=info cargo run --bin server
```

It prints its Nym address:

```
Echo server listening at: 8gk4Y...@2xU4d...
```

In a second terminal, start the client with the server's address:

```sh
RUST_LOG=info cargo run --bin client -- 8gk4Y...@2xU4d...
```

You'll see the messages traverse the Mixnet and echo back:

```
Client address: F3qR7...@9nK2m...
Stream opened: 12345678
Sending message 1 (320 bytes)
Received echo: 320 bytes ok
Sending message 2 (25000 bytes)
Received echo: 25000 bytes ok
Sending message 3 (1280 bytes)
Received echo: 1280 bytes ok
Done!
```

On the server side:

```
Accepted stream 12345678
Stream 12345678 received 320 bytes
Stream 12345678 received 25000 bytes
Stream 12345678 received 1280 bytes
Stream 12345678 closed
```

## How it works internally

1. The server's `listener()` activates **stream mode**, which spawns a **router task** that decodes incoming Mixnet messages and dispatches them by stream ID.

2. The client's `open_stream()` generates a random 8-byte `StreamId`, sends an `Open` message through the Mixnet, and registers the stream in a local routing table.

3. When the server's router receives the `Open` message, it delivers it to `listener.accept()`, which creates the inbound `MixnetStream`.

4. Each `write_all()` prepends a 16-byte LP frame header (`[LpFrameKind: 2B][StreamId: 8B][MsgType: 1B][SequenceNum: 4B][Reserved: 1B]`) and sends the data through the Mixnet as a Sphinx packet.

5. On arrival, the router reads the `LpFrameKind` to identify it as stream traffic, decodes the header, finds the matching stream by ID, and delivers the raw payload to `read()`.

6. The inbound stream replies via **reply SURBs**, the same anonymous reply mechanism as the message API, applied transparently. The server never learns the client's Nym address.

7. When a stream is dropped, it deregisters from the local router. No close message is sent over the wire, since a close could race ahead of in-flight data.

See the [Architecture](./architecture) page for the full technical details.

## What you've learned

- `client.listener()` activates stream mode and returns a `MixnetListener`
- `listener.accept()` blocks until a remote peer opens a stream
- `client.open_stream(recipient, surbs)` opens an outbound stream to a Nym address
- `MixnetStream` implements `AsyncRead + AsyncWrite`, so standard tokio I/O works unchanged
- Multiple streams are multiplexed over a single client
- Streams deregister on `drop`; no close handshake is needed
- The server replies via SURBs and never learns the client's address

## Complete code

### Server (`src/bin/server.rs`)

```rust
use nym_sdk::mixnet;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    println!("Echo server listening at: {}", client.nym_address());

    let mut listener = client.listener().unwrap();

    loop {
        let mut stream = match listener.accept().await {
            Some(s) => s,
            None => {
                println!("Listener closed");
                break;
            }
        };

        let stream_id = stream.id();
        println!("Accepted stream {stream_id}");

        tokio::spawn(async move {
            let mut buf = vec![0u8; 32_000];

            loop {
                let n = match stream.read(&mut buf).await {
                    Ok(0) => break,
                    Ok(n) => n,
                    Err(e) => {
                        eprintln!("Stream {stream_id} read error: {e}");
                        break;
                    }
                };

                let data = &buf[..n];
                println!("Stream {stream_id} received {n} bytes");

                if let Err(e) = stream.write_all(data).await {
                    eprintln!("Stream {stream_id} write error: {e}");
                    break;
                }
                stream.flush().await.unwrap();
            }

            println!("Stream {stream_id} closed");
        });
    }
}
```

### Client (`src/bin/client.rs`)

```rust
use nym_sdk::mixnet::{self, Recipient};
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

const TIMEOUT: Duration = Duration::from_secs(60);

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    let server_addr: Recipient = std::env::args()
        .nth(1)
        .expect("Usage: client <SERVER_NYM_ADDRESS>")
        .parse()
        .expect("Invalid Nym address");

    let mut client = mixnet::MixnetClient::connect_new().await.unwrap();
    println!("Client address: {}", client.nym_address());

    let mut stream = client.open_stream(server_addr, None).await.unwrap();
    println!("Stream opened: {}", stream.id());

    // Wait for the Open message to reach the server through the mixnet
    tokio::time::sleep(Duration::from_secs(5)).await;

    let sizes = [320, 25_000, 1280];

    for (i, &size) in sizes.iter().enumerate() {
        let payload: Vec<u8> = (0..size).map(|_| rand::random::<u8>()).collect();
        println!("Sending message {} ({size} bytes)", i + 1);

        stream.write_all(&payload).await.unwrap();
        stream.flush().await.unwrap();

        let mut buf = vec![0u8; 32_000];
        let n = tokio::time::timeout(TIMEOUT, stream.read(&mut buf))
            .await
            .expect("timed out waiting for echo")
            .expect("read failed");

        assert_eq!(&buf[..n], &payload[..], "echo mismatch on message {}", i + 1);
        println!("Received echo: {n} bytes ok");
    }

    drop(stream);
    client.disconnect().await;
    println!("Done!");
}
```

---
title: Stream Module Architecture
description: Internal architecture of the Nym Stream subsystem: wire protocol, multiplexing, router task, and how concurrent byte channels share a single MixnetClient.
url: https://nym.com/docs/developers/rust/stream/architecture
---

# Stream Architecture

{/* Canonical source: sdk/rust/nym-sdk/src/mixnet/stream/ARCHITECTURE.md */}

## Overview

The stream subsystem gives each `MixnetClient` the ability to hold many concurrent byte channels (`AsyncRead + AsyncWrite`) to different remote peers, multiplexed over a single client connection.

```mermaid
---
config:
  theme: neo-dark
---
flowchart TD
    subgraph MixnetClient
        SA["MixnetStream A"] -->|writes| CI["Client input channel"]
        SB["MixnetStream B"] -->|writes| CI
        CI --> MX["── Mixnet ──"]
        MX --> RT["Router task"]
        RT -->|Open messages| ML["MixnetListener.accept()"]
        RT -->|Data messages| SM["Stream routing table"]
        SM --> SA
        SM --> SB
    end
```

## Wire protocol

Every stream message has a fixed 16-byte LP frame header prepended to the payload:

```
[LpFrameKind: 2 bytes LE][StreamId: 8 bytes BE][MsgType: 1 byte][SequenceNum: 4 bytes BE][Reserved: 1 byte][payload ...]
```

- **LpFrameKind:** `3` (SphinxStream). Distinguishes stream traffic from other LP frame types (Opaque, Registration, Forward).
- **StreamId:** random `u64` generated by the opener, used to multiplex streams.
- **MsgType:** `Open` (0) or `Data` (1).
- **SequenceNum:** `u32` counter, incremented per write. Used by the receiver's per-stream reorder buffer to deliver data in the correct order.
- **Reserved:** must be `0x00`.

There is no `Close` message type; see [Known Limitations](#known-limitations) for why.

## Stream mode

Stream mode is activated lazily on the first call to `open_stream()` or `listener()`. This is a **one-way transition**:

1. The client's message receiver is handed off to a background router task
2. `stream_mode` flag is set to `true`
3. Message-based methods (`send_plain_message`, `wait_for_messages`) are disabled and return errors

There is no switching back without disconnecting and creating a new client.

## Opening and accepting streams

**Opening (outbound):**
1. `open_stream(recipient, surbs)` generates a random `StreamId`
2. An `Open` message is sent through the Mixnet to the recipient
3. A `MixnetStream` is returned, ready for writing and reading

**Accepting (inbound):**
1. `listener.accept()` waits for an `Open` message from a remote peer
2. A `MixnetStream` is created with the opener's `sender_tag` for anonymous replies
3. The stream is ready for bidirectional I/O

## Cleanup

- **On `drop`:** the stream deregisters from the routing table. No close message is sent over the wire.
- **Idle timeout:** streams idle for longer than the configured timeout (default: 30 minutes) are automatically cleaned up. Configure with [`MixnetClientBuilder::with_stream_idle_timeout()`](https://docs.rs/nym-sdk/latest/nym_sdk/mixnet/struct.MixnetClientBuilder.html).

## Known limitations

**Sequence-based reordering.** The Mixnet does not guarantee message ordering at the transport level, but each stream write includes a `sequence_num` in the LP frame header. The receiver maintains a per-stream reorder buffer (BTreeMap keyed by sequence number) that buffers out-of-order messages and drains them in sequence. This means protocols that depend on byte ordering (HTTP, TLS, protobuf) work correctly over streams.

- **Buffer cap:** 256 messages per stream. If the buffer fills (e.g. a large gap in sequence numbers), the receiver skips ahead to the lowest buffered sequence.
- **Duplicates:** messages with a sequence number below the next expected are dropped.
- There is no `Close` message type, since a close could race ahead of in-flight data.

## Internal details

For the full implementation details (router task, `StreamMap`, `PollSender` usage, base-client type rationale), see the `ARCHITECTURE.md` file next to the module source code, or the [docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/) API reference.

---
title: Stream Module Examples
description: Runnable Rust examples for the Nym Stream module: bidirectional read/write, idle timeouts, mode guards, and throughput benchmarks.
url: https://nym.com/docs/developers/rust/stream/examples
---

# Examples

Runnable examples in [`sdk/rust/nym-sdk/examples/`](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples). Each file is self-contained with step-by-step comments.

```bash
cargo run --example <name>
```

| Example | Source | What it demonstrates |
|---|---|---|
| Simple Read/Write | [`stream_simple_read_write.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/stream_simple_read_write.rs) | Multiple concurrent streams, bidirectional communication |
| Idle Timeout | [`stream_idle_timeout.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/stream_idle_timeout.rs) | Configuring `with_stream_idle_timeout`, observing EOF after cleanup |
| Mode Guard | [`stream_mode_guard.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/stream_mode_guard.rs) | Mutual exclusion between stream and message modes |
| Throughput | [`stream_throughput.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/stream_throughput.rs) | Sending 1 MB over a single stream, verifying data integrity |

---
title: Nym TcpProxy: Route TCP via the Mixnet
description: Route TCP traffic through the Nym mixnet using the TcpProxy Rust module. Covers architecture, single and multi-connection patterns, and troubleshooting.
url: https://nym.com/docs/developers/rust/tcpproxy
---

# TcpProxy Module

  **This module is unmaintained.** The TcpProxy is no longer actively developed in favour of the [Stream module](/developers/rust/stream), which provides `AsyncRead + AsyncWrite` streams directly over the Mixnet without the TCP socket overhead. Existing users should plan to migrate to streams when possible. The TcpProxy will continue to work but will not receive new features or bug fixes.

The Stream module offers the same key benefit (familiar I/O patterns on top of the Mixnet) with a simpler API. Streams multiplex connections on a single client, eliminate the localhost socket overhead, and now include sequence-based message reordering. There is no remaining reason to choose TcpProxy over Streams for new projects.

---

`NymProxyClient` and `NymProxyServer` proxy TCP traffic through the Mixnet. Both run in a background thread and expose a configurable `localhost` socket that you read and write to like any other TCP connection.

> Non-Rust/Go developers who want to experiment with this module can start with the [standalone binaries](/developers/tools/standalone-tcpproxy).

## Examples

| Example | Source |
|---|---|
| Single connection | [`tcp_proxy_single_connection.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/tcp_proxy_single_connection.rs) |
| Multiple connections | [`tcp_proxy_multistream.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/tcp_proxy_multistream.rs) |

```bash
cargo run --example tcp_proxy_single_connection
cargo run --example tcp_proxy_multistream
```

## API reference

- [API reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/tcp_proxy/): architecture overview, client/server examples, and type documentation

## Tutorial

Set up the project:

```sh
cargo init nym-tcp-proxy
cd nym-tcp-proxy
rm src/main.rs
```

Add dependencies to `Cargo.toml`:

```toml
[dependencies]
nym-sdk = "1.21.0"
nym-network-defaults = "1.21.0"
nym-bin-common = { version = "1.21.0", features = ["basic_tracing"] }
tokio = { version = "1", features = ["full"] }

[[bin]]
name = "proxy_server"
path = "src/bin/proxy_server.rs"

[[bin]]
name = "proxy_client"
path = "src/bin/proxy_client.rs"
```

### Server

The server connects to the Mixnet and forwards incoming traffic to a local TCP service (e.g. a web server on port 8000).

```rust
use nym_sdk::tcp_proxy::NymProxyServer;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    nym_bin_common::logging::setup_tracing_logger();

    let mut server = NymProxyServer::new(
        "127.0.0.1:8000",           // upstream address (host:port)
        "./proxy-server-config",    // config directory for persistent keys
        None,                       // env file (None = mainnet)
        None,                       // gateway (None = auto-select)
    ).await?;

    println!("Proxy server address: {}", server.nym_address());
    server.run_with_shutdown().await?;
    Ok(())
}
```

### Client

The client opens a localhost TCP socket and tunnels all traffic through the Mixnet to the server.

```rust
use nym_sdk::tcp_proxy::NymProxyClient;
use nym_sdk::mixnet::Recipient;
use nym_network_defaults::setup_env;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    nym_bin_common::logging::setup_tracing_logger();
    // Load mainnet network defaults into env vars (required by NymProxyClient's internal ClientPool)
    setup_env(None::<String>);

    let server_addr: Recipient = std::env::args()
        .nth(1).expect("Usage: proxy_client <SERVER_NYM_ADDRESS>")
        .parse()?;

    let client = NymProxyClient::new(
        server_addr,
        "127.0.0.1",  // listen host
        "8070",       // listen port
        60,           // close timeout (seconds)
        None,         // env file (None = mainnet)
        1,            // client pool size
    ).await?;

    let proxy = tokio::spawn(async move { client.run().await });

    // Wait for the pool to create a client and the proxy to be ready.
    // The first startup takes ~10-15s while the client connects to the Mixnet.
    println!("Waiting for proxy to be ready...");
    tokio::time::sleep(std::time::Duration::from_secs(15)).await;

    let mut stream = TcpStream::connect("127.0.0.1:8070").await?;
    stream.write_all(b"GET / HTTP/1.0\r\nHost: localhost\r\n\r\n").await?;

    let mut response = Vec::new();
    stream.read_to_end(&mut response).await?;
    println!("Response:\n{}", String::from_utf8_lossy(&response));

    drop(stream);
    proxy.abort();
    Ok(())
}
```

### Run it

Start an upstream TCP service (e.g. a simple HTTP server):

```sh
python3 -m http.server 8000
```

In a second terminal, start the proxy server:

```sh
RUST_LOG=info cargo run --bin proxy_server
```

Copy the Nym address it prints, then in a third terminal:

```sh
RUST_LOG=info cargo run --bin proxy_client -- <SERVER_NYM_ADDRESS>
```

The response will take 30–60 seconds to arrive as it traverses the Mixnet in both directions.

## Architecture

Each sub-module handles Nym clients differently:
- **`NymProxyClient`** relies on the [Client Pool](/developers/rust/client-pool) to create clients and keep a reserve. If incoming TCP connections outpace the pool, it creates an ephemeral client per connection. One client maps to one TCP connection.
- **`NymProxyServer`** has a single Nym client with a persistent identity.

### Sessions & message ordering

Messages are wrapped in a session ID per connection, with individual messages given an incrementing message ID. Once all messages are sent, the client sends a `Close` message to notify the server that there are no more outbound messages for this session.

> Session management and message IDs are necessary since *the Mixnet guarantees message delivery but not message ordering*: in the case of trying to e.g. send gRPC protobuf through the Mixnet, ordering is required so that a buffer is not split across Sphinx packet payloads, and that the 2nd half of the frame is not passed upstream to the parser before the 1st half.

The key data structure:

```rust
pub struct ProxiedMessage {
    message: Payload,
    session_id: Uuid,
    message_id: u16,
}
```

### Full request/response flow

```mermaid
---
config:
  theme: neo-dark
  layout: elk
---
sequenceDiagram
    box Local Machine
    participant Client Process
    participant NymProxyClient
    end
    Client Process->>NymProxyClient: Request bytes
    NymProxyClient->>NymProxyClient: New session
    NymProxyClient->>Entry Gateway: Sphinx Packets: Message 1
    Entry Gateway-->>NymProxyClient: Acks
    NymProxyClient->>Entry Gateway: Sphinx Packets: Message 2
    Entry Gateway-->>NymProxyClient: Acks
    NymProxyClient->>Entry Gateway: Sphinx Packets: Close Message
    Entry Gateway-->>NymProxyClient: Acks

    Entry Gateway-->>Mix Nodes: All Packets, Acks, etc
    Note right of Mix Nodes: We are omitting the 3 hops etc for brevity here
    Mix Nodes-->> Exit Gateway: All Packets, Acks, etc

    Exit Gateway->>NymProxyServer: Sphinx Packets: Message 2
    NymProxyServer-->>Exit Gateway: Acks
    loop Message Buffer
        NymProxyServer->>NymProxyServer: Wait for Message 1
        Exit Gateway->>NymProxyServer: Sphinx Packets: Message 1
        NymProxyServer-->>Exit Gateway: Acks
        NymProxyServer->>NymProxyServer: Message Received: trigger upstream send
    end
    Note right of NymProxyServer: Note this happens **per session**
    NymProxyServer->>Upstream Process: Reconstructed request bytes
    Upstream Process->>Upstream Process: Do something with request
    Exit Gateway->>NymProxyServer: Sphinx Packets: Close Message
    NymProxyServer-->>Exit Gateway: Acks
    NymProxyServer->>NymProxyServer: Trigger Client timeout start for session
    Upstream Process->>NymProxyServer: Response bytes
    NymProxyServer->>NymProxyServer: Write to provided SURB payloads
    NymProxyServer->>Exit Gateway: Anonymous replies
    box Remote Host
    participant NymProxyServer
    participant Upstream Process
    end

    Entry Gateway->>NymProxyClient: Sphinx Packets: Reply Message 2
    NymProxyClient-->Entry Gateway: Ack
    Loop Message Buffer:
        NymProxyClient->>NymProxyClient: Wait for Message 1
        Entry Gateway->>NymProxyClient: Sphinx Packets: Message 1
        NymProxyClient-->>Entry Gateway: Acks
        NymProxyClient->>NymProxyClient: Message Received: trigger send
        NymProxyClient->>Client Process: Response bytes
    end
    Note right of NymProxyClient: Note this happens **per session**
```

## Troubleshooting

### Lots of `duplicate fragment received` messages

`WARN` level logs about duplicate fragments are caused by Mixnet-level packet retransmission, where both the original and the retransmitted copy arrive at the destination. This is expected behaviour, not a bug in the client or TcpProxy module.

---
title: Client Pool: Pre-Connected Mixnet Clients
description: The Nym ClientPool maintains ready-to-use MixnetClient instances, eliminating connection latency for bursty traffic patterns.
url: https://nym.com/docs/developers/rust/client-pool
---

# Client Pool

The `ClientPool` maintains a configurable number of connected ephemeral `MixnetClient` instances, ready for immediate use. This eliminates the connection latency that comes with creating a new client on each request: the gateway handshake, key generation, and topology fetch all happen ahead of time.

## How it works

```mermaid
---
config:
  theme: neo-dark
---
flowchart LR
    BG["Background loop"] -->|creates clients| P["Pool (Vec)"]
    P -->|"get_mixnet_client()"| APP["Your application"]
    APP -->|uses and disconnects| D["Done"]
    BG -->|"pool < reserve? create another"| P
```

1. **Create** the pool with a target reserve size: `ClientPool::new(5)`
2. **Start** the background loop: `pool.start()`. It immediately begins connecting clients
3. **Pop** a client when needed: `pool.get_mixnet_client()` returns `Some(client)` or `None` if the pool is empty
4. **Use** the client normally: send messages, open streams, etc.
5. **Disconnect** the client when done. The background loop notices the pool is below reserve and creates a replacement

Clients are **consumed, not returned**. The pool creates new ones to maintain the reserve. If the pool is empty, you can fall back to `MixnetClient::connect_new()` (slower, but keeps things working).

The `NymProxyClient` (TcpProxy) uses a `ClientPool` internally: one client per incoming TCP connection.

## Quick example

```rust
use nym_sdk::client_pool::ClientPool;
use nym_network_defaults::setup_env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    nym_bin_common::logging::setup_tracing_logger();
    // Load mainnet network defaults into env vars (required by ClientPool)
    setup_env(None::<String>);

    let pool = ClientPool::new(5); // maintain 5 clients in reserve

    let pool_clone = pool.clone();
    tokio::spawn(async move { pool_clone.start().await });

    // Get a client when needed
    if let Some(client) = pool.get_mixnet_client().await {
        println!("Got client: {}", client.nym_address());
        client.disconnect().await;
    }

    pool.disconnect_pool().await;
    Ok(())
}
```

## Further reading

- [Tutorial: Handle bursty traffic](./client-pool/tutorial): step-by-step guide covering pool creation, burst handling, and fallback logic
- [API reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/client_pool/): type details, method signatures, and architecture docs
- [Example source on GitHub](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs): complete working example

---
title: Client Pool Tutorial: Handle Bursty Traffic
description: Step-by-step Rust tutorial to use Nym ClientPool for handling bursts of concurrent mixnet operations without blocking on client creation.
url: https://nym.com/docs/developers/rust/client-pool/tutorial
---

# Tutorial: Handle Bursty Traffic with Client Pool

In this tutorial you'll build a program that uses `ClientPool` to handle bursts of concurrent Mixnet operations without blocking on client creation. You'll see how the pool pre-creates clients in the background, how to pop them under load, and what happens when demand exceeds supply.

## What you'll learn

- Creating and starting a `ClientPool`
- Popping clients from the pool for concurrent operations
- Falling back to on-demand client creation when the pool is empty
- Observing pool replenishment
- Graceful shutdown

## Prerequisites

- Rust toolchain ({RUST_MSRV}+)
- A working internet connection

## Step 1: Set up the project

```sh
cargo init nym-pool-demo
cd nym-pool-demo
```

Add dependencies to `Cargo.toml`:

```toml
[dependencies]
nym-sdk = "1.21.0"
nym-network-defaults = "1.21.0"
nym-bin-common = { version = "1.21.0", features = ["basic_tracing"] }
tokio = { version = "1", features = ["full"] }
```

## Step 2: Create and start the pool

The pool is created with a **reserve size**: the number of connected clients it tries to maintain at all times. The `start()` method runs a background loop that creates clients whenever the pool drops below the reserve.

Create `src/main.rs`:

```rust
use nym_sdk::client_pool::ClientPool;
use nym_sdk::mixnet::MixnetMessageSender;
use nym_network_defaults::setup_env;
use std::time::Duration;

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();

    // Load mainnet network defaults into env vars (required by ClientPool)
    setup_env(None::<String>);

    // Create a pool that maintains 3 clients in reserve
    let pool = ClientPool::new(3);

    // Start the pool in a background task.
    // It immediately begins connecting clients.
    let pool_bg = pool.clone();
    tokio::spawn(async move {
        pool_bg.start().await.unwrap();
    });

    println!("Pool started, waiting for clients to connect...");
    tokio::time::sleep(Duration::from_secs(15)).await;

    // Check how many are ready
    let count = pool.get_client_count().await;
    println!("Pool has {count} clients ready");
```

Creating a `MixnetClient` takes several seconds (gateway handshake, key generation, topology fetch). The pool does this work ahead of time so your application doesn't block when it needs a client.

## Step 3: Pop clients and use them

When you call `get_mixnet_client()`, the pool removes a client and returns it. The background loop notices the shortfall and starts creating a replacement.

```rust
    // Simulate a burst of 3 concurrent tasks, each needing a client
    let mut handles = vec![];

    for i in 1..=3 {
        let pool = pool.clone();

        let handle = tokio::spawn(async move {
            // Pop a client from the pool
            let mut client = match pool.get_mixnet_client().await {
                Some(c) => {
                    println!("Task {i}: got client {} from pool", c.nym_address());
                    c
                }
                None => {
                    // Pool is empty: fall back to creating one on the fly.
                    // This is slower but keeps things working.
                    println!("Task {i}: pool empty, creating client on the fly...");
                    nym_sdk::mixnet::MixnetClient::connect_new().await.unwrap()
                }
            };

            // Do something with the client: here, send a message to ourselves
            let addr = *client.nym_address();
            client
                .send_plain_message(addr, format!("hello from task {i}"))
                .await
                .unwrap();

            // Wait for the message to arrive
            if let Some(msgs) = client.wait_for_messages().await {
                for msg in msgs {
                    if !msg.message.is_empty() {
                        println!(
                            "Task {i}: received {:?}",
                            String::from_utf8_lossy(&msg.message)
                        );
                    }
                }
            }

            // Disconnect when done: the pool will create a replacement
            client.disconnect().await;
            println!("Task {i}: done");
        });

        handles.push(handle);
    }

    // Wait for all tasks to finish
    for h in handles {
        h.await.unwrap();
    }
```

## Step 4: Observe replenishment

After popping all 3 clients, the pool background loop starts creating replacements. Give it time and check:

```rust
    // Pool should be replenishing
    println!("\nWaiting for pool to replenish...");
    tokio::time::sleep(Duration::from_secs(15)).await;

    let count = pool.get_client_count().await;
    println!("Pool has {count} clients ready again");
```

## Step 5: Shut down gracefully

```rust
    // Disconnect all remaining clients and stop the background loop
    pool.disconnect_pool().await;
    println!("Pool shut down");
}
```

## Step 6: Run it

```sh
RUST_LOG=info cargo run
```

You'll see output like:

```
Pool started, waiting for clients to connect...
Pool has 3 clients ready
Task 1: got client 8gk4Y...@2xU4d... from pool
Task 2: got client F3qR7...@9nK2m... from pool
Task 3: got client A7bN2...@4pL8w... from pool
Task 1: received "hello from task 1"
Task 2: received "hello from task 2"
Task 3: received "hello from task 3"
Task 1: done
Task 2: done
Task 3: done

Waiting for pool to replenish...
Pool has 3 clients ready again
Pool shut down
```

## When to use the pool

The pool is most useful when:

- **You have bursty traffic:** many concurrent operations that each need their own client
- **Latency matters:** you can't afford the several-second delay of creating a client on each request
- **You're building a service:** an API endpoint that creates a client per request would benefit from pre-warmed clients

If your application only ever needs one client at a time, just use `MixnetClient::connect_new()` directly.

The `NymProxyClient` (TcpProxy module) uses a `ClientPool` internally: one client per incoming TCP connection.

## What you've learned

- **`ClientPool::new(n)`** creates a pool targeting `n` reserve clients
- **`pool.start()`** runs a background loop that creates clients whenever the pool is below reserve
- **`pool.get_mixnet_client()`** pops a client; returns `None` if the pool is empty
- **Clients are consumed, not returned.** The pool automatically creates replacements
- **`pool.disconnect_pool()`** shuts down all remaining clients and stops the background loop
- **Fall back to on-demand creation** when the pool is empty for resilience

## Complete code

```rust
use nym_sdk::client_pool::ClientPool;
use nym_sdk::mixnet::MixnetMessageSender;
use nym_network_defaults::setup_env;
use std::time::Duration;

#[tokio::main]
async fn main() {
    nym_bin_common::logging::setup_tracing_logger();
    setup_env(None::<String>);

    let pool = ClientPool::new(3);

    let pool_bg = pool.clone();
    tokio::spawn(async move {
        pool_bg.start().await.unwrap();
    });

    println!("Pool started, waiting for clients to connect...");
    tokio::time::sleep(Duration::from_secs(15)).await;

    let count = pool.get_client_count().await;
    println!("Pool has {count} clients ready");

    let mut handles = vec![];

    for i in 1..=3 {
        let pool = pool.clone();

        let handle = tokio::spawn(async move {
            let mut client = match pool.get_mixnet_client().await {
                Some(c) => {
                    println!("Task {i}: got client {} from pool", c.nym_address());
                    c
                }
                None => {
                    println!("Task {i}: pool empty, creating client on the fly...");
                    nym_sdk::mixnet::MixnetClient::connect_new().await.unwrap()
                }
            };

            let addr = *client.nym_address();
            client
                .send_plain_message(addr, format!("hello from task {i}"))
                .await
                .unwrap();

            if let Some(msgs) = client.wait_for_messages().await {
                for msg in msgs {
                    if !msg.message.is_empty() {
                        println!(
                            "Task {i}: received {:?}",
                            String::from_utf8_lossy(&msg.message)
                        );
                    }
                }
            }

            client.disconnect().await;
            println!("Task {i}: done");
        });

        handles.push(handle);
    }

    for h in handles {
        h.await.unwrap();
    }

    println!("\nWaiting for pool to replenish...");
    tokio::time::sleep(Duration::from_secs(15)).await;

    let count = pool.get_client_count().await;
    println!("Pool has {count} clients ready again");

    pool.disconnect_pool().await;
    println!("Pool shut down");
}
```

---
title: Client Pool Examples
description: Runnable Rust example for the Nym Client Pool: managing multiple MixnetClients with ephemeral fallback.
url: https://nym.com/docs/developers/rust/client-pool/examples
---

# Examples

Runnable examples in [`sdk/rust/nym-sdk/examples/`](https://github.com/nymtech/nym/tree/develop/sdk/rust/nym-sdk/examples). Each file is self-contained with step-by-step comments.

```bash
cargo run --example <name>
```

| Example | Source | What it demonstrates |
|---|---|---|
| Client Pool | [`client_pool.rs`](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs) | Creating a pool of `MixnetClient`s, retrieving clients from the pool, and falling back to ephemeral clients when the pool is empty |

---
title: FFI Bindings: Go and C/C++
description: Use the Nym SDK from Go and C/C++ via FFI bindings. Covers mixnet messaging, anonymous replies, and TcpProxy lifecycle from non-Rust languages.
url: https://nym.com/docs/developers/rust/ffi
---

# FFI Bindings

The SDK exposes FFI bindings for Go and C/C++. The source lives in [`sdk/ffi`](https://github.com/nymtech/nym/tree/develop/sdk/ffi):

```
ffi
├── cpp      # C/C++ bindings (manual C FFI)
├── go       # Go bindings (via uniffi-bindgen-go)
└── shared   # Shared Rust implementation
```

Core logic lives in `shared/` and is imported into language-specific wrappers. The shared layer handles thread safety and ensures client operations run on blocking threads on the Rust side of the FFI boundary.

## What's exposed

**Mixnet** (Go and C/C++): ephemeral and persistent client creation, sending messages, anonymous replies via SURBs, listening for incoming messages.

**TcpProxy** (Go only): client and server creation and lifecycle.

The TcpProxy module is deprecated. For new projects, use the [Stream module](./stream) instead.

**Client Pool and Stream** have no standalone FFI bindings yet. The TcpProxy bindings use the Client Pool internally.

## Quick example (Go)

```go
// Initialize an ephemeral client
bindings.InitEphemeral()

// Get our Nym address
addr, _ := bindings.GetSelfAddress()

// Send a message through the Mixnet
bindings.SendMessage(addr, "hello from Go")

// Listen for incoming messages
msg, _ := bindings.ListenForIncoming()
fmt.Println("Received:", msg.Message)

// Reply anonymously via SURBs
bindings.Reply(msg.Sender, "reply from Go")
```

## Quick example (C++)

The C++ bindings use callbacks for return values and a `ReceivedMessage` struct for incoming data:

```cpp
extern "C" {
    struct ReceivedMessage {
        const uint8_t* message;
        size_t size;
        const char* sender_tag;
    };

    void init_logging();
    char init_ephemeral();
    char get_self_address(void (*callback)(const char*));
    char send_message(const char*, const char*);
    char listen_for_incoming(void (*callback)(ReceivedMessage));
    char reply(const char*, const char*);
}

// Get address via callback
char addr[134];
void on_address(const char* s) { strcpy(addr, s); }

// Receive message via callback
char sender_tag[22];
void on_message(ReceivedMessage msg) {
    std::cout << "Received: " << msg.message << std::endl;
    strcpy(sender_tag, msg.sender_tag);
}

int main() {
    init_ephemeral();
    get_self_address(on_address);
    send_message(addr, "hello from C++");
    listen_for_incoming(on_message);
    reply(sender_tag, "reply from C++");
}
```

## Building

Each language has a `build.sh` script that compiles the Rust shared library and generates bindings. See the README in each directory for prerequisites.

## Examples and source

- [Go mixnet example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/go/example.go): init, send, receive, SURB reply
- [Go TcpProxy example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/go/proxy_example.go): proxy client and server with TCP echo
- [C++ example](https://github.com/nymtech/nym/blob/develop/sdk/ffi/cpp/src/main.cpp): same flow using Boost threads
- [`sdk/ffi` source](https://github.com/nymtech/nym/tree/develop/sdk/ffi): full source and build scripts

---
title: Nym TypeScript SDK: Privacy for Web Apps
description: TypeScript SDK for integrating web apps with the Nym mixnet. Covers mixFetch, Mixnet Client, Smart Contracts, and Cosmos Kit with live playground examples.
url: https://nym.com/docs/developers/typescript
---

# TypeScript SDK

The TypeScript SDK lets you build browser-based applications that communicate through the Nym mixnet. Import SDK packages via NPM as you would any other TypeScript library.

The Nym Mixnet routes traffic through multiple nodes with no persistent connections or guaranteed ordering. The SDK abstracts the complexity, but understanding the [underlying model](/developers/rust/tour) helps when debugging.

## Packages

                **mixFetch**

                A drop-in replacement for [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
                that sends HTTP requests over the Nym mixnet

                    <NPMLink packageName={'@nymproject/mix-fetch'} kind={'esm'}/><br/>
                    <NPMLink packageName={'@nymproject/mix-fetch-full-fat'} kind={'esm'} preBundled/><br/>
                    <NPMLink packageName={'@nymproject/mix-fetch-commonjs'} kind={'cjs'}/><br/>

                    **Mixnet Client**

                    Send and receive text and binary messages over the Nym mixnet

                    <NPMLink packageName={'@nymproject/sdk'} kind={'esm'}/><br/>
                    <NPMLink packageName={'@nymproject/sdk-full-fat'} kind={'esm'} preBundled/><br/>
                    <NPMLink packageName={'@nymproject/sdk-commonjs'} kind={'cjs'}/><br/>

                **Nym Smart Contracts**

                Query and execute methods on the smart contracts that run the Nym mixnet

### Which variant should I use?

All packages (except Contract Clients) come in four variants:

- **ESM:** For new projects with current tooling. You may need to [configure your bundler](./typescript/bundling) to handle WASM and web worker components.
- **ESM full-fat:** Pre-bundled with inline WASM and web workers. No bundler config needed.
- **CommonJS:** For older projects using CommonJS. WASM and web workers need to be [bundled](./typescript/bundling/webpack).
- **CommonJS full-fat:** Pre-bundled, works without additional configuration.

All `*-full-fat` variants have large bundle sizes because they include WASM and web workers as inline Base64 strings. Use the standard ESM variant if bundle size matters.

## Installation

### mixFetch

```bash
npm install @nymproject/mix-fetch-full-fat
```

### Mixnet Client

```bash
npm install @nymproject/sdk-full-fat
```

### Nym Smart Contracts

```bash
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate @cosmjs/proto-signing
```

### Install everything

```bash
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate @cosmjs/proto-signing @nymproject/sdk-full-fat @nymproject/mix-fetch-full-fat
```

## Quick start

### mixFetch

Use [`mixFetch`](https://www.npmjs.com/package/@nymproject/mix-fetch) as a drop-in replacement for `fetch` to send HTTP requests over the mixnet:

```ts

// HTTP GET
const response = await mixFetch('https://nym.com');
const html = await response.text();

// HTTP POST
const apiResponse = await mixFetch('https://api.example.com', {
  method: 'POST',
  body: JSON.stringify({ foo: 'bar' }),
  headers: { 'Content-Type': 'application/json' }
});
```

### Mixnet Client

Create a [`Mixnet Client`](https://www.npmjs.com/package/@nymproject/sdk) to send and receive messages through the mixnet:

```js

const nym = await createNymMixnetClient();
const nymApiUrl = 'https://validator.nymtech.net/api';

// Subscribe to incoming messages
nym.events.subscribeToTextMessageReceivedEvent((e) => {
  console.log('Got a message: ', e.args.payload);
});

// Connect to the mixnet
await nym.client.start({ clientId: 'my-app', nymApiUrl });

// Send a message to yourself
const recipient = nym.client.selfAddress();
nym.client.send({ payload: 'Hello mixnet', recipient });
```

### Nym Smart Contracts

Use the [Contract Clients](https://www.npmjs.com/package/@nymproject/contract-clients) to query or execute on Nym smart contracts:

```js

const signer = await DirectSecp256k1HdWallet.fromMnemonic("...");
const accounts = await signer.getAccounts();

const cosmWasmSigningClient = await SigningCosmWasmClient.connectWithSigner(
  "https://rpc.nymtech.net:443", signer
);
const client = new contracts.Mixnet.MixnetClient(
  cosmWasmSigningClient,
  accounts[0].address,
  'n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr'
);

// Delegate 1 NYM to mixnode with id 100
const result = await client.delegateToMixnode(
  { mixId: 100 }, 'auto', undefined,
  [{ amount: `${1_000_000}`, denom: 'unym' }]
);
console.log(`Tx Hash = ${result.transactionHash}`);
```

## Next steps

- **[Step-by-step examples](./typescript/examples):** Full working projects for each package
- **[Live playground](./typescript/playground):** Try the SDK in your browser
- **[Bundling](./typescript/bundling):** Configure Webpack or ESBuild for WASM and web workers
- **[TypeDoc reference](./typescript/api):** generated reference for all packages

---
title: mixFetch Example: Private HTTP Requests
description: Replace browser fetch with mixFetch to route HTTP requests through the Nym mixnet. Covers setup, CA certificates, TLS configuration, and usage examples.
url: https://nym.com/docs/developers/typescript/examples/mix-fetch
---

# mixFetch

An easy way to secure parts or all of your web app is to replace calls to [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) with `mixFetch`. It works the same as vanilla `fetch`: it's a proxied wrapper around the original function.

Things to be aware of:

- **CA certificates** are bundled into the WASM binary at build time. They're updated with each SDK release, so if you hit a certificate error, update to the latest `@nymproject/mix-fetch-full-fat` version.
- **HTTPS and WSS.** When serving your app over HTTPS, the mixnet connection must also use Secure WebSockets to avoid a [mixed content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content) error. Set `forceTls: true` in your `SetupMixFetchOps` config (see below) and the SDK will automatically select a WSS-capable gateway.
- `mixFetch` supports **concurrent requests** (up to 10) to the same or different URLs.

## Environment Setup

Create a new project with Vite:

```bash
npm create vite@latest
```

Choose React + TypeScript, then:

```bash
cd <YOUR_APP>
npm i
npm run dev
```

## Installation

```bash
npm install @nymproject/mix-fetch-full-fat @mui/material @emotion/react @emotion/styled
```

The MUI packages are used by the example UI below. If you only need `mixFetch` itself, install just `@nymproject/mix-fetch-full-fat`.

## Configuration

```ts

const mixFetchOptions: SetupMixFetchOps = {
  clientId: "my-app",
  preferredGateway: "q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1",
  mixFetchOverride: {
    requestTimeoutMs: 60_000,
  },
  forceTls: true, // use Secure WebSockets (required when serving over HTTPS)
};
```

`preferredGateway` is optional. If omitted, the SDK auto-selects a gateway. You can pin a specific one via [Harbourmaster](https://harbourmaster.nymtech.net/).

## Full Example

This example shows explicit initialization via `createMixFetch`, single URL fetch, and concurrent requests. Results appear both in the UI and in a visible log panel.

For this example we use the `full-fat` version of the ESM SDK. If you use the unbundled ESM variant, make sure your [bundler configuration](/developers/typescript/bundling/bundling) copies the WASM and web worker files to the output bundle.

```tsx

const defaultUrl =
  "https://nymtech.net/.wellknown/network-requester/exit-policy.txt";
const args = { mode: "unsafe-ignore-cors" };
const mixFetchOptions: SetupMixFetchOps = {
  clientId: "docs-mixfetch-demo",
  preferredGateway: "q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1",
  mixFetchOverride: {
    requestTimeoutMs: 60_000,
  },
  forceTls: true,
};

// Log entry type for the visible log panel
type LogLevel = "info" | "error" | "send" | "receive";
type LogEntry = { timestamp: string; message: string; level: LogLevel };

const logColors: Record<LogLevel, string> = {
  info: "gray",
  error: "red",
  send: "blue",
  receive: "green",
};

const logLabels: Record<LogLevel, string> = {
  info: "INFO",
  error: "ERROR",
  send: "SEND",
  receive: "RECV",
};

export const MixFetch = () => {
  // MixFetch initialization state
  const [status, setStatus] = useState<"idle" | "starting" | "ready" | "error">("idle");
  const [errorMsg, setErrorMsg] = useState<string | null>(null);

  // Log panel state
  const [logs, setLogs] = useState<LogEntry[]>([]);
  const logEndRef = useRef<HTMLDivElement>(null);

  // Single fetch state
  const [url, setUrl] = useState<string>(defaultUrl);
  const [html, setHtml] = useState<string>();
  const [busy, setBusy] = useState<boolean>(false);

  // Concurrent fetch state
  const [concurrentResults, setConcurrentResults] = useState<string[]>([]);
  const [concurrentBusy, setConcurrentBusy] = useState<boolean>(false);

  // Auto-scroll log panel to bottom
  useEffect(() => {
    logEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [logs]);

  // Helper to add a timestamped log entry
  const addLog = (message: string, level: LogLevel) => {
    const timestamp = new Date().toISOString().substring(11, 23);
    setLogs((prev) => [...prev, { timestamp, message, level }]);
  };

  // Initialize MixFetch explicitly via createMixFetch
  const handleStart = async () => {
    try {
      setStatus("starting");
      setErrorMsg(null);
      addLog("Starting MixFetch...", "info");
      await createMixFetch(mixFetchOptions);
      setStatus("ready");
      addLog("MixFetch is ready!", "info");
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      setStatus("error");
      setErrorMsg(msg);
      addLog(`Error: ${msg}`, "error");
    }
  };

  // Single URL fetch: reuses the existing MixFetch singleton
  const handleFetch = async () => {
    try {
      setBusy(true);
      setHtml(undefined);
      addLog(`Sending request to ${url}...`, "send");
      const response = await mixFetch(url, args, mixFetchOptions);
      const resHtml = await response.text();
      setHtml(resHtml);
      addLog(`Response received (${resHtml.length} bytes)`, "receive");
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      addLog(`Fetch error: ${msg}`, "error");
    } finally {
      setBusy(false);
    }
  };

  // Send 5 concurrent requests to different URLs on the same domain
  const handleConcurrentFetch = async () => {
    const baseUrl = "https://jsonplaceholder.typicode.com/posts/";
    const count = 5;
    try {
      setConcurrentBusy(true);
      setConcurrentResults([]);
      addLog(
        `Starting ${count} concurrent requests to ${baseUrl}1-${count}...`,
        "send",
      );
      const requests = Array.from({ length: count }, (_, i) => {
        const targetUrl = `${baseUrl}${i + 1}`;
        return mixFetch(targetUrl, args, mixFetchOptions)
          .then((res) => res.json())
          .then((json: { id: number; title: string }) => {
            const entry = `[${json.id}] ${json.title}`;
            addLog(entry, "receive");
            return entry;
          });
      });
      const results = await Promise.all(requests);
      setConcurrentResults(results);
      addLog(`All ${count} concurrent requests completed!`, "info");
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      addLog(`Concurrent fetch error: ${msg}`, "error");
    } finally {
      setConcurrentBusy(false);
    }
  };

  const isReady = status === "ready";

  return (

      {/* Start MixFetch */}

            Start MixFetch

          {status === "starting" && <CircularProgress size={20} />}

            {status === "idle" ? "Not started" :
             status === "starting" ? "Starting..." :
             status === "ready" ? "Ready" :
             `Error: ${errorMsg}`}

      {/* Fetch controls: disabled until MixFetch is ready */}

        {/* Single fetch */}

          <TextField
            disabled={busy}
            fullWidth
            label="URL"
            type="text"
            variant="outlined"
            defaultValue={defaultUrl}
            onChange={(e) => setUrl(e.target.value)}
          />

            Fetch

        {busy && <Box mt={2}><CircularProgress /></Box>}
        {html && (
          <>
            <Box mt={2}><strong>Response</strong></Box>

              <Typography fontFamily="monospace" fontSize="small">{html}</Typography>

          </>
        )}

        {/* Concurrent fetch */}

          <strong>Concurrent Requests</strong>

              Send 5 Concurrent Requests (posts/1-5)

        {concurrentBusy && <Box mt={2}><CircularProgress /></Box>}
        {concurrentResults.length > 0 && (

            {concurrentResults.map((result, i) => (
              <Typography key={i} fontFamily="monospace" fontSize="small">{result}</Typography>
            ))}

        )}

      {/* Log Panel */}
      {logs.length > 0 && (

          <strong>Log</strong>
          {logs.map((entry, i) => (

              {entry.timestamp} [{logLabels[entry.level]}] {entry.message}

          ))}

      )}

  );
};
```

---
title: TypeScript Mixnet Client Example
description: Send and receive private messages in the browser using the Nym TypeScript SDK. Includes setup, SURB anonymous replies, and environment configuration.
url: https://nym.com/docs/developers/typescript/examples/mixnet
---

# Mixnet Client

The [`SDK Client`](https://www.npmjs.com/package/@nymproject/sdk) lets you send and receive messages over the Nym mixnet.

The client is message-based: it sends one-way messages to another client's address. Replying can be achieved in two ways:
- Reveal the sender's address to the recipient (as part of the payload)
- Use a SURB (single use reply block) that lets the recipient reply without compromising the identity of either party

## Environment Setup

Create a new project with Vite:

```bash
npm create vite@latest
```

Choose React + TypeScript, then:

```bash
cd <YOUR_APP>
npm i
npm run dev
```

## Installation

```bash
npm install @nymproject/sdk-full-fat
```

## Full Example

This example creates a Mixnet client, connects to a gateway, and provides a UI for sending and receiving messages through the mixnet.

For this example we use the `full-fat` version of the ESM SDK. If you use the unbundled ESM variant, make sure your [bundler configuration](/developers/typescript/bundling/bundling) copies the WASM and web worker files to the output bundle.

```ts copy filename="App.tsx"

  createNymMixnetClient,
  NymMixnetClient,
  Payload,
} from "@nymproject/sdk-full-fat";

const nymApiUrl = "https://validator.nymtech.net/api";

export const Traffic = () => {
  const [nym, setNym] = useState<NymMixnetClient>();
  const [selfAddress, setSelfAddress] = useState<string>();
  const [recipient, setRecipient] = useState<string>();
  const [payload, setPayload] = useState<Payload>();
  const [receivedMessage, setReceivedMessage] = useState<string>();
  const [buttonEnabled, setButtonEnabled] = useState<boolean>(false);

  const init = async () => {
    const client = await createNymMixnetClient();
    setNym(client);

    // start the client and connect to a gateway
    await client?.client.start({
      clientId: crypto.randomUUID(),
      nymApiUrl,
      forceTls: true, // force WSS
    });

    // check when is connected and set the self address
    client?.events.subscribeToConnected((e) => {
      const { address } = e.args;
      setSelfAddress(address);
    });

    // show whether the client is ready or not
    client?.events.subscribeToLoaded((e) => {
      console.log("Client ready: ", e.args);
    });

    // show message payload content when received
    client?.events.subscribeToTextMessageReceivedEvent((e) => {
      console.log(e.args.payload);
      setReceivedMessage(e.args.payload);
    });
  };

  const stop = async () => {
    await nym?.client.stop();
  };

  const send = () =>
    payload && recipient && nym?.client.send({ payload, recipient });

  useEffect(() => {
    init();
    return () => {
      stop();
    };
  }, []);

  useEffect(() => {
    if (recipient && payload) {
      setButtonEnabled(true);
    } else {
      setButtonEnabled(false);
    }
  }, [recipient, payload]);

  if (!nym || !selfAddress) {
    return (

    );
  }

  return (

          <Typography variant="body1">My self address is:</Typography>
          <Typography variant="body1">{selfAddress || "loading"}</Typography>
          <Typography variant="h5">Communication through the Mixnet</Typography>
          <TextField
            type="text"
            placeholder="Recipient Address"
            onChange={(e) => setRecipient(e.target.value)}
            size="small"
          />

              setPayload({ message: e.target.value, mimeType: "text/plain" })
            }
            size="small"
          />
          <Button
            variant="outlined"
            onClick={() => send()}
            disabled={!buttonEnabled}
            sx={{ width: "fit-content" }}
          >
            Send

        {receivedMessage && (

            <Typography variant="h5">Message Received!</Typography>
            <Typography fontFamily="monospace">{receivedMessage}</Typography>

        )}

  );
};
```

If you encounter a Gateway client error that persists even after a hard refresh, open your browser console, navigate to the "Application" tab, and delete the databases listed under "IndexedDB".

---
title: Nym Smart Contract Clients
description: Query and execute on Nym smart contracts using TypeScript contract clients. Covers Mixnet, Coconut, Vesting, Name Service, and other on-chain contracts.
url: https://nym.com/docs/developers/typescript/examples/nym-smart-contracts
---

# Nym Smart Contract Clients

To query or execute on any of the Nym contracts, use the [`Contract Clients`](https://www.npmjs.com/package/@nymproject/contract-clients), which contain read-only query and signing clients for all of Nym's smart contracts.

## Contract Clients

| Client | Functionality | Methods |
| :---: | :---: | :---: |
| Coconut Bandwidth | Manages depositing and release of funds. Tracks double spending. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/CoconutBandwidth.client.ts) |
| Coconut DKG | Allows signers to derive keys for issuing Coconut credentials. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/CoconutDkg.client.ts) |
| Cw3FlexMultisig | Used by the Coconut APIs to issue credentials. [cw3-flex-multisig](https://github.com/CosmWasm/cw-plus/tree/main/contracts/cw3-flex-multisig) backed by cw4. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Cw3FlexMultisig.client.ts) |
| Cw4Group | Used by the Coconut APIs. [Cw4 Group](https://github.com/CosmWasm/cw-plus/tree/main/contracts/cw4-group) stores members with an admin. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Cw4Group.client.ts) |
| Mixnet | Manages the network topology, tracking delegations and rewards. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Mixnet.client.ts) |
| Name Service | Directory of user-defined aliases, analogous to DNS. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/NameService.client.ts) |
| Service Provider Directory | Public directory for registering service providers. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/ServiceProviderDirectory.client.ts) |
| Vesting | Manages NYM token vesting functionality. | [Source](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Vesting.client.ts) |

## Environment Setup

Create a new project with Vite:

```bash
npm create vite@latest
```

Choose React + TypeScript, then:

```bash
cd <YOUR_APP>
npm i
npm run dev
```

## Query Example

### Installation

```bash
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate
```

### Querying the Mixnet Contract

This example uses `MixnetQueryClient` to fetch a paged list of mixnodes from the contract. Create a `settings.ts` file for your network configuration:

```ts filename="settings.ts"
export const settings = {
  url: "wss://rpc.nymtech.net:443",
  mixnetContractAddress: "n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr",
};
```

```ts copy filename="App.tsx"

const getClient = async () => {
  const cosmWasmClient = await SigningCosmWasmClient.connect(settings.url);
  const client = new contracts.Mixnet.MixnetQueryClient(
    cosmWasmClient,
    settings.mixnetContractAddress
  );
  return client;
};

export const Mixnodes = () => {
  const [mixnodes, setMixnodes] = useState<any>();

  const getMixnodes = async () => {
    const client = await getClient();
    const { nodes } = await client.getMixNodesDetailed({});
    setMixnodes(nodes);
  };

  useEffect(() => {
    getMixnodes();
  }, []);

  if (!mixnodes) {
    return (

    );
  }

  return (

      {mixnodes?.length &&
        mixnodes.map((mixnode: any) => (

              {`id: ${mixnode.bond_information.mix_id}`}

            <span>{`owner: ${mixnode.bond_information.owner}`}</span>

        ))}

  );
};
```

## Execute Example

### Installation

```bash
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate @cosmjs/proto-signing
```

### Executing Contract Methods

This example uses `MixnetClient` with a signer to execute methods like delegation.

Update your `settings.ts` to include signing credentials:

```ts filename="settings.ts"
export const settings = {
  url: "wss://rpc.nymtech.net:443",
  mixnetContractAddress: "<ENTER MIXNET CONTRACT ADDRESS>",
  mnemonic: "<ENTER MNEMONIC>",
  address: "<ENTER NYM ADDRESS>",
};
```

```ts copy filename="App.tsx"

export default function Exec() {
  let signer: DirectSecp256k1HdWallet;
  let signerMixnetClient: any;
  let cosmWasmSigningClient: SigningCosmWasmClient;
  let mixId: number;
  let amountToDelegate: string;
  let nodeAddress: string;
  let amountToSend: string;
  let delegations: any;

  async function ExecuteOnNyx() {
    signer = await DirectSecp256k1HdWallet.fromMnemonic(settings.mnemonic, {
      prefix: "n",
    });
    const cosmWasmClient = await SigningCosmWasmClient.connectWithSigner(
      settings.url,
      signer,
      { gasPrice: GasPrice.fromString("0.025unym") }
    );
    cosmWasmSigningClient = cosmWasmClient;

    const mixnetClient = new contracts.Mixnet.MixnetClient(
      cosmWasmSigningClient,
      settings.address,
      settings.mixnetContractAddress
    );
    signerMixnetClient = mixnetClient;
  }

  const getDelegations = async () => {
    if (!signerMixnetClient) return;
    delegations = await signerMixnetClient.getDelegatorDelegations({
      delegator: settings.address,
    });
  };

  const doDelegation = async () => {
    if (!signerMixnetClient) return;
    const res = await signerMixnetClient.delegateToMixnode(
      { mixId },
      "auto",
      undefined,
      [{ amount: `${amountToDelegate}`, denom: "unym" }]
    );
    console.log(res);
  };

  const doUndelegateAll = async () => {
    for (const delegation of delegations.delegations) {
      await signerMixnetClient.undelegateFromMixnode(
        { mixId: delegation.mix_id },
        "auto"
      );
    }
  };

  const doSendTokens = async () => {
    const res = await cosmWasmSigningClient.sendTokens(
      settings.address,
      nodeAddress,
      [{ amount: amountToSend, denom: "unym" }],
      "auto",
      "test sending tokens"
    );
    console.log(res);
  };

  ExecuteOnNyx();
  setTimeout(() => getDelegations(), 1000);

  return (

      <p>Send Tokens</p>
      <input type="string" placeholder="Node Address" onChange={(e) => (nodeAddress = e.target.value)} />
      <input type="number" placeholder="Amount" onChange={(e) => (amountToSend = e.target.value)} />
      <button onClick={() => doSendTokens()}>Send Tokens</button>

      <p>Delegate</p>
      <input type="number" placeholder="Mixnode Id" onChange={(e) => (mixId = +e.target.value)} />
      <input type="number" placeholder="Amount" onChange={(e) => (amountToDelegate = e.target.value)} />
      <button onClick={() => doDelegation()}>Delegate</button>
      <button onClick={() => doUndelegateAll()}>Undelegate All</button>

  );
}
```

---
title: Cosmos Kit
url: https://nym.com/docs/developers/typescript/examples/cosmos-kit
---

# Cosmos Kit

The wonderful people of Cosmology have made some [fantastic components](https://cosmoskit.com/) that can be used with
Nym. These include:

- Using the wallets such as Keplr, Cosmostation and others from your React application;
- Using the [Ledger hardware wallet](https://docs.cosmoskit.com/integrating-wallets/ledger) from your browser;
- Any wallet that supports [Wallet Connect v2.0](https://docs.cosmoskit.com/integrating-wallets/adding-new-wallets);

##### Environment Setup
Begin by creating a directory and configuring your application environment:

```bash
npm create vite@latest
```

During the environment setup, choose React and subsequently opt for Typescript if you want your application to function smoothly following this tutorial. Next, navigate to your application directory and run the following commands:
```bash
cd < YOUR_APP >
npm i
npm run dev
```

##### Installation
Install the required package:
```bash
npm install @cosmos-kit/react @cosmos-kit/keplr @cosmos-kit/ledger chain-registry
```

You need to polyfill some nodejs modules in order to use keplr and ledger wallets by modifying your `vite.config.js` file:
```bash
npm install @esbuild-plugins/node-globals-polyfill
```

```js
// vite.config.js

export default defineConfig({
  plugins: [react()],
  optimizeDeps: {
        esbuildOptions: {
            define: {
                global: 'globalThis'
            },
            plugins: [
                NodeGlobalsPolyfillPlugin({
                    buffer: true
                })
            ]
        }
    }
})
```

Your components have to be wrapped into a [ChainProvider](https://docs.cosmoskit.com/chain-provider),
in order to use the `useChain('nyx')` hook. The nyx chain is provided in the 'chain-registry' NPM package by default.

Now, go to the `src` folder and open your `App.tsx` file to replace all the code with the following, which will allow you to connect and disconnect a Ledger or Keplr wallet to Nyx:

```ts

export const getDoc = (address: string) => {
  const chainId = 'nyx';
  const msg: AminoMsg = {
    type: '/cosmos.bank.v1beta1.MsgSend',
    value: MsgSend.fromPartial({
      fromAddress: address,
      toAddress: 'n1nn8tghp94n8utsgyg3kfttlxm0exgjrsqkuwu9',
      amount: [{ amount: '1000', denom: 'unym' }],
    }),
  };
  const fee = {
    amount: [{ amount: '2000', denom: 'ucosm' }],
    gas: '180000', // 180k
  };
  const memo = 'Use your power wisely';
  const accountNumber = 15;
  const sequence = 16;
  const doc = makeSignDoc([msg], fee, chainId, memo, accountNumber, sequence);
  return doc
};

function MyComponent() {
  const {wallet, address, connect, disconnect, getOfflineSignerAmino } =
  useChain('nyx');

  React.useEffect(() => {
    connect();
    disconnect();
  }, []);

  const sign = async () => {
    if (!address) return
    const doc = getDoc(address);
    return getOfflineSignerAmino().signAmino(address, doc);
  };

  return (

        {wallet &&

          <div>Connected to {wallet?.prettyName} </div>
          <div>Address: <code>{address}</code></div>
        </div>}

      {wallet ? (

          <button onClick={() => disconnect()}>Disconnect wallet</button>

      ) : (

          <button onClick={() => connect()}>Connect wallet</button>

      )}

  );
}

export default function App() {
    const assetsFixedUp = React.useMemo(() => {
    const nyx = assets.find((a) => a.chain_name === 'nyx');
    if (nyx) {
      const nyxCoin = nyx.assets.find((a) => a.name === 'nyx');
      if (nyxCoin) {
        nyxCoin.coingecko_id = 'nyx';
      }
      nyx.assets = nyx.assets.reverse();
    }
    return assets;
  }, [assets]);

  return (
     <ChainProvider
      chains={[chains.find((c) => c.chain_id === 'nyx')!]}
      assetLists={assetsFixedUp}
      wallets={[...ledger, ...keplr]}
      signerOptions={{
        preferredSignType: () => 'amino',
      }}
    >

  )
}
```

---
title: TypeScript SDK Bundling Troubleshooting
description: Fix common bundling issues with the Nym TypeScript SDK: WASM files missing from output, web worker configuration for Webpack and other bundlers.
url: https://nym.com/docs/developers/typescript/bundling/bundling
---

# Troubleshooting

## Bundling issues

### WASM and web worker not included in output bundle (Webpack)

You might need to use the CopyPlugin by adding this to your Webpack config:

```js
const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
    plugins: [
        new CopyPlugin({
            patterns: [
              {
                from: path.resolve(path.dirname(require.resolve('@nymproject/mix-fetch/package.json')), '*.wasm'),
                to: '[name][ext]',
              },
              {
                from: path.resolve(path.dirname(require.resolve('@nymproject/mix-fetch/package.json')), '*worker*.js'),
                to: '[name][ext]',
              },
          ],
        }),
    ],
}
```

`require.resolve('@nymproject/mix-fetch/package.json')` finds the disk location of the Nym SDK package. `path.dirname` resolves the directory, and the `*.wasm` glob matches the WASM files. Use `[name][ext]` to preserve the output filename, because the package expects it to stay the same.

### ESM not supported

If your bundler does not support ECMAScript Modules (ESM), CommonJS packages are supported for most parts of the SDK.

For those that don't have ESM versions, you will need to use a tool like [Babel](https://babeljs.io/) to convert ESM to CommonJS.

### CSP prevents loading

If you are using a `*-full-fat` package, or if you inline WASM or web workers, you may not be able to load them if the [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) prevents WASM from being instantiated from a string.

You'll have to experiment with either adjusting the CSP or use another variant that is unbundled.

## Mixnet client issues

### Insufficient topology error

The mixnet client will complain about insufficient topology in the following cases:
- There are empty mix layers (rare)
- The gateway you've registered with does not appear in the network topology; it is either unbonded or was blacklisted
- The gateway you want to send packets to does not appear in the network topology; it is either unbonded or was blacklisted

To avoid the last two, make sure the gateway you are using is bonded and whitelisted.

### Checking gateway status

Your client address has the format: `client-id.client-dh@gateway-id`

For example: `DpB3cHAchJi...suko.ANNWrvHq...U2Vx@2BuMSfMW...3SEh`

- First part: client's identity key
- Second part: client's Diffie-Hellman key
- After `@`: gateway's identity key. Search for this in the [Nym Explorer](https://nym.com/explorer) to check its status

---
title: Troubleshooting bundling with ESbuild
url: https://nym.com/docs/developers/typescript/bundling/esbuild
---

# Troubleshooting bundling with ESbuild

If you've been following the steps outlined in the Examples section, your development environment should be configured as follows:

#### Environment Setup
Begin by creating a directory and configuring your application environment:

Create your directory and set-up your app environment:
```bash
npm create vite@latest
```
During the environment setup, choose React and subsequently opt for Typescript if you want your application to function smoothly following this tutorial. Next, navigate to your application directory and run the following commands:
```bash
cd < YOUR_APP >
npm i
npm run dev
```

##### Installation
Install the required package:
```bash
npm install @nymproject/< PACKAGE_NAME >
```

    Remember that the CosmosKit example will require you to make use of polyfills.

By implementing the provided code for the various components in the step-by-step examples section, you should be able to set-up and run your application without encountering any bundling challenges!

---
title: Troubleshooting bundling with Webpack
url: https://nym.com/docs/developers/typescript/bundling/webpack
---

# Troubleshooting bundling with Webpack

## Webpack > 5 ESM

For any project using Webpack, you´ll need the following rule in your `webpack.config.js` above version 5:
```json
{
        test: /\.(m?js)$/,
        resolve: {
          fullySpecified: false
        }
}
```

### Create-react-app

#### General cases

If you wish to use Webpack for your app with the code provided in the step-by-step examples section, you'll need to:

```bash
npx create-react-app nymapp --template typescript
cd nymapp
```
You'll then need to install the needed dependencies, head to your app's `App.tsx` file and paste the code provided in the step-by-step section.

#### Contract client

    Using webpack, the `Contract client` for querying or executing might need polyfills. As create-react-app doesn´t allow you access to the Webpack config without ejecting, you'll overwrite it as follow:

##### Install contract-clients dependencies
```bash
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate @cosmjs/proto-signing
```

Head to you app's `App.tsx` file and replace the code by the one provided in the step-by-step examples section.

##### Polyfilling

Copy the following to your terminal and run:

```bash
npm install react-app-rewired
npm install --save-dev crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer process
cat <<EOF > config-overrides.js
const webpack = require('webpack');
const path = require('path')

module.exports = function override(config) {
  const fallback = config.resolve.fallback || {};
  Object.assign(fallback, {
    "crypto": require.resolve("crypto-browserify"),
    "stream": require.resolve("stream-browserify"),
    "assert": require.resolve("assert"),
    "http": require.resolve("stream-http"),
    "https": require.resolve("https-browserify"),
    "os": require.resolve("os-browserify"),
    "url": require.resolve("url")
  })
  config.resolve.fallback = fallback;
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: 'process/browser',
      Buffer: ['buffer', 'Buffer']
    })
  ])
  config.module.rules = (config.module.rules || []).concat([
      {
        test: /\.(m?js)$/,
        resolve: {
          fullySpecified: false
        }
      }
    ])
  return config;
}
EOF
```

#### Edit the `package.json` file as follows:

```json
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
```

---
title: NymVPN CLI: Run NymVPN from the Command Line
description: Install and run NymVPN from the terminal on Linux, macOS, and Windows. Includes ARM64 .deb packages, account setup, tunnel configuration, and gateway selection.
url: https://nym.com/docs/developers/nymvpncli
---

# Nym VPN CLI

This is a short guide to setting up and using the `nym-vpnc` tool, which is used in conjunction with the `nym-vpnd` daemon.

Download and run instructions for the GUIs can be found [here](https://nymvpn.com/en/download/linux).

## Download & Extract Binary
Check the [release page](https://github.com/nymtech/nym-vpn-client/releases/) page for the latest release version and modify the instructions accordingly. These instructions use the latest as of the time of writing.
```sh
wget -q https://github.com/nymtech/nym-vpn-client/releases/download/nym-vpn-core-v1.29.0/nym-vpn-core-v1.29.0_<YOUR_OPERATING_SYSTEM>.tar.gz &&
tar -xzf nym-vpn-core-v1.29.0_<YOUR_OPERATING_SYSTEM>.tar.gz &&
cd nym-vpn-core-v1.29.0_<YOUR_OPERATING_SYSTEM>/ &&
chmod u+x *
```

### Linux ARM64 (.deb)

ARM64 `.deb` packages are available for Linux distributions that support them (e.g. Ubuntu/Debian on Raspberry Pi or ARM servers). Install both the daemon and the client:

```sh
sudo dpkg -i nym-vpnd_<VERSION>_arm64.deb
sudo dpkg -i nym-vpnc_<VERSION>_arm64.deb
```

The `.deb` package installs a systemd service that starts `nym-vpnd` automatically. Verify the service is running:

```sh
service nym-vpnd status
```

You should see output similar to:

```sh
● nym-vpnd.service - nym-vpnd daemon
     Loaded: loaded (/usr/lib/systemd/system/nym-vpnd.service; enabled; preset: enabled)
     Active: active (running)
```

Verify the installed version with `nym-vpnc info`:

```sh
nym-vpnc info
```
```sh
nym-vpnd:
  version: 1.25.0
  build_timestamp (utc): 2026-03-02 16:25:31.229479864 +00:00:00
  triple: aarch64-unknown-linux-gnu
  platform: Ubuntu; Linux (Ubuntu 24.04); aarch64
  git_commit: fce7a84e612b8d2cb48b66695cdaf023d7f9a42b
```

## Build from Source
### Prerequisites
All operating systems require both [Rust](https://www.rust-lang.org/tools/install) and [Go](https://go.dev/doc/install).

**Arch specific packages:**
```sh
yay -S gcc make protobuf base-devel clang
```

**Ubuntu24 specific packages:**
```sh
apt install gcc make protobuf-compiler pkconfig libdbus-1-dev build-essential clang
```

  Older Debian/Ubuntu versions need to manually install `protobuf-compiler` >= v3.21.12

### Clone & `make`
```sh
git clone https://github.com/nymtech/nym-vpn-client.git
cd nym-vpn-client/
make
```

## Start the Daemon

If you installed via `.deb` packages, the daemon is already running as a systemd service. You can check its status with:

```sh
service nym-vpnd status
```

If you are running from pre-built binaries or a source build, start the daemon manually:

```sh
sudo ./PATH/TO/nym-vpnd
```

  Leave the daemon running and run `nym-vpnc` commands in a separate terminal window.

## Account Setup

### Create an Account

Head to [https://nym.com/account/create](https://nym.com/account/create) and obtain a passphrase (mnemonic).

### Log In

Store your account passphrase on this device:

```sh
nym-vpnc account set "<YOUR_PASSPHRASE>"
```

### Check Account Status

Verify that the device is logged in and view account details:

```sh
nym-vpnc account get
```

Example output:

```sh
Account identity: n1wlmrpa7ts7znz7nxvmxevaw65796cr6q6pht69
Canonical Account identity: n1wlmrpa7ts7znz7nxvmxevaw65796cr6q6pht69
Account mode: Some(Api)
Account state: Error(BandwidthExceeded { context: "SYNCING_STATE" })
```

### Account Summary & Balance

```sh
nym-vpnc account summary
nym-vpnc account balance
```

### Account Links

Get URLs for managing your NymVPN account:

```sh
nym-vpnc account links
```

### Forget Account

Remove the stored passphrase, device keys, and local credentials from this device:

```sh
nym-vpnc account forget
```

### Device Information

View the current device identity:

```sh
nym-vpnc device get
```

## Pay as You Go: Decentralized Access to Nym

You can fund your VPN usage directly from your own wallet instead of going through the NymVPN account system. You deposit `$NYM` into the ticketbook smart contract and receive zk-nym ticketbooks that authenticate you on the network.

  If you already have an account stored in `nym-vpnc`, you must remove it first with `nym-vpnc account forget` before setting a new mnemonic.

### Set Your Mnemonic

Store the recovery phrase for your on-chain wallet address (`n1...`) that holds your `$NYM` tokens:

```sh
nym-vpnc account set "<MNEMONIC>" --location blockchain
```

You must fund this address yourself, for example by transferring `$NYM` from an exchange or another wallet. The `--location blockchain` flag tells `nym-vpnc` to use the on-chain wallet directly rather than the NymVPN account system.

### Obtain Ticketbooks

Deposit `$NYM` into the ticketbook smart contract and receive zk-nym credentials:

```sh
nym-vpnc account obtain-ticketbooks --amount 1 --source smartcontract
```

You can omit `--source` to use the default:

```sh
nym-vpnc account obtain-ticketbooks --amount 1
```

The `--amount` flag specifies how many ticketbooks to obtain **per ticket type**. Each request issues one ticketbook for each of the three types listed below, so `--amount 1` produces 3 ticketbooks total and `--amount 2` produces 6.

Each ticketbook contains **50 tickets** and is valid for **7 days**. Each ticketbook costs **75 NYM**, so `--amount 1` deposits **225 NYM** (75 × 3 types) and `--amount 2` deposits **450 NYM**.

| Kind | Ticket size | Ticketbook capacity | Used for |
|------|-------------|---------------------|----------|
| Mixnet Entry | 200 MB | 10 GB (200 MB × 50) | 5-hop mixnet mode |
| WireGuard Entry | 500 MB | 25 GB (500 MB × 50) | 2-hop WireGuard mode (entry side) |
| WireGuard Exit | 500 MB | 25 GB (500 MB × 50) | 2-hop WireGuard mode (exit side) |

  If you only use two-hop (WireGuard) mode, the Mixnet Entry ticketbooks will go unused. There is currently no way to obtain ticketbooks for a single type.

This command:

- Deposits `$NYM` into the ticketbook smart contract (plus a small fee buffer per deposit)
- Requests credential issuance from the decentralised Nym API validators
- Stores the resulting zk-nym ticketbooks locally on the device

### Connect

Connect using the locally stored ticketbooks:

```sh
nym-vpnc connect-v2
```

The CLI uses the ticketbooks to authenticate with entry nodes (gateways) and connect to the Nym network. You will see the connection happening in the `nym-vpnd` logs.

## Tunnel Configuration

Print current tunnel configuration:

```sh
nym-vpnc tunnel get
```

Enable two-hop mode (WireGuard): traffic jumps directly from entry gateway to exit gateway:

```sh
nym-vpnc tunnel set --two-hop on
```

Enable Mixnet (5-hop): disable two-hop to route traffic through the full mixnet for maximum privacy:

```sh
nym-vpnc tunnel set --two-hop off
```

Enable or disable IPv6:

```sh
nym-vpnc tunnel set --ipv6 on
```

Enable censorship circumvention transports (currently QUIC):

```sh
nym-vpnc tunnel set --circumvention-transports on
```

  Run `nym-vpnc tunnel set --help` for all available tunnel options including mixnet timing parameters.

## Gateway Configuration

Set entry and exit gateways bound to specific countries using [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country codes:

```sh
nym-vpnc gateway set --entry-country US --exit-country JP
```

Print current gateway configuration:

```sh
nym-vpnc gateway get
```

Example output:

```sh
Entry point: Country { two_letter_iso_country_code: "US" }
Exit point: Country { two_letter_iso_country_code: "JP" }
Residential exit: off
```

Only use residential exit nodes:

```sh
nym-vpnc gateway set --residential-exit on
```

### List Available Gateways

List available WireGuard gateways (use a wide terminal window for the table output):

```sh
nym-vpnc gateway list wg
```

You can also list mixnet entry and exit gateways:

```sh
nym-vpnc gateway list mixnet-entry
nym-vpnc gateway list mixnet-exit
```

## Connect & Disconnect

Connect using the settings stored in `nym-vpnd`:

```sh
nym-vpnc connect
```

Disconnect:

```sh
nym-vpnc disconnect
```

Reconnect:

```sh
nym-vpnc reconnect
```

Print the current tunnel status:

```sh
nym-vpnc status
```

Continuously stream tunnel status in real time:

```sh
nym-vpnc status --listen
```

## Ad-Block

NymVPN includes a built-in ad-blocker (Brave ad-engine). Ad-blocking is only active while the tunnel is connected.

Enable ad-block:

```sh
nym-vpnc ad-block set enabled
```

Disable ad-block:

```sh
nym-vpnc ad-block set disabled
```

  You can test ad-blocking with [adblock.turtlecute.org](https://adblock.turtlecute.org/). Some browsers cache DNS internally, so toggling ad-block on/off at runtime may not have an immediate effect; a browser restart may be needed. Use `nslookup` or `dig` to verify that domains are being blocked.

## DNS

View current DNS configuration:

```sh
nym-vpnc dns get
nym-vpnc dns get-default
```

Set custom DNS servers:

```sh
nym-vpnc dns set 1.1.1.1 9.9.9.9
nym-vpnc dns enable
```

Disable custom DNS and revert to defaults:

```sh
nym-vpnc dns disable
```

Clear custom DNS servers:

```sh
nym-vpnc dns clear
```

## Local Network Access

Control whether local network (LAN) traffic is allowed while the tunnel is active:

```sh
nym-vpnc lan get
nym-vpnc lan set allow
nym-vpnc lan set block
```

## SOCKS5 Proxy

NymVPN can expose a local SOCKS5 proxy:

```sh
nym-vpnc socks5 enable
nym-vpnc socks5 disable
nym-vpnc socks5 status
```

## Network

View or change the Nym network (requires a daemon restart):

```sh
nym-vpnc network get
nym-vpnc network set mainnet
```

## Diagnostic

Run connectivity diagnostics:

```sh
nym-vpnc diagnostic run
```

## Getting Help

Any `nym-vpnc` command has built-in help. Add `--help` to the end of any command to view available options:

```sh
nym-vpnc --help
nym-vpnc connect --help
nym-vpnc tunnel set --help
```

## Default Config Directories
Configurations are stored in `/etc/nym`. State stored between runs (keys, mnemonic, etc) are stored in `/var/lib/nym-vpnd`.

---
title: Nyx Blockchain & Nym Smart Contracts
description: Developer guide for interacting with the Nyx blockchain via Cosmos SDK. Covers CLI wallet setup, Cosmos Registry, Ledger Live, and RPC node deployment.
url: https://nym.com/docs/developers/chain
---

# Interacting with Nyx Chain and Smart Contracts

There are two options for interacting with the blockchain to send tokens or interact with deployed smart contracts:
* [`Nym-CLI`](./tools/nym-cli) tool
* `nyxd` binary

## Nym-CLI tool (recommended in most cases)
The `nym-cli` tool is a binary offering a simple interface for interacting with deployed smart contract (for instance, bonding and unbonding a Mix Node from the CLI), as well as creating and managing accounts and keypairs, sending tokens, and querying the blockchain.

Instructions on how to do so can be found on the [`nym-cli` docs page](./tools/nym-cli)

## Nyxd binary
The `nyxd` binary, although more complex to compile and use, offers the full range of commands availiable to users of CosmosSDK chains. Use this if you are (e.g.) wanting to perform more granular queries about transactions from the CLI.

You can use the instructions on how to do this on from the [`gaiad` docs page](https://hub.cosmos.network/main/delegators/delegator-guide-cli.html#querying-the-state).

---
title: CLI Wallet
url: https://nym.com/docs/developers/chain/cli-wallet
---

# CLI Wallet

If you have already read our [validator setup and maintenance documentation](../../operators/nodes/validator-setup) you will have seen that we compile and use the `nyxd` binary primarily for our validators. This binary can however be used for many other tasks, such as creating and using keypairs for wallets, or automated setups that require the signing and broadcasting of transactions.

### Using `nyxd` binary as a CLI wallet
You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../../operators/nodes/validator-setup#building-your-validator) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain.

---
title: Cosmos Registry
url: https://nym.com/docs/developers/chain/cosmos-registry
---

# Cosmos Registry
You can find all relevant information (chain info, RPC endpoints, etc) on the [Cosmos Chain Registry](https://github.com/cosmos/chain-registry/tree/master/nyx).

---
title: Ledger Live Support
url: https://nym.com/docs/developers/chain/ledger-live
---

# Ledger Live Support

Use the following instructions to interact with the Nyx blockchain - either with deployed smart contracts, or just to send tokens - using your Ledger device to sign transactions.

## Prerequisites
* Download and install [Ledger Live](https://www.ledger.com/ledger-live).
* Compile the `nyxd` binary as per the instructions [here](../../operators/nodes/validator-setup). Stop after you can successfully run `nyxd` and get the helptext in your console output.

## Prepare your Ledger App
* Plug in your Ledger device
* Install the `Cosmos (ATOM)` app by following the instructions [here](https://hub.cosmos.network/main/resources/ledger.html). This app allows you to interact with **any** Cosmos SDK chain - you can manage your ATOM, OSMOSIS, NYM tokens, etc.
* On the device, navigate to the Cosmos app and open it

## Create a keypair
Add a reference to the ledger device on your local machine by running the following command in the same directory as your `nyxd` binary:

```
nyxd keys add ledger_account --ledger
```

## Command help with `nyxd`
More information about each command is available by consulting the help section (`--help`) at each layer of `nyxd`'s commands:

```
# logging top level command help
nyxd --help

# logging top level command help for transaction commands
nyxd tx --help

# logging top level command help for transaction commands utilising the 'bank' module
nyxd tx bank --help
```

## Sending tokens between addresses
Perform a transaction from the CLI with `nyxd`, appending the `--ledger` option to the command.

As an example, the below command will send 1 `NYM` from the ledger account to the `$DESTINATION_ACCOUNT`:

```
nyxd tx bank send ledger_account $DESTINATION_ACCOOUNT 1000000unym --ledger --node https://rpc.dev.nymte.ch:443
```

> When a command is run, the transaction will appear on the Ledger device and will require physical confirmation from the device before being signed.

## Nym-specific transactions
Nym-specific commands and queries, like bonding a Mix Node or delegating unvested tokens, are available in the `wasm` module, and follow the following pattern:

```
# Executing commands
nyxd tx wasm execute $CONTRACT_ADDRESS $JSON_MSG

# Querying the state of a smart contract
nyxd query wasm contract-state smart $CONTRACT_ADDRESS $JSON_MSG
```

You can find the value of `$CONTRACT_ADDRESS` in the [`network defaults`](https://github.com/nymtech/nym/blob/master/common/network-defaults/src/mainnet.rs) file.

The value of `$JSON_MSG` will be a blog of `json` formatted as defined for each command and query. You can find these definitions for the mixnet smart contract [here](https://github.com/nymtech/nym/blob/master/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs) and for the vesting contract [here](https://github.com/nymtech/nym/blob/master/common/cosmwasm-smart-contracts/vesting-contract/src/messages.rs) under `ExecuteMsg` and `QueryMsg`.

### Example command execution:
#### Delegate to a Mix Node
You can delegate to a Mix Node from the CLI using `nyxd` and signing the transaction with your ledger by filling in the values of this example:
```
CONTRACT_ADDRESS=mixnet_contract_address

./nyxd tx wasm execute $CONTRACT_ADDRESS '{"delegate_to_mixnode":{"mix_identity":"MIX_NODE_IDENTITY","amount":{"amount":"100000000000","denom":"unym"}}}' --ledger --from admin --node https://rpc.dev.nymte.ch:443 --gas-prices 0.025unymt --gas auto -b block
```

> By replacing the value of `CONTRACT_ADDRESS` with the address of the vesting contract, you could use the above command to use tokens held in the vesting contract.

#### Query a vesting schedule
You can query for (e.g.) seeing the current vesting period of an address by filling in the values of the following:
```
CONTRACT_ADDRESS=vesting_contract_address

nyxd query wasm contract-state smart $CONTRACT_ADDRESS '{"get_current_vesting_period"}:{"address": "address_to_query_for"}' --ledger --from admin --node https://rpc.dev.nymte.ch:443 --chain-id qa-net --gas-prices 0.025unymt --gas auto -b block
```

---
title: Run a Nyx RPC Node for the Nym Network
description: Set up and run a dedicated RPC node for the Nyx blockchain. Query network state, serve chain data, and interact with Nym smart contracts programmatically.
url: https://nym.com/docs/developers/chain/rpc-node
---

# RPC Nodes

RPC Nodes (which might otherwise be referred to as 'Lite Nodes' or just 'Full Nodes') differ from Validators in that they hold a copy of the Nyx blockchain, but do **not** participate in consensus / block-production.

You may want to set up an RPC Node for querying the blockchain, or in order to have an endpoint that your app can use to send transactions.

In order to set up an RPC Node, simply follow the instructions to set up a [Validator](../../operators/nodes/validator-setup), but **exclude the `nyxd tx staking create-validator` command**.

If you want to fast-sync your node, check out the Polkachu snapshot and their other [resources](https://polkachu.com/seeds/nym).

---
title: Nym Developer Tools: CLI, Diagnostics & TcpProxy
description: Overview of Nym developer tools including nym-cli for blockchain interaction, diagnostic tool for troubleshooting, and standalone TcpProxy binary downloads.
url: https://nym.com/docs/developers/tools
---

# Tools

Standalone binaries for development and testing that don't require an SDK. Download or compile them and use them directly.

| Tool | Use case |
|---|---|
| [nym-cli](./tools/nym-cli) | Command-line interface for interacting with the Nyx blockchain: querying state, submitting transactions, managing keys. An easier-to-use wrapper around `nyxd`. |
| [Diagnostic Tool](./tools/diagnostic-tool) | Network diagnostic utility for troubleshooting connectivity issues. |
| [Standalone TcpProxy](./tools/standalone-tcpproxy) | Pre-built binaries of the TcpProxy client and server for proxying TCP traffic through the Mixnet. Note: the TcpProxy module is unmaintained; use the [Stream module](./rust/stream) for new projects. |

---
title: Nym CLI: Mixnet & Blockchain Commands
description: Use nym-cli to interact with the Nym mixnet and Nyx blockchain. Manage nodes, delegate stake, and query network state from the command line.
url: https://nym.com/docs/developers/tools/nym-cli
---

# Nym-CLI

This is a CLI tool for interacting with:

* the Nyx blockchain (account management, querying the chain state, etc)
* the smart contracts deployed on Nyx (bonding and un-bonding mixnodes, collecting rewards, etc)

It provides a convenient wrapper around the `nymd` client, and has similar functionality to the `nyxd` binary for querying the chain or executing smart contract methods.

---
title: Usage
url: https://nym.com/docs/developers/tools/nym-cli/usage
---

# Usage

## Building
The `nym-cli` binary can be built by running `cargo build --release` in the `nym/tools/nym-cli` directory.

## Usage
See the [commands](/developers/tools/nym-cli/commands) page for an overview of all command options.

## Staking on someone's behalf (for custodians)

There is a limitation the staking address can only perform the following actions (and are visible via the Nym Wallet:

- Bond on the gateway's or Mix Node's behalf.
- Delegate or Un-delegate (to a Mix Node in order to begin receiving rewards)
- Claiming the rewards on the account

```admonish note title=""
The staking address has no ability to withdraw any coins from the parent's account.
```

The staking address must maintain the same level of security as the parent mnemonic; while the parent mnemonic's delegations and bonding events will be visible to the parent owner, the staking address will be the only account capable of undoing the bonding and delegating from the Mix Nodes or gateway.

Query for staking on behalf of someone else
```
./nym-cli --mnemonic <staking address mnemonic>  mixnet delegators delegate --mix-id <input> --identity-key <input> --amount <input>
```

---
title: `nym-cli` Binary Commands (Autogenerated)
url: https://nym.com/docs/developers/tools/nym-cli/commands
---

# `nym-cli` Binary Commands (Autogenerated)

These docs are autogenerated by the [`autodocs`](https://github.com/nymtech/nym/tree/max/new-docs-framework/documentation/autodoc) script.
```sh
A client for interacting with Nym smart contracts and the Nyx blockchain

Usage: nym-cli [OPTIONS] <COMMAND>

Commands:
  account           Query and manage Nyx blockchain accounts
  signature         Sign and verify messages
  ecash             Ecash related stuff
  block             Query chain blocks
  cosmwasm          Manage and execute WASM smart contracts
  tx                Query for transactions
  vesting-schedule  Create and query for a vesting schedule
  mixnet            Manage your mixnet infrastructure, delegate stake or query the directory
  generate-fig      Generates shell completion
  help              Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `account`
```sh
Query and manage Nyx blockchain accounts

Usage: nym-cli account [OPTIONS]
       nym-cli account <COMMAND>

Commands:
  create         Create a new mnemonic - note, this account does not appear on the chain until the account id is used in a transaction
  balance        Gets the balance of an account
  pub-key        Gets the public key of an account
  send           Sends tokens to another account
  send-multiple  Batch multiple token sends
  help           Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `account create`
```sh
Create a new mnemonic - note, this account does not appear on the chain until the account id is used in a transaction

Usage: nym-cli account create [OPTIONS]

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
      --word-count <WORD_COUNT>

  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `account balance`
```sh
Gets the balance of an account

Usage: nym-cli account balance [OPTIONS] [ADDRESS]

Arguments:
  [ADDRESS]  The account address to get the balance for

Options:
      --denom <DENOM>
          Optional currency to show balance for
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --hide-denom
          Optionally hide the denom
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --raw
          Show as a raw value
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `account pub-key`
```sh
Gets the public key of an account

Usage: nym-cli account pub-key [OPTIONS] [ADDRESS]

Arguments:
  [ADDRESS]  Optionally, show the public key for this account address, otherwise generate the account address from the mnemonic

Options:
      --from-mnemonic
          If set, get the public key from the mnemonic, rather than querying for it
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `account send`
```sh
Sends tokens to another account

Usage: nym-cli account send [OPTIONS] <RECIPIENT> <AMOUNT>

Arguments:
  <RECIPIENT>  The recipient account address
  <AMOUNT>     Amount to transfer in micro denomination (e.g. unym or unyx)

Options:
      --denom <DENOM>
          Override the denomination
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --memo <MEMO>

      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `account send-multiple`
```sh
Batch multiple token sends

Usage: nym-cli account send-multiple [OPTIONS] --input <INPUT>

Options:
      --memo <MEMO>

      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --input <INPUT>
          Input file path (CSV format) with account/amount pairs to send
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --output <OUTPUT>
          An output file path (CSV format) to create or append a log of results to
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `signature`
```sh
Sign and verify messages

Usage: nym-cli signature [OPTIONS]
       nym-cli signature <COMMAND>

Commands:
  sign    Sign a message
  verify  Verify a message
  help    Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `signature sign`
```sh
Sign a message

Usage: nym-cli signature sign [OPTIONS] <MESSAGE>

Arguments:
  <MESSAGE>  The message to sign

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `signature verify`
```sh
Verify a message

Usage: nym-cli signature verify [OPTIONS] <PUBLIC_KEY_OR_ADDRESS> <SIGNATURE_AS_HEX> <MESSAGE>

Arguments:
  <PUBLIC_KEY_OR_ADDRESS>  The public key of the account, or the account id to query for a public key (NOTE: the account must have signed a message stored on the chain for the public key record to exist)
  <SIGNATURE_AS_HEX>       The signature to verify as hex
  <MESSAGE>                The message to verify as a string

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `ecash`
```sh
Ecash related stuff

Usage: nym-cli ecash [OPTIONS]
       nym-cli ecash <COMMAND>

Commands:
  issue-ticket-book
  recover-ticket-book
  import-ticket-book
  generate-ticket
  import-coin-index-signatures
  import-expiration-date-signatures
  import-master-verification-key
  help                               Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `ecash issue-ticket-book`
```sh
Usage: nym-cli ecash issue-ticket-book [OPTIONS] <--client-config <CLIENT_CONFIG>|--output-file <OUTPUT_FILE>>

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
      --ticketbook-type <TICKETBOOK_TYPE>
          Specify which type of ticketbook should be issued [default: v1-mixnet-entry]
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --client-config <CLIENT_CONFIG>
          Config file of the client that is supposed to use the credential
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --output-file <OUTPUT_FILE>
          Output file for the ticketbook
      --bs58-output
          Specifies whether the output file should use binary or bs58 encoded data
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --include-expiration-date-signatures
          Specifies whether the file output should contain expiration date signatures
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --include-coin-index-signatures
          Specifies whether the file output should contain coin index signatures
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
      --include-master-verification-key
          Specifies whether the file output should contain master verification key
      --bs58-encoded-client-secret <BS58_ENCODED_CLIENT_SECRET>
          Secret value that's used for deriving underlying ecash keypair
  -h, --help
          Print help
```

## `ecash recover-ticket-book`
```sh
Usage: nym-cli ecash recover-ticket-book [OPTIONS] --client-config <CLIENT_CONFIG>

Options:
      --client-config <CLIENT_CONFIG>
          Config file of the client that is supposed to use the credential
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `ecash import-ticket-book`
```sh
Usage: nym-cli ecash import-ticket-book [OPTIONS] --credentials-store <CREDENTIALS_STORE> <--credential-data <CREDENTIAL_DATA>|--credential-path <CREDENTIAL_PATH>> <--standalone|--full>

Options:
      --credentials-store <CREDENTIALS_STORE>
          Config file of the client that is supposed to use the credential
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --credential-data <CREDENTIAL_DATA>
          Explicitly provide the encoded credential data (as base58)
      --credential-path <CREDENTIAL_PATH>
          Specifies the path to file containing binary credential data
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --standalone
          Specifies whether we're attempting to import a standalone ticketbook (i.e. serialised `IssuedTicketBook`)
      --full
          Specifies whether we're attempting to import full ticketboot (i.e. one that **might** contain required global signatures; that is serialised `ImportableTicketBook`)
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `coconut`

## `coconut generate-freepass`

## `coconut issue-credentials`

## `coconut recover-credentials`

## `coconut import-credential`

## `block`
```sh
Query chain blocks

Usage: nym-cli block [OPTIONS]
       nym-cli block <COMMAND>

Commands:
  get             Gets a block's details and prints as JSON
  time            Gets the block time at a height
  current-height  Gets the current block height
  help            Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `block get`
```sh
Gets a block's details and prints as JSON

Usage: nym-cli block get [OPTIONS] <HEIGHT>

Arguments:
  <HEIGHT>  The block height

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `block time`
```sh
Gets the block time at a height

Usage: nym-cli block time [OPTIONS] <HEIGHT>

Arguments:
  <HEIGHT>  The block height

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `block current-height`
```sh
Gets the current block height

Usage: nym-cli block current-height [OPTIONS]

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `cosmwasm`
```sh
Manage and execute WASM smart contracts

Usage: nym-cli cosmwasm [OPTIONS]
       nym-cli cosmwasm <COMMAND>

Commands:
  upload                 Upload a smart contract WASM blob
  init                   Init a WASM smart contract
  generate-init-message  Generate an instantiate message
  migrate                Migrate a WASM smart contract
  execute                Execute a WASM smart contract method
  raw-contract-state     Obtain raw contract state of a cosmwasm smart contract
  help                   Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `cosmwasm upload`
```sh
Upload a smart contract WASM blob

Usage: nym-cli cosmwasm upload [OPTIONS] --wasm-path <WASM_PATH>

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
      --wasm-path <WASM_PATH>

  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --memo <MEMO>

      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `cosmwasm init`
```sh
Init a WASM smart contract

Usage: nym-cli cosmwasm init [OPTIONS] --init-message <INIT_MESSAGE> <CODE_ID>

Arguments:

Options:
      --memo <MEMO>

      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --label <LABEL>

      --init-message <INIT_MESSAGE>

      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --admin <ADMIN>

      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --funds <FUNDS>
          Amount to supply as funds in micro denomination (e.g. unym or unyx)
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --funds-denom <FUNDS_DENOM>
          Set the denomination for the funds
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `cosmwasm generate-init-message`
```sh
Generate an instantiate message

Usage: nym-cli cosmwasm generate-init-message [OPTIONS]
       nym-cli cosmwasm generate-init-message <COMMAND>

Commands:
  ecash-bandwidth
  coconut-dkg
  mixnet
  multisig
  vesting
  help             Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `cosmwasm migrate`
```sh
Migrate a WASM smart contract

Usage: nym-cli cosmwasm migrate [OPTIONS] --code-id <CODE_ID> <CONTRACT_ADDRESS>

Arguments:

Options:
      --code-id <CODE_ID>

      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --memo <MEMO>

      --init-message <INIT_MESSAGE>

      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `cosmwasm execute`
```sh
Execute a WASM smart contract method

Usage: nym-cli cosmwasm execute [OPTIONS] <CONTRACT_ADDRESS> <JSON_ARGS> [FUNDS]

Arguments:
  <CONTRACT_ADDRESS>  The address of contract to execute
  <JSON_ARGS>         JSON encoded method arguments
  [FUNDS]             Amount to supply as funds in micro denomination (e.g. unym or unyx)

Options:
      --memo <MEMO>

      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --funds-denom <FUNDS_DENOM>
          Set the denomination for the funds
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `tx`
```sh
Query for transactions

Usage: nym-cli tx [OPTIONS]
       nym-cli tx <COMMAND>

Commands:
  get    Get a transaction by hash or block height
  query  Query for transactions
  help   Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `tx get`
```sh
Get a transaction by hash or block height

Usage: nym-cli tx get [OPTIONS] <TX_HASH>

Arguments:
  <TX_HASH>  The transaction hash

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `tx query`
```sh
Query for transactions

Usage: nym-cli tx query [OPTIONS] <QUERY>

Arguments:
  <QUERY>  The query to execute

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `vesting-schedule`
```sh
Create and query for a vesting schedule

Usage: nym-cli vesting-schedule [OPTIONS]
       nym-cli vesting-schedule <COMMAND>

Commands:
  create           Creates a vesting schedule
  query            Query for vesting schedule
  vested-balance   Get the amount that has vested and is free for withdrawal, delegation or bonding
  withdraw-vested  Withdraw vested tokens (note: the available amount excludes anything delegated or bonded before or after vesting)
  help             Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `vesting-schedule create`
```sh
Creates a vesting schedule

Usage: nym-cli vesting-schedule create [OPTIONS] --address <ADDRESS> --amount <AMOUNT>

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
      --periods-seconds <PERIODS_SECONDS>

  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --number-of-periods <NUMBER_OF_PERIODS>

      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --start-time <START_TIME>

      --address <ADDRESS>

      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --amount <AMOUNT>

      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --staking-address <STAKING_ADDRESS>

      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
      --pledge-cap <PLEDGE_CAP>
          Pledge cap as either absolute uNYM value or percentage, floats need to be in the 0.0 to 1.0 range and will be parsed as percentages, integers will be parsed as uNYM
  -h, --help
          Print help
```

## `vesting-schedule query`
```sh
Query for vesting schedule

Usage: nym-cli vesting-schedule query [OPTIONS] [ADDRESS]

Arguments:
  [ADDRESS]  Optionally, the account address to get the balance for

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `vesting-schedule vested-balance`
```sh
Get the amount that has vested and is free for withdrawal, delegation or bonding

Usage: nym-cli vesting-schedule vested-balance [OPTIONS] [ADDRESS]

Arguments:
  [ADDRESS]  Optionally, the account address to get the balance for

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `vesting-schedule withdraw-vested`
```sh
Withdraw vested tokens (note: the available amount excludes anything delegated or bonded before or after vesting)

Usage: nym-cli vesting-schedule withdraw-vested [OPTIONS] <AMOUNT>

Arguments:
  <AMOUNT>  Amount to transfer in micro denomination (e.g. unym or unyx)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `mixnet`
```sh
Manage your mixnet infrastructure, delegate stake or query the directory

Usage: nym-cli mixnet [OPTIONS]
       nym-cli mixnet <COMMAND>

Commands:
  query       Query the mixnet directory
  delegators  Manage your delegations
  operators   Manage a mixnode or gateway you operate
  help        Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `mixnet query`
```sh
Query the mixnet directory

Usage: nym-cli mixnet query [OPTIONS]
       nym-cli mixnet query <COMMAND>

Commands:
  mixnodes  Query mixnodes
  gateways  Query gateways
  help      Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `mixnet delegators`
```sh
Manage your delegations

Usage: nym-cli mixnet delegators [OPTIONS]
       nym-cli mixnet delegators <COMMAND>

Commands:
  list                       Lists current delegations
  rewards                    Manage rewards from delegations
  delegate                   Delegate to a mixnode
  delegate-multi             Perform bulk delegations from an input file
  undelegate                 Undelegate from a mixnode
  delegate-vesting           Delegate to a mixnode with locked tokens
  undelegate-vesting         Undelegate from a mixnode (when originally using locked tokens)
  migrate-vested-delegation  Migrate the delegation to use liquid tokens
  help                       Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `mixnet operators`
```sh
Manage a mixnode or gateway you operate

Usage: nym-cli mixnet operators [OPTIONS]
       nym-cli mixnet operators <COMMAND>

Commands:
  nymnode       Manage your Nym Node
  mixnode       Manage your legacy mixnode
  gateway       Manage your legacy gateway
  identity-key  Sign messages using your private identity key
  help          Print this message or the help of the given subcommand(s)

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `generate-fig`
```sh
Generates shell completion

Usage: nym-cli generate-fig [OPTIONS]

Options:
      --mnemonic <MNEMONIC>
          Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC.
  -c, --config-env-file <CONFIG_ENV_FILE>
          Overrides configuration as a file of environment variables. Note: individual env vars take precedence over this file.
      --nyxd-url <NYXD_URL>
          Overrides the nyxd URL provided either as an environment variable NYXD_VALIDATOR or in a config file
      --nym-api-url <NYM_API_URL>
          Overrides the validator API URL provided either as an environment variable API_VALIDATOR or in a config file
      --mixnet-contract-address <MIXNET_CONTRACT_ADDRESS>
          Overrides the mixnet contract address provided either as an environment variable or in a config file
      --vesting-contract-address <VESTING_CONTRACT_ADDRESS>
          Overrides the vesting contract address provided either as an environment variable or in a config file
  -h, --help
          Print help
```

## `generate-fig `

---
title: Diagnostic Tool
url: https://nym.com/docs/developers/tools/diagnostic-tool
---

# Diagnostic Tool

The Diagnostic Tool is a standalone binary designed to perform various network tests, including DNS, HTTP, and gateway connectivity tests. This tool helps diagnose connectivity issues and provides insights into network performance.

It’s also possible to run it within the daemon with the same CLI interface.

## Download Binary

To get `nym-diagnostic` follow these steps:

###### 1. Download `nym-vpn-core`
- Navigate to [github.com/nymtech/nym-vpn-client/releases](https://github.com/nymtech/nym-vpn-client/releases)
- Find latest `nym-vpn-core-<VERSION>`
- Download version for your system

###### 2. Install or extract and make executable

- If you downloaded `.deb` installer, install it with this command:
```sh
sudo dpkg -i <FILE_NAME>
```

- If you downloaded `.tar.gz`, in terminal you can extract the file with
```sh
tar -xvf <FILE_NAME>
```

- Navigate inside the directory and make executable:
```sh
cd nym-vpn-core-<VERSION>
chmod +x ./*
```
</ Steps>

## CLI Usage

The Diagnostic Tool can be executed from the command line interface (CLI). Below are the usage instructions and options available. Read in the chapter [*Tests Performed*](#tests-performed) about the purpose and outcome of these commands.

### Command Syntax

```sh
./nym-diagnostic [command] [options]
./nym-vpnc diagnostic [command] [options]
```

#### `run` command arguments

The most useful command is `run`, here are the options for that command:

```sh
-h, --help      Display help information and exit.
--skip-dns      Skip the DNS tests
--skip-http     Skip the HTTP tests
--gateway <ID_KEY>  Run the gateway connectivity test on the given gateway. Skip those tests if not provided
-v, --verbose   Enable verbose output for detailed logging.
```

#### `register` command arguments

Command `register` requires valid credential. Here are the options for that command:

```sh
--gateway <ID_KEY>    Register to the given gateway
--storage-path    Path to the directory containing the credentials database. If it is not valid registration will be skipped.
--skip-wireguard  Skip Wireguard tests
```

### Command Examples

- Run all tests on a gateway:
```sh
./nym-diagnostic run --gateway <ID_KEY>
```

- Run the DNS tests only:
```sh
./nym-diagnostic run --skip-http
```

- Register to a gateway:
```sh
sudo ./nym-diagnostic register --gateway <ID_KEY> --storage-path /var/lib/nym-vpnd/mainnet
# sudo is required to read the database
```

- You can also run DNS and HTTP tests from `nym-vpnc` (installation [here](/developers/nymvpncli)):
```sh
./nym-vpnc diagnostic run​
```

## Tests Performed

The Diagnostic Tool runs the following tests:

### 1. DNS Test

- **Purpose**: To check the resolution DNS availability.
- **Process**: We try to resolve all the domain names present in a given nym network environment with different DNS configurations
- **Output**: Displays the resolved IP address and the time taken for the resolution.

### 2. HTTP Test

- **Purpose**: To verify the accessibility of the NymVPN API.
- **Process**: The tool query the `health` endpoint as well as the `nodes/described` endpoint.
- **Output**: Displays the response of the `health` endpoint, the time skew and the number of nodes in the network (sanity check)

### 3. Gateway Test

- **Purpose**: To check the connectivity to a given gateway.
- **Process**: The tool fetches information about the gateway, then establishes a TCP connection, upgrades it to WS and sends a request
- **Output**: Display the gateway reported information, the status of the connections and the WS response.

### 4. Registration Test

- **Purpose:** To check the correctness of the registration process.
- **Process:** The tool tries to build a mixnet client to the provided gateway and then tries to register to the entry authenticator
- **Output:** Display the status of the different steps
- **Caveat:** This test requires a credential to be spent, which is why it is available as a separate command only

### 5. Wireguard Test

- **Purpose:** To check the soundness of a wireguard connection
- **Process:** The tool uses the registration data from the previous step to establish a wireguard connection and ping an IP.
- **Output:** Display the ping RTTs and any error that might have happened

## Reports

Reports are logged in a JSON format and also returned by the commands for a future use

---
title: Standalone TcpProxy Binaries
url: https://nym.com/docs/developers/tools/standalone-tcpproxy
---

# Standalone TcpProxy Binaries

**Deprecated.** The TcpProxy module is no longer actively developed. The [Stream module](/developers/rust/stream) provides the same functionality (familiar `AsyncRead`/`AsyncWrite` I/O over the Mixnet) with a simpler API, multiplexed connections, and sequence-based message reordering. Use Streams for new projects.

Standalone versions of the `TcpProxyClient` and `TcpProxyServer` [sdk module](/developers/rust/tcpproxy) can be found [here](https://github.com/nymtech/standalone-tcp-proxies/tree/main).

These might be an easy way for developers to start proxying their traffic throught the mixnet and understanding the sort of latency they should expect, and whether their application can currently tolerate it. They might also prove useful for server setups where several components are being run via init scripts, and the addition of a separate process is acceptable.

## Build
```shell
cargo build --release
```

## Use
```shell
» ./target/release/proxy_server --help
Usage: proxy_server [OPTIONS] --upstream-tcp-address <UPSTREAM_TCP_ADDRESS>

Options:
  -u, --upstream-tcp-address <UPSTREAM_TCP_ADDRESS>
          Upstream address of the server process we want to proxy traffic to e.g. 127.0.0.1:9067
  -c, --config-dir <CONFIG_DIR>
          Config directory [default: /tmp/nym-tcp-proxy-server]
  -e, --env-path <ENV_PATH>
          Optional env filepath - if none is supplied then the proxy defaults to using mainnet else just use a path to one of the supplied files in envs/ e.g. ./envs/sandbox.env
  -h, --help
```

```shell
» ./target/release/proxy_client --help
Usage: proxy_client [OPTIONS] --server-address <SERVER_ADDRESS>

Options:
      --close-timeout <CLOSE_TIMEOUT>
          Send timeout in seconds [default: 30]
  -s, --server-address <SERVER_ADDRESS>
          Nym address of the NymProxyServer e.g. EjYsntVxxBJrcRugiX5VnbKMbg7gyBGSp9SLt7RgeVFV.EzRtVdHCHoP2ho3DJgKMisMQ3zHkqMtAFAW4pxsq7Y2a@Hs463Wh5LtWZUNyAmt4trcCbNVsuUhry1wpEXpVnAAfn
      --listen-address <LISTEN_ADDRESS>
          Listen address [default: 127.0.0.1]
      --listen-port <LISTEN_PORT>
          Listen port [default: 8080]
  -e, --env-path <ENV_PATH>
          Optional env filepath - if none is supplied then the proxy defaults to using mainnet else just use a path to one of the supplied files in envs/ e.g. ./envs/sandbox.env
      --client-pool-reserve <CLIENT_POOL_RESERVE>
          How many clients to have running in reserve for quick access by incoming connections [default: 2]
  -h, --help
          Print help
```

## Run
```shell
# set up the server on your remote machine, listening on the port your upstream process is expecting to communicate on (e.g. 127.0.0.1:9067).
# this will log the Nym address of the Nym Proxy Server to pass to the proxy_client
./target/release/proxy_server -u <UPSTREAM_TCP_ADDRESS>

# start your proxy client with the address of the server client. by default this listens on 127.0.0.1:8080
./target/release/proxy_client --server-address <SERVER_NYM_ADDRESS>

# now start your client process, directing its traffic to the listen port of your nym proxy client process. all traffic will now be proxied through the mixnet.
```

> You can run on another network by downloading on of the [env files](https://github.com/nymtech/nym/tree/nym-binaries-v2024.12-aero/envs) and passing that to both clients with `-e <PATH_TO_ENV_FILE>`

### A Note on Switching Networks
If you are running the `proxy_server` binary on one network and then switch to another, make sure to either specify a new env-specific directory for key and surb storage, or remove the existing one, before running the binary. Since the `proxy_client` relies on ephemeral clients, then this is not a problem for this binary.

---
title: Socks5 Client (Standalone)
url: https://nym.com/docs/developers/clients/socks5
---

# Socks5 Client (Standalone)

> This client can also be utilised via the [Rust SDK](/developers/rust).

Many existing applications are able to use either the SOCKS4, SOCKS4A, or SOCKS5 proxy protocols. If you want to send such an application's traffic through the mixnet, you can use the `nym-socks5-client` to bounce network traffic through the Nym network, like this:

```mermaid
flowchart TB
    subgraph Local Machine[Local Machine]
        A[Application Logic]
        B[Nym Socks5 Client]
    end
    A <-->|Bytes| B
    B <-->|Sphinx Packets| EG

    subgraph Mixnet Nodes[Mixnet Nodes]
        EG[/Entry Gateway/]
        M{Mix Nodes 1..3}
        ExG[\Exit Gateway\]
    end
    EG <-->|Sphinx Packets| M
    M <-->|Sphinx Packets| ExG

    subgraph External Systems
        C[Blockchain RPC]
        D[Mail Server]
        E[Message Server]
        F[etc]
    end
    C <-->|Bytes| ExG
    D <-->|Bytes| ExG
    E <-->|Bytes| ExG
    F <-->|Bytes| ExG
```

There are 2 pieces of software that work together to send SOCKS traffic through the mixnet: the `nym-socks5-client`, and a `nym-node` running as an Exit Gateway.

> The functionality performed by the Exit Gateway was previously performed by the `nym-network-requester`: this functionality has been migrated into the Exit Gateway mode of the `nym-node`.

The `nym-socks5-client` allows you to do the following from your local machine:
* Take a TCP data stream from a application that can send traffic via SOCKS5.
* Chop up the TCP stream into multiple Sphinx packets, assigning sequence numbers to them, while leaving the TCP connection open for more data
* Send the Sphinx packets through the Nym Network. Packets are shuffled and mixed as they transit the mixnet.

The `nym-node` then reassembles the original TCP stream using the packets' sequence numbers, and make the intended request. It will then chop up the response into Sphinx packets and send them back through the mixnet to your `nym-socks5-client`. The application will then receive its data, without even noticing that it wasn't talking to a "normal" SOCKS5 proxy!

---
title: Client setup
url: https://nym.com/docs/developers/clients/socks5/setup
---

# Client setup

## Download or compile socks5 client

If you are using OSX or a Debian-based operating system, you can download the `nym-socks5-client` binary from our [Github releases page](https://github.com/nymtech/nym/releases).

If you are using a different operating system, or want to build from source, simply use `cargo build --release` from the root of the Nym monorepo.
## Viewing command help

You can check that your binaries are properly compiled with:

```
./nym-socks5-client --help
```

You can check the necessary parameters for the available commands by running:

```
./nym-socks5-client <COMMAND> --help
```

## Initialising a new client instance
Before you can use the client, you need to initalise a new instance of it, which can be done with the following command:

```
./nym-socks5-client init --id docs-example --use-reply-surbs true --provider Entztfv6Uaz2hpYHQJ6JKoaCTpDL5dja18SuQWVJAmmx.Cvhn9rBJw5Ay9wgHcbgCnVg89MPSV5s2muPV2YF1BXYu@Fo4f4SQLdoyoGkFae5TpVhRVoXCF8UiypLVGtGjujVPf
```

The `--id` in the example above is a local identifier so that you can name your clients and keep track of them on your local system; it is **never** transmitted over the network.

The `--use-reply-surbs` field denotes whether you wish to send [SURBs](/network/mixnet-mode/anonymous-replies) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with versions of the pre-smoosh `nym-network-requester` binary which will soon be deprecated.

The `--provider` field needs to be filled with the Nym address of an Exit Gateway that can make network requests on your behalf. You can select one from the [mixnet explorer](https://nym.com/explorer) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).

## Choosing a Gateway
By default - as in the example above - your client will choose a random gateway to connect to.

However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client:
* If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`.
* You can also choose a gateway based on its location relative to your client. This can be done by appending the `--latency-based-selection` flag to your `init` command. This command means that to select a gateway, your client will:
	* fetch a list of all availiable gateways
	* send few ping messages to all of them, and measure response times.
	* create a weighted distribution to randomly choose one, favouring ones with lower latency.

You can select one from the [mixnet explorer](https://nym.com/explorer) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).

> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms

---
title: Usage
url: https://nym.com/docs/developers/clients/socks5/usage
---

# Usage

## Run
You can run the initialised client by doing this:

```
./nym-socks5-client run --id docs-example
```

## Automating your socks5 client with systemd
Create a service file for the socks5 client at `/etc/systemd/system/nym-socks5-client.service`:

```ini
[Unit]
Description=Nym Socks5 Client
StartLimitInterval=350
StartLimitBurst=10

[Service]
User=nym # replace this with whatever user you wish
LimitNOFILE=65536
ExecStart=/home/nym/nym-socks5-client run --id <your_id>
KillSignal=SIGINT
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
```

Now enable and start your socks5 client:

```
systemctl enable nym-socks5-client.service
systemctl start nym-socks5-client.service
# you can always check your socks5 client has succesfully started with:
systemctl status nym-socks5-client.service
```

## Using your Socks5 Client
After completing the steps above, your local Socks5 Client will be listening on `localhost:1080` ready to proxy traffic to the Network Requester set as the `--provider` when initialising.

When trying to connect your app, generally the proxy settings are found in `settings->advanced` or `settings->connection`.

Here is an example of setting the proxy connecting in Blockstream Green:

![Blockstream Green settings](/images/developers/blockstream-green.gif)

Most wallets and other applications work the same way: find the network proxy settings and enter the proxy url (host: **localhost**, port: **1080**).

In some other applications, this might be written as **localhost:1080** if there's only one proxy entry field.

## Useful Commands
**no-banner**

Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment.

**build-info**

A `build-info` command prints the build information like commit hash, rust version, binary version just like what command `--version` does. However, you can also specify an `--output=json` flag that will format the whole output as a json, making it an order of magnitude easier to parse.

---
title: Config
url: https://nym.com/docs/developers/clients/socks5/config
---

# Config

## Default Config Directories
When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/socks5-clients/<client-name>/`.

```
tree $HOME/<user>/.nym/socks5-clients/docs-example
├── config
│   └── config.toml
└── data
    ├── ack_key.pem
    ├── credentials_database.db
    ├── gateway_shared.pem
    ├── persistent_reply_store.sqlite
    ├── private_encryption.pem
    ├── private_identity.pem
    ├── public_encryption.pem
    └── public_identity.pem

```

The `config.toml` file contains client configuration options, while the two `pem` files contain client key information.

The generated files contain the client name, public/private keypairs, and gateway address. The name `<client_id>` in the example above is just a local identifier so that you can name your clients.

## Configuring your client for Docker
By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`.

You can set this via the `--host` flag during either the `init` or `run` commands.

Alternatively, a custom host can be set in the `config.toml` file under the `socket` section. If you do this, remember to restart your client process.

---
title: `nym-socks5-client` Binary Commands (Autogenerated)
url: https://nym.com/docs/developers/clients/socks5/commands
---

# `nym-socks5-client` Binary Commands (Autogenerated)

These docs are autogenerated by the [`autodocs`](https://github.com/nymtech/nym/tree/max/new-docs-framework/documentation/autodoc) script.
```sh
A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address

Usage: nym-socks5-client [OPTIONS] <COMMAND>

Commands:
  init               Initialise a Nym client. Do this first!
  run                Run the Nym client with provided configuration client optionally overriding set parameters
  ecash              Ecash-related functionalities
  list-gateways      List all registered with gateways
  add-gateway        Add new gateway to this client
  switch-gateway     Change the currently active gateway. Note that you must have already registered with the new gateway!
  build-info         Show build information of this binary
  completions        Generate shell completions
  generate-fig-spec  Generate Fig specification
  help               Print this message or the help of the given subcommand(s)

Options:
  -c, --config-env-file <CONFIG_ENV_FILE>  Path pointing to an env file that configures the client
      --no-banner                          Flag used for disabling the printed banner in tty
  -h, --help                               Print help
  -V, --version                            Print version
```

## `init`
```sh
Initialise a Nym client. Do this first!

Usage: nym-socks5-client init [OPTIONS] --id <ID> --provider <PROVIDER>

Options:
      --id <ID>
          Id of client we want to create config for

      --gateway <GATEWAY>
          Id of the gateway we are going to connect to

      --force-tls-gateway
          Specifies whether the client will attempt to enforce tls connection to the desired gateway

      --latency-based-selection
          Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly

      --nym-apis <NYM_APIS>
          Comma separated list of rest endpoints of the API validators

      --provider <PROVIDER>
          Address of the socks5 provider to send messages to

      --use-reply-surbs <USE_REPLY_SURBS>
          Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs.

          Note that some service providers might not support this.

          [possible values: true, false]

  -p, --port <PORT>
          Port for the socket to listen on in all subsequent runs

      --host <HOST>
          The custom host on which the socks5 client will be listening for requests

  -o, --output <OUTPUT>
          [default: text]
          [possible values: text, json]

  -h, --help
          Print help (see a summary with '-h')
```

## `run`
```sh
Run the Nym client with provided configuration client optionally overriding set parameters

Usage: nym-socks5-client run [OPTIONS] --id <ID>

Options:
      --id <ID>
          Id of client we want to create config for

      --gateway <GATEWAY>
          Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened

      --nym-apis <NYM_APIS>
          Comma separated list of rest endpoints of the API validators

      --use-anonymous-replies <USE_ANONYMOUS_REPLIES>
          Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs.

          Note that some service providers might not support this.

          [possible values: true, false]

      --provider <PROVIDER>
          Address of the socks5 provider to send messages to

  -p, --port <PORT>
          Port for the socket to listen on

      --host <HOST>
          The custom host on which the socks5 client will be listening for requests

  -h, --help
          Print help (see a summary with '-h')
```

## `import-credential`

## `list-gateways`
```sh
List all registered with gateways

Usage: nym-socks5-client list-gateways [OPTIONS] --id <ID>

Options:
      --id <ID>          Id of client we want to list gateways for
  -o, --output <OUTPUT>  [default: text] [possible values: text, json]
  -h, --help             Print help
```

## `add-gateway`
```sh
Add new gateway to this client

Usage: nym-socks5-client add-gateway [OPTIONS] --id <ID>

Options:
      --id <ID>                  Id of client we want to add gateway for
      --gateway-id <GATEWAY_ID>  Explicitly specify id of the gateway to register with. If unspecified, a random gateway will be chosen instead
      --force-tls-gateway        Specifies whether the client will attempt to enforce tls connection to the desired gateway
      --latency-based-selection  Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly
      --set-active               Specify whether this new gateway should be set as the active one
      --nym-apis <NYM_APIS>      Comma separated list of rest endpoints of the API validators
  -o, --output <OUTPUT>          [default: text] [possible values: text, json]
  -h, --help                     Print help
```

## `build-info`
```sh
Show build information of this binary

Usage: nym-socks5-client build-info [OPTIONS]

Options:
  -o, --output <OUTPUT>  [default: text] [possible values: text, json]
  -h, --help             Print help
```
Example output:
```sh

Binary Name:        nym-socks5-client
Build Timestamp:    2024-12-18T17:33:13.184930493Z
Build Version:      1.1.45
Commit SHA:         b628a5f8148f74c646915292c8b6dc0a46202a27
Commit Date:        2024-12-13T11:49:27.000000000+01:00
Commit Branch:      master
rustc Version:      1.84.0-nightly
rustc Channel:      nightly
cargo Profile:      release

```

## `completions`
```sh
Generate shell completions

Usage: nym-socks5-client completions <SHELL>

Arguments:
  <SHELL>  [possible values: bash, elvish, fish, power-shell, zsh]

Options:
  -h, --help  Print help
```

## `generate-fig-spec`
```sh
Generate Fig specification

Usage: nym-socks5-client generate-fig-spec

Options:
  -h, --help  Print help
```
Example output:
```sh
const completion: Fig.Spec = {
  name: "nym-socks5-client",
  description: "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address",
  subcommands: [
    {
      name: "init",
      description: "Initialise a Nym client. Do this first!",
      options: [
        {
          name: "--id",
          description: "Id of client we want to create config for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway",
          description: "Id of the gateway we are going to connect to",
          isRepeatable: true,
          args: {
            name: "gateway",
            isOptional: true,
          },
        },
        {
          name: "--nyxd-urls",
          description: "Comma separated list of rest endpoints of the nyxd validators",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "nyxd_urls",
            isOptional: true,
          },
        },
        {
          name: "--nym-apis",
          description: "Comma separated list of rest endpoints of the API validators",
          isRepeatable: true,
          args: {
            name: "nym_apis",
            isOptional: true,
          },
        },
        {
          name: "--custom-mixnet",
          description: "Path to .json file containing custom network specification",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "custom_mixnet",
            isOptional: true,
            template: "filepaths",
          },
        },
        {
          name: "--enabled-credentials-mode",
          description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "enabled_credentials_mode",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: "--stats-reporting-address",
          description: "Sets the address to report statistics",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "stats_reporting_address",
            isOptional: true,
          },
        },
        {
          name: "--provider",
          description: "Address of the socks5 provider to send messages to",
          isRepeatable: true,
          args: {
            name: "provider",
          },
        },
        {
          name: "--use-reply-surbs",
          description: "Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs",
          isRepeatable: true,
          args: {
            name: "use_reply_surbs",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: ["-p", "--port"],
          description: "Port for the socket to listen on in all subsequent runs",
          isRepeatable: true,
          args: {
            name: "port",
            isOptional: true,
          },
        },
        {
          name: "--host",
          description: "The custom host on which the socks5 client will be listening for requests",
          isRepeatable: true,
          args: {
            name: "host",
            isOptional: true,
          },
        },
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: "--force-tls-gateway",
          description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
        },
        {
          name: "--latency-based-selection",
          description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
          exclusiveOn: [
            "--gateway",
          ],
        },
        {
          name: "--fastmode",
          description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
        },
        {
          name: "--no-cover",
          description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
        },
        {
          name: ["-h", "--help"],
          description: "Print help (see more with '--help')",
        },
      ],
    },
    {
      name: "run",
      description: "Run the Nym client with provided configuration client optionally overriding set parameters",
      options: [
        {
          name: "--id",
          description: "Id of client we want to create config for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway",
          description: "Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened",
          isRepeatable: true,
          args: {
            name: "gateway",
            isOptional: true,
          },
        },
        {
          name: "--nyxd-urls",
          description: "Comma separated list of rest endpoints of the nyxd validators",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "nyxd_urls",
            isOptional: true,
          },
        },
        {
          name: "--nym-apis",
          description: "Comma separated list of rest endpoints of the API validators",
          isRepeatable: true,
          args: {
            name: "nym_apis",
            isOptional: true,
          },
        },
        {
          name: "--custom-mixnet",
          description: "Path to .json file containing custom network specification",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "custom_mixnet",
            isOptional: true,
            template: "filepaths",
          },
        },
        {
          name: "--enabled-credentials-mode",
          description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "enabled_credentials_mode",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: "--stats-reporting-address",
          description: "Sets the address to report statistics",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "stats_reporting_address",
            isOptional: true,
          },
        },
        {
          name: "--use-anonymous-replies",
          description: "Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs",
          isRepeatable: true,
          args: {
            name: "use_anonymous_replies",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: "--provider",
          description: "Address of the socks5 provider to send messages to",
          isRepeatable: true,
          args: {
            name: "provider",
            isOptional: true,
          },
        },
        {
          name: ["-p", "--port"],
          description: "Port for the socket to listen on",
          isRepeatable: true,
          args: {
            name: "port",
            isOptional: true,
          },
        },
        {
          name: "--host",
          description: "The custom host on which the socks5 client will be listening for requests",
          isRepeatable: true,
          args: {
            name: "host",
            isOptional: true,
          },
        },
        {
          name: "--geo-routing",
          description: "Set geo-aware mixnode selection when sending mixnet traffic, for experiments only",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "geo_routing",
            isOptional: true,
          },
        },
        {
          name: "--fastmode",
          description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
        },
        {
          name: "--no-cover",
          description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
        },
        {
          name: "--medium-toggle",
          description: "Enable medium mixnet traffic, for experiments only. This includes things like disabling cover traffic, no per hop delays, etc",
        },
        {
          name: "--outfox",
        },
        {
          name: ["-h", "--help"],
          description: "Print help (see more with '--help')",
        },
      ],
    },
    {
      name: "ecash",
      description: "Ecash-related functionalities",
      subcommands: [
        {
          name: "show-ticket-books",
          description: "Display information associated with the imported ticketbooks,",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to display the ticketbook information",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: ["-o", "--output"],
              isRepeatable: true,
              args: {
                name: "output",
                isOptional: true,
                suggestions: [
                  "text",
                  "json",
                ],
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-ticket-book",
          description: "Import a pre-generated ticketbook",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the credential",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--credential-data",
              description: "Explicitly provide the encoded credential data (as base58)",
              isRepeatable: true,
              args: {
                name: "credential_data",
                isOptional: true,
              },
            },
            {
              name: "--credential-path",
              description: "Specifies the path to file containing binary credential data",
              isRepeatable: true,
              args: {
                name: "credential_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: "--standalone",
              description: "Specifies whether we're attempting to import a standalone ticketbook (i.e. serialised `IssuedTicketBook`)",
            },
            {
              name: "--full",
              description: "Specifies whether we're attempting to import full ticketboot (i.e. one that **might** contain required global signatures; that is serialised `ImportableTicketBook`)",
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-coin-index-signatures",
          description: "Import coin index signatures needed for ticketbooks",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the signatures",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--client-config",
              description: "Config file of the client that is supposed to use the signatures",
              isRepeatable: true,
              args: {
                name: "client_config",
                template: "filepaths",
              },
            },
            {
              name: "--signatures-data",
              description: "Explicitly provide the encoded signatures data (as base58)",
              isRepeatable: true,
              args: {
                name: "signatures_data",
                isOptional: true,
              },
            },
            {
              name: "--signatures-path",
              description: "Specifies the path to file containing binary signatures data",
              isRepeatable: true,
              args: {
                name: "signatures_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-expiration-date-signatures",
          description: "Import expiration date signatures needed for ticketbooks",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the signatures",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--client-config",
              description: "Config file of the client that is supposed to use the signatures",
              isRepeatable: true,
              args: {
                name: "client_config",
                template: "filepaths",
              },
            },
            {
              name: "--signatures-data",
              description: "Explicitly provide the encoded signatures data (as base58)",
              isRepeatable: true,
              args: {
                name: "signatures_data",
                isOptional: true,
              },
            },
            {
              name: "--signatures-path",
              description: "Specifies the path to file containing binary signatures data",
              isRepeatable: true,
              args: {
                name: "signatures_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-master-verification-key",
          description: "Import master verification key needed for ticketbooks",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the key",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--client-config",
              description: "Config file of the client that is supposed to use the key",
              isRepeatable: true,
              args: {
                name: "client_config",
                template: "filepaths",
              },
            },
            {
              name: "--key-data",
              description: "Explicitly provide the encoded key data (as base58)",
              isRepeatable: true,
              args: {
                name: "key_data",
                isOptional: true,
              },
            },
            {
              name: "--key-path",
              description: "Specifies the path to file containing binary key data",
              isRepeatable: true,
              args: {
                name: "key_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "help",
          description: "Print this message or the help of the given subcommand(s)",
          subcommands: [
            {
              name: "show-ticket-books",
              description: "Display information associated with the imported ticketbooks,",
            },
            {
              name: "import-ticket-book",
              description: "Import a pre-generated ticketbook",
            },
            {
              name: "import-coin-index-signatures",
              description: "Import coin index signatures needed for ticketbooks",
            },
            {
              name: "import-expiration-date-signatures",
              description: "Import expiration date signatures needed for ticketbooks",
            },
            {
              name: "import-master-verification-key",
              description: "Import master verification key needed for ticketbooks",
            },
            {
              name: "help",
              description: "Print this message or the help of the given subcommand(s)",
            },
          ],
        },
      ],
      options: [
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "list-gateways",
      description: "List all registered with gateways",
      options: [
        {
          name: "--id",
          description: "Id of client we want to list gateways for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "add-gateway",
      description: "Add new gateway to this client",
      options: [
        {
          name: "--id",
          description: "Id of client we want to add gateway for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway-id",
          description: "Explicitly specify id of the gateway to register with. If unspecified, a random gateway will be chosen instead",
          isRepeatable: true,
          args: {
            name: "gateway_id",
            isOptional: true,
          },
        },
        {
          name: "--nym-apis",
          description: "Comma separated list of rest endpoints of the API validators",
          isRepeatable: true,
          args: {
            name: "nym_apis",
            isOptional: true,
          },
        },
        {
          name: "--custom-mixnet",
          description: "Path to .json file containing custom network specification",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "custom_mixnet",
            isOptional: true,
            template: "filepaths",
          },
        },
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: "--force-tls-gateway",
          description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
        },
        {
          name: "--latency-based-selection",
          description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
          exclusiveOn: [
            "--gateway-id",
          ],
        },
        {
          name: "--set-active",
          description: "Specify whether this new gateway should be set as the active one",
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "switch-gateway",
      description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
      options: [
        {
          name: "--id",
          description: "Id of client we want to list gateways for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway-id",
          description: "Id of the gateway we want to switch to",
          isRepeatable: true,
          args: {
            name: "gateway_id",
          },
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "build-info",
      description: "Show build information of this binary",
      options: [
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "completions",
      description: "Generate shell completions",
      options: [
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
      args: {
        name: "shell",
        suggestions: [
          "bash",
          "elvish",
          "fish",
          "power-shell",
          "zsh",
        ],
      },
    },
    {
      name: "generate-fig-spec",
      description: "Generate Fig specification",
      options: [
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "help",
      description: "Print this message or the help of the given subcommand(s)",
      subcommands: [
        {
          name: "init",
          description: "Initialise a Nym client. Do this first!",
        },
        {
          name: "run",
          description: "Run the Nym client with provided configuration client optionally overriding set parameters",
        },
        {
          name: "ecash",
          description: "Ecash-related functionalities",
          subcommands: [
            {
              name: "show-ticket-books",
              description: "Display information associated with the imported ticketbooks,",
            },
            {
              name: "import-ticket-book",
              description: "Import a pre-generated ticketbook",
            },
            {
              name: "import-coin-index-signatures",
              description: "Import coin index signatures needed for ticketbooks",
            },
            {
              name: "import-expiration-date-signatures",
              description: "Import expiration date signatures needed for ticketbooks",
            },
            {
              name: "import-master-verification-key",
              description: "Import master verification key needed for ticketbooks",
            },
          ],
        },
        {
          name: "list-gateways",
          description: "List all registered with gateways",
        },
        {
          name: "add-gateway",
          description: "Add new gateway to this client",
        },
        {
          name: "switch-gateway",
          description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
        },
        {
          name: "build-info",
          description: "Show build information of this binary",
        },
        {
          name: "completions",
          description: "Generate shell completions",
        },
        {
          name: "generate-fig-spec",
          description: "Generate Fig specification",
        },
        {
          name: "help",
          description: "Print this message or the help of the given subcommand(s)",
        },
      ],
    },
  ],
  options: [
    {
      name: ["-c", "--config-env-file"],
      description: "Path pointing to an env file that configures the client",
      isRepeatable: true,
      args: {
        name: "config_env_file",
        isOptional: true,
        template: "filepaths",
      },
    },
    {
      name: "--no-banner",
      description: "Flag used for disabling the printed banner in tty",
    },
    {
      name: ["-h", "--help"],
      description: "Print help",
    },
    {
      name: ["-V", "--version"],
      description: "Print version",
    },
  ],
};

export default completion;
```

---
title: WebSocket Client (Standalone)
url: https://nym.com/docs/developers/clients/websocket
---

# WebSocket Client (Standalone)

> This client can also be used via the [Rust SDK](../rust) and [Go/C++ FFI](../rust/ffi).

The standalone WebSocket client connects to the Nym Mixnet and exposes a WebSocket interface on localhost, allowing applications in any language to send and receive messages through the Mixnet.

This is useful if you're building an application in a language other than TypeScript or Rust and cannot use one of the SDKs directly. Your application connects to the local WebSocket, and the client handles Sphinx packet construction, gateway registration, and key management.

## Download or compile

Pre-built binaries for macOS and Debian-based Linux are available on the [GitHub releases page](https://github.com/nymtech/nym/releases). Look for the `nym-client` binary.

To build from source:

```bash
git clone https://github.com/nymtech/nym.git
cd nym
cargo build --release -p nym-client
```

The binary will be at `target/release/nym-client`.

## Initialize and run

```bash
# Create a new client identity
./nym-client init --id my-client

# Start the client
./nym-client run --id my-client
```

The client prints its Nym address on startup and opens a WebSocket on `ws://127.0.0.1:1977`.

## Sending and receiving

Connect to `ws://127.0.0.1:1977` from your application. Messages are JSON-formatted:

**Send a message:**
```json
{
  "type": "send",
  "message": "hello",
  "recipient": "<recipient-nym-address>"
}
```

**Receive messages:** The client pushes incoming messages to your WebSocket connection as they arrive through the Mixnet.

## Source code

The client source is in the [Nym monorepo](https://github.com/nymtech/nym/tree/master/clients/native).

---
title: Setup & Run
url: https://nym.com/docs/developers/clients/websocket/setup
---

# Setup & Run

## Viewing command help

You can check that your binaries are properly compiled with:

```
./nym-client --help
```

The two most important commands you will issue to the client are:

* `init` - initalise a new client instance.
* `run` - run a mixnet client process.

You can check the necessary parameters for the available commands by running:

```
./nym-client <command> --help
```

## Initialising your client

Before you can use the client, you need to initalise a new instance of it. Each instance of the client has its own public/private keypair, and connects to its own gateway node. Taken together, these 3 things (public/private keypair + gateway node identity key) make up an app's identity.

Initialising a new client instance can be done with the following command:

```
./nym-client init --id example-client
```

The `--id` in the example above is a local identifier so that you can name your clients; it is **never** transmitted over the network.

There is an optional `--gateway` flag that you can use if you want to use a specific gateway. The supplied argument is the `Identity Key` of the gateway you wish to use, which can be found on the [mixnet explorer](https://nym.com/explorer). Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/)

Not passing this argument will randomly select a gateway for your client.

## Running your client
You can run the initalised client by doing this:

```
./nym-client run --id example-client
```

When you run the client, it immediately starts generating (fake) cover traffic and sending it to the mixnet.

When the client is first started, it will reach out to the Nym network's validators, and get a list of available Nym nodes (gateways, mixnodes, and validators). We call this list of nodes the network _topology_. The client does this so that it knows how to connect, register itself with the network, and know which mixnodes it can route Sphinx packets through.

---
title: Using Your Client
url: https://nym.com/docs/developers/clients/websocket/usage
---

# Using Your Client
The Nym native client exposes a websocket interface that your code connects to. The **default** websocket port is `1977`, you can override that in the client config if you want.

Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening for incoming messages.

## Message Requests
There are a number of message types that you can send up the websocket as defined [here](https://github.com/nymtech/nym/blob/master/clients/native/websocket-requests/src/responses.rs#L48).

### Getting your own address
When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files <!--add link -->. If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:

```json
{
  "type": "selfAddress"
}
```

You'll receive a response of the format:

```json
{
  "type": "selfAddress",
  "address": "your address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
}
```

See [here](https://github.com/nymtech/nym/blob/93cc281abc2cc951023b51746fa6f2ead1f56c46/clients/native/examples/python-examples/websocket/textsend.py#L16C9-L16C9) for an example of this being used.

> Note that all the pieces of native client example code begin with printing the selfAddress. Examples exist for Rust, Go, Javascript, and Python.

### Sending text
If you want to send text information through the mixnet, format a message like this one and poke it into the websocket:

```json
{
  "type": "send",
  "message": "the message",
  "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
}
```

In some applications, e.g. where people are chatting with friends who they know, you might want to include unencrypted reply information in the message field. This provides an easy way for the receiving chat to then turn around and send a reply message:

```json
{
  "type": "send",
  "message": {
    "sender": "198427b63ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
    "chatMessage": "hi julia!"
  },
  "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
}
```

**If that fits your security model, good. However, will probably be the case that you want to send anonymous replies using Single Use Reply Blocks (SURBs)**.

You can read more about SURBs [here](/network/mixnet-mode/anonymous-replies) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**.

Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the final destination of. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client.

```json
{
    "type": "sendAnonymous",
    "message": "something you want to keep secret",
    "recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
    "replySurbs": 20 // however many reply SURBs to send along with your message
}
```

See ['Replying to SURB Messages'](#replying-to-surb-messages) below for an example of how to deal with incoming messages that have SURBs attached.

Deciding on the amount of SURBs to generate and send along with outgoing messages depends on the expected size of the reply. You might want to send a lot of SURBs in order to make sure you get your response as quickly as possible (but accept the minor additional latency when sending, as your client has to generate and encrypt the packets), or you might just send a few (e.g. 20) and then if your response requires more SURBs, send them along, accepting the additional latency in getting your response.

### Sending binary data
You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded
Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information.

> As a response the `native-client` will send a `ServerResponse` to be decoded. See [Message Responses](#message-responses) below for more.

You can find examples of sending and receiving binary data in the [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust.

### Replying to SURB messages
Each bucket of `replySURBs`, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them in a situation where multiple clients are sending requests to a single service.

Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message)

```json
{
    "type": "reply",
    "message": "reply you also want to keep secret",
    "senderTag": "the sender tag you parsed from the incoming message"
}
```

### Error messages
Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format:

```json
{
  "type": "error",
  "message": "string message"
}
```

### LaneQueueLength
This is currently only used in the [Socks Client](../socks5) to keep track of the number of Sphinx packets waiting to be sent to the mixnet via being slotted amongst cover traffic. As this value becomes larger, the client signals to the application it should slow down the speed with which it writes to the proxy. This is to stop situations arising whereby an app connected to the client appears as if it has sent (e.g.) a bunch of messages and is awaiting a reply, when they in fact have not been sent through the mixnet yet.

## Message Responses
Responses to your messages are defined [here](https://github.com/nymtech/nym/blob/master/clients/native/websocket-requests/src/responses.rs#L47):

```rust
#[derive(Debug)]
pub enum ServerResponse {
    Received(ReconstructedMessage),
    SelfAddress(Box<Recipient>),
    LaneQueueLength { lane: u64, queue_length: usize },
    Error(error::Error),
}
```

---
title: Configuration
url: https://nym.com/docs/developers/clients/websocket/config
---

# Configuration

## Default listening port
The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want.

You can either set this via the `--port` flag at `init` or `run`, or you can manually edit `~/.nym/clients/<CLIENT-ID>/config/config.toml`.

> Remember to restart your client if you change your listening port via editing your config file.

## Choosing a Gateway
By default your client will choose a random gateway to connect to.

However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client:
* If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`.
* You can also choose a gateway based on its location relative to your client. This can be done by appending the `--latency-based-routing` flag to your `init` command. This command means that to select a gateway, your client will:
    * fetch a list of all available gateways
    * send few ping messages to all of them, and measure response times.
    * create a weighted distribution to randomly choose one, favouring ones with lower latency.

> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms

## Configuring your client
When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/clients/<client-name>/`.

```
tree $HOME/<user>/.nym/clients/example-client
├── config
│   └── config.toml
└── data
    ├── ack_key.pem
    ├── gateway_shared.pem
    ├── private_encryption.pem
    ├── private_identity.pem
    ├── public_encryption.pem
    └── public_identity.pem
```

The `config.toml` file contains client configuration options, while the two `pem` files contain client key information.

The generated files contain the client name, public/private keypairs, and gateway address. The name `<client_id>` in the example above is just a local identifier so that you can name your clients.

### Configuring your client for Docker
By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`.

You can set this via the `--host` flag during either the `init` or `run` commands.

Alternatively, a custom host can be set in the `config.toml` file under the `socket` section. If you do this, remember to restart your client process.

---
title: Examples
url: https://nym.com/docs/developers/clients/websocket/examples
---

# Examples
The Nym monorepo includes websocket client example code for Rust, Go, Javacript, and Python, all of which can be found [here](https://github.com/nymtech/nym/tree/master/clients/native/examples).

> Rust users can run the examples with `cargo run --example <rust_file>.rs`, as the examples are not organised in the same way as the other examples, due to already being inside a Cargo project.

All of these code examples will do the following:
* connect to a running websocket client on port `1977`
* format a message to send in either JSON or Binary format. Nym messages have defined JSON formats.
* send the message into the websocket. The native client packages the message into a Sphinx packet and sends it to the mixnet
* wait for confirmation that the message hit the native client
* wait to receive messages from other Nym apps

By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store.

<!-- THIS PAGE IS NOT WORKING AT THE MOMENT:
> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nym.com/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal.
-->

---
title: `nym-client` Binary Commands (Autogenerated)
url: https://nym.com/docs/developers/clients/websocket/commands
---

# `nym-client` Binary Commands (Autogenerated)

These docs are autogenerated by the [`autodocs`](https://github.com/nymtech/nym/tree/max/new-docs-framework/documentation/autodoc) script.
```sh
Implementation of the Nym Client

Usage: nym-client [OPTIONS] <COMMAND>

Commands:
  init               Initialise a Nym client. Do this first!
  run                Run the Nym client with provided configuration client optionally overriding set parameters
  ecash              Ecash-related functionalities
  list-gateways      List all registered with gateways
  add-gateway        Add new gateway to this client
  switch-gateway     Change the currently active gateway. Note that you must have already registered with the new gateway!
  build-info         Show build information of this binary
  completions        Generate shell completions
  generate-fig-spec  Generate Fig specification
  help               Print this message or the help of the given subcommand(s)

Options:
  -c, --config-env-file <CONFIG_ENV_FILE>  Path pointing to an env file that configures the client
      --no-banner                          Flag used for disabling the printed banner in tty
  -h, --help                               Print help
  -V, --version                            Print version
```

## `init`
```sh
Initialise a Nym client. Do this first!

Usage: nym-client init [OPTIONS] --id <ID>

Options:
      --id <ID>
          Id of client we want to create config for
      --gateway <GATEWAY>
          Id of the gateway we are going to connect to
      --force-tls-gateway
          Specifies whether the client will attempt to enforce tls connection to the desired gateway
      --latency-based-selection
          Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly
      --nym-apis <NYM_APIS>
          Comma separated list of rest endpoints of the API validators
      --disable-socket <DISABLE_SOCKET>
          Whether to not start the websocket [possible values: true, false]
  -p, --port <PORT>
          Port for the socket (if applicable) to listen on in all subsequent runs
      --host <HOST>
          Ip for the socket (if applicable) to listen for requests
  -o, --output <OUTPUT>
          [default: text] [possible values: text, json]
  -h, --help
          Print help
```

## `run`
```sh
Run the Nym client with provided configuration client optionally overriding set parameters

Usage: nym-client run [OPTIONS] --id <ID>

Options:
      --id <ID>
          Id of client we want to create config for
      --gateway <GATEWAY>
          Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened
      --nym-apis <NYM_APIS>
          Comma separated list of rest endpoints of the API validators
      --disable-socket <DISABLE_SOCKET>
          Whether to not start the websocket [possible values: true, false]
  -p, --port <PORT>
          Port for the socket to listen on
      --host <HOST>
          Ip for the socket (if applicable) to listen for requests
  -h, --help
          Print help
```

## `import-credential`

## `list-gateways`
```sh
List all registered with gateways

Usage: nym-client list-gateways [OPTIONS] --id <ID>

Options:
      --id <ID>          Id of client we want to list gateways for
  -o, --output <OUTPUT>  [default: text] [possible values: text, json]
  -h, --help             Print help
```

## `switch-gateway`
```sh
Change the currently active gateway. Note that you must have already registered with the new gateway!

Usage: nym-client switch-gateway --id <ID> --gateway-id <GATEWAY_ID>

Options:
      --id <ID>                  Id of client we want to list gateways for
      --gateway-id <GATEWAY_ID>  Id of the gateway we want to switch to
  -h, --help                     Print help
```

## `build-info`
```sh
Show build information of this binary

Usage: nym-client build-info [OPTIONS]

Options:
  -o, --output <OUTPUT>  [default: text] [possible values: text, json]
  -h, --help             Print help
```
Example output:
```sh

Binary Name:        nym-client
Build Timestamp:    2024-12-18T17:33:13.184930493Z
Build Version:      1.1.45
Commit SHA:         b628a5f8148f74c646915292c8b6dc0a46202a27
Commit Date:        2024-12-13T11:49:27.000000000+01:00
Commit Branch:      master
rustc Version:      1.84.0-nightly
rustc Channel:      nightly
cargo Profile:      release

```

## `completions`
```sh
Generate shell completions

Usage: nym-client completions <SHELL>

Arguments:
  <SHELL>  [possible values: bash, elvish, fish, power-shell, zsh]

Options:
  -h, --help  Print help
```

## `generate-fig-spec`
```sh
Generate Fig specification

Usage: nym-client generate-fig-spec

Options:
  -h, --help  Print help
```
Example output:
```sh
const completion: Fig.Spec = {
  name: "nym-native-client",
  description: "Implementation of the Nym Client",
  subcommands: [
    {
      name: "init",
      description: "Initialise a Nym client. Do this first!",
      options: [
        {
          name: "--id",
          description: "Id of client we want to create config for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway",
          description: "Id of the gateway we are going to connect to",
          isRepeatable: true,
          args: {
            name: "gateway",
            isOptional: true,
          },
        },
        {
          name: "--nyxd-urls",
          description: "Comma separated list of rest endpoints of the nyxd validators",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "nyxd_urls",
            isOptional: true,
          },
        },
        {
          name: "--nym-apis",
          description: "Comma separated list of rest endpoints of the API validators",
          isRepeatable: true,
          args: {
            name: "nym_apis",
            isOptional: true,
          },
        },
        {
          name: "--custom-mixnet",
          description: "Path to .json file containing custom network specification",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "custom_mixnet",
            isOptional: true,
            template: "filepaths",
          },
        },
        {
          name: "--enabled-credentials-mode",
          description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "enabled_credentials_mode",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: "--stats-reporting-address",
          description: "Sets the address to report statistics",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "stats_reporting_address",
            isOptional: true,
          },
        },
        {
          name: "--disable-socket",
          description: "Whether to not start the websocket",
          isRepeatable: true,
          args: {
            name: "disable_socket",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: ["-p", "--port"],
          description: "Port for the socket (if applicable) to listen on in all subsequent runs",
          isRepeatable: true,
          args: {
            name: "port",
            isOptional: true,
          },
        },
        {
          name: "--host",
          description: "Ip for the socket (if applicable) to listen for requests",
          isRepeatable: true,
          args: {
            name: "host",
            isOptional: true,
          },
        },
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: "--force-tls-gateway",
          description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
        },
        {
          name: "--latency-based-selection",
          description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
          exclusiveOn: [
            "--gateway",
          ],
        },
        {
          name: "--fastmode",
          description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
        },
        {
          name: "--no-cover",
          description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "run",
      description: "Run the Nym client with provided configuration client optionally overriding set parameters",
      options: [
        {
          name: "--id",
          description: "Id of client we want to create config for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway",
          description: "Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened",
          isRepeatable: true,
          args: {
            name: "gateway",
            isOptional: true,
          },
        },
        {
          name: "--nyxd-urls",
          description: "Comma separated list of rest endpoints of the nyxd validators",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "nyxd_urls",
            isOptional: true,
          },
        },
        {
          name: "--nym-apis",
          description: "Comma separated list of rest endpoints of the API validators",
          isRepeatable: true,
          args: {
            name: "nym_apis",
            isOptional: true,
          },
        },
        {
          name: "--custom-mixnet",
          description: "Path to .json file containing custom network specification",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "custom_mixnet",
            isOptional: true,
            template: "filepaths",
          },
        },
        {
          name: "--enabled-credentials-mode",
          description: "Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "enabled_credentials_mode",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: "--stats-reporting-address",
          description: "Sets the address to report statistics",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "stats_reporting_address",
            isOptional: true,
          },
        },
        {
          name: "--disable-socket",
          description: "Whether to not start the websocket",
          isRepeatable: true,
          args: {
            name: "disable_socket",
            isOptional: true,
            suggestions: [
              "true",
              "false",
            ],
          },
        },
        {
          name: ["-p", "--port"],
          description: "Port for the socket to listen on",
          isRepeatable: true,
          args: {
            name: "port",
            isOptional: true,
          },
        },
        {
          name: "--host",
          description: "Ip for the socket (if applicable) to listen for requests",
          isRepeatable: true,
          args: {
            name: "host",
            isOptional: true,
          },
        },
        {
          name: "--fastmode",
          description: "Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init",
        },
        {
          name: "--no-cover",
          description: "Disable loop cover traffic and the Poisson rate limiter (for debugging only)",
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "ecash",
      description: "Ecash-related functionalities",
      subcommands: [
        {
          name: "show-ticket-books",
          description: "Display information associated with the imported ticketbooks,",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to display the ticketbook information",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: ["-o", "--output"],
              isRepeatable: true,
              args: {
                name: "output",
                isOptional: true,
                suggestions: [
                  "text",
                  "json",
                ],
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-ticket-book",
          description: "Import a pre-generated ticketbook",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the credential",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--credential-data",
              description: "Explicitly provide the encoded credential data (as base58)",
              isRepeatable: true,
              args: {
                name: "credential_data",
                isOptional: true,
              },
            },
            {
              name: "--credential-path",
              description: "Specifies the path to file containing binary credential data",
              isRepeatable: true,
              args: {
                name: "credential_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: "--standalone",
              description: "Specifies whether we're attempting to import a standalone ticketbook (i.e. serialised `IssuedTicketBook`)",
            },
            {
              name: "--full",
              description: "Specifies whether we're attempting to import full ticketboot (i.e. one that **might** contain required global signatures; that is serialised `ImportableTicketBook`)",
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-coin-index-signatures",
          description: "Import coin index signatures needed for ticketbooks",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the signatures",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--client-config",
              description: "Config file of the client that is supposed to use the signatures",
              isRepeatable: true,
              args: {
                name: "client_config",
                template: "filepaths",
              },
            },
            {
              name: "--signatures-data",
              description: "Explicitly provide the encoded signatures data (as base58)",
              isRepeatable: true,
              args: {
                name: "signatures_data",
                isOptional: true,
              },
            },
            {
              name: "--signatures-path",
              description: "Specifies the path to file containing binary signatures data",
              isRepeatable: true,
              args: {
                name: "signatures_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-expiration-date-signatures",
          description: "Import expiration date signatures needed for ticketbooks",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the signatures",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--client-config",
              description: "Config file of the client that is supposed to use the signatures",
              isRepeatable: true,
              args: {
                name: "client_config",
                template: "filepaths",
              },
            },
            {
              name: "--signatures-data",
              description: "Explicitly provide the encoded signatures data (as base58)",
              isRepeatable: true,
              args: {
                name: "signatures_data",
                isOptional: true,
              },
            },
            {
              name: "--signatures-path",
              description: "Specifies the path to file containing binary signatures data",
              isRepeatable: true,
              args: {
                name: "signatures_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "import-master-verification-key",
          description: "Import master verification key needed for ticketbooks",
          options: [
            {
              name: "--id",
              description: "Id of client that is going to import the key",
              isRepeatable: true,
              args: {
                name: "id",
              },
            },
            {
              name: "--client-config",
              description: "Config file of the client that is supposed to use the key",
              isRepeatable: true,
              args: {
                name: "client_config",
                template: "filepaths",
              },
            },
            {
              name: "--key-data",
              description: "Explicitly provide the encoded key data (as base58)",
              isRepeatable: true,
              args: {
                name: "key_data",
                isOptional: true,
              },
            },
            {
              name: "--key-path",
              description: "Specifies the path to file containing binary key data",
              isRepeatable: true,
              args: {
                name: "key_path",
                isOptional: true,
                template: "filepaths",
              },
            },
            {
              name: "--version",
              hidden: true,
              isRepeatable: true,
              args: {
                name: "version",
                isOptional: true,
              },
            },
            {
              name: ["-h", "--help"],
              description: "Print help",
            },
          ],
        },
        {
          name: "help",
          description: "Print this message or the help of the given subcommand(s)",
          subcommands: [
            {
              name: "show-ticket-books",
              description: "Display information associated with the imported ticketbooks,",
            },
            {
              name: "import-ticket-book",
              description: "Import a pre-generated ticketbook",
            },
            {
              name: "import-coin-index-signatures",
              description: "Import coin index signatures needed for ticketbooks",
            },
            {
              name: "import-expiration-date-signatures",
              description: "Import expiration date signatures needed for ticketbooks",
            },
            {
              name: "import-master-verification-key",
              description: "Import master verification key needed for ticketbooks",
            },
            {
              name: "help",
              description: "Print this message or the help of the given subcommand(s)",
            },
          ],
        },
      ],
      options: [
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "list-gateways",
      description: "List all registered with gateways",
      options: [
        {
          name: "--id",
          description: "Id of client we want to list gateways for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "add-gateway",
      description: "Add new gateway to this client",
      options: [
        {
          name: "--id",
          description: "Id of client we want to add gateway for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway-id",
          description: "Explicitly specify id of the gateway to register with. If unspecified, a random gateway will be chosen instead",
          isRepeatable: true,
          args: {
            name: "gateway_id",
            isOptional: true,
          },
        },
        {
          name: "--nym-apis",
          description: "Comma separated list of rest endpoints of the API validators",
          isRepeatable: true,
          args: {
            name: "nym_apis",
            isOptional: true,
          },
        },
        {
          name: "--custom-mixnet",
          description: "Path to .json file containing custom network specification",
          hidden: true,
          isRepeatable: true,
          args: {
            name: "custom_mixnet",
            isOptional: true,
            template: "filepaths",
          },
        },
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: "--force-tls-gateway",
          description: "Specifies whether the client will attempt to enforce tls connection to the desired gateway",
        },
        {
          name: "--latency-based-selection",
          description: "Specifies whether the new gateway should be determined based by latency as opposed to being chosen uniformly",
          exclusiveOn: [
            "--gateway-id",
          ],
        },
        {
          name: "--set-active",
          description: "Specify whether this new gateway should be set as the active one",
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "switch-gateway",
      description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
      options: [
        {
          name: "--id",
          description: "Id of client we want to list gateways for",
          isRepeatable: true,
          args: {
            name: "id",
          },
        },
        {
          name: "--gateway-id",
          description: "Id of the gateway we want to switch to",
          isRepeatable: true,
          args: {
            name: "gateway_id",
          },
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "build-info",
      description: "Show build information of this binary",
      options: [
        {
          name: ["-o", "--output"],
          isRepeatable: true,
          args: {
            name: "output",
            isOptional: true,
            suggestions: [
              "text",
              "json",
            ],
          },
        },
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "completions",
      description: "Generate shell completions",
      options: [
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
      args: {
        name: "shell",
        suggestions: [
          "bash",
          "elvish",
          "fish",
          "power-shell",
          "zsh",
        ],
      },
    },
    {
      name: "generate-fig-spec",
      description: "Generate Fig specification",
      options: [
        {
          name: ["-h", "--help"],
          description: "Print help",
        },
      ],
    },
    {
      name: "help",
      description: "Print this message or the help of the given subcommand(s)",
      subcommands: [
        {
          name: "init",
          description: "Initialise a Nym client. Do this first!",
        },
        {
          name: "run",
          description: "Run the Nym client with provided configuration client optionally overriding set parameters",
        },
        {
          name: "ecash",
          description: "Ecash-related functionalities",
          subcommands: [
            {
              name: "show-ticket-books",
              description: "Display information associated with the imported ticketbooks,",
            },
            {
              name: "import-ticket-book",
              description: "Import a pre-generated ticketbook",
            },
            {
              name: "import-coin-index-signatures",
              description: "Import coin index signatures needed for ticketbooks",
            },
            {
              name: "import-expiration-date-signatures",
              description: "Import expiration date signatures needed for ticketbooks",
            },
            {
              name: "import-master-verification-key",
              description: "Import master verification key needed for ticketbooks",
            },
          ],
        },
        {
          name: "list-gateways",
          description: "List all registered with gateways",
        },
        {
          name: "add-gateway",
          description: "Add new gateway to this client",
        },
        {
          name: "switch-gateway",
          description: "Change the currently active gateway. Note that you must have already registered with the new gateway!",
        },
        {
          name: "build-info",
          description: "Show build information of this binary",
        },
        {
          name: "completions",
          description: "Generate shell completions",
        },
        {
          name: "generate-fig-spec",
          description: "Generate Fig specification",
        },
        {
          name: "help",
          description: "Print this message or the help of the given subcommand(s)",
        },
      ],
    },
  ],
  options: [
    {
      name: ["-c", "--config-env-file"],
      description: "Path pointing to an env file that configures the client",
      isRepeatable: true,
      args: {
        name: "config_env_file",
        isOptional: true,
        template: "filepaths",
      },
    },
    {
      name: "--no-banner",
      description: "Flag used for disabling the printed banner in tty",
    },
    {
      name: ["-h", "--help"],
      description: "Print help",
    },
    {
      name: ["-V", "--version"],
      description: "Print version",
    },
  ],
};

export default completion;
```

---
title: Licensing
url: https://nym.com/docs/developers/licensing
---

# Licensing

As a general approach, licensing follows this pattern:

* [Nym Documentation](https://nym.com/docs) by [Nym Technologies](https://nym.com) is licensed under [CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) ![CC](/images/cc-icons/cc.svg) ![BY](/images/cc-icons/by.svg) ![NC](/images/cc-icons/nc.svg) ![SA](/images/cc-icons/sa.svg)

* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)

* Used libraries and different components are [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) or [MIT](https://mit-license.org/)

For accurate information, please check individual files.

---
title: Code of Conduct
url: https://nym.com/docs/developers/coc
---

# Code of Conduct

We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.

Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all.

Please be kind and courteous. There’s no need to be mean or rude.

Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.

Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.

We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behaviour that excludes people in socially marginalized groups.

Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Rust moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.

Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.

---
title: Nym Node Operator Guide & Prerequisites
description: Introduction to running Nym nodes. Learn requirements, skill expectations, time commitment, and how to get started operating a node on the Nym mixnet.
url: https://nym.com/docs/operators/introduction
---

# Introduction

This is **Nym's Operators guide**, containing information and setup guides for the various components of Nym network and Nyx blockchain validators.

Nym network (also known as Nym mixnet) routes and mixes packets through Gateways and Mixnodes, all run from the same binary called `nym-node`.

```ascii
                      ┌─►mix──┐  mix     mix
                      │       │
            Entry     │       │                   Exit
client ───► Gateway ──┘  mix  │  mix  ┌─►mix ───► Gateway ───► internet
                              │       │
                              │       │
                         mix  └─►mix──┘  mix
```

If you want to dive deeper into Nym Network architecture, clients and nodes visit the [Network docs](../network).

If you want to explore kickstart options and examples, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](../developers).

## Minimum Requirements

**If you are an operator and want to join the journey of starting and mantaining a Nym Node, begin with visiting [Minimum requirements page](nodes.mdx).**

## Popular pages

**Binary Information**

* [Building Nym](binaries/building-nym.mdx)
* [Pre-built Binaries](binaries/pre-built-binaries.mdx)

**Node setup and usage guides:**

* [Nym Node](nodes/nym-node)
* [Nymvisor](nodes/maintenance/nymvisor-upgrade.mdx)
* [Validators](nodes/validator-setup.mdx)
* [Nym API Setup](nodes/validator-setup/nym-api.mdx)

**Performance Monitoring**
* [Performance, probe and measurements](performance-and-testing)

**Tokenomics, rewards and roadmap**
* [General tokenomics page](tokenomics.mdx)
* [Nym Node rewards page](tokenomics/mixnet-rewards.mdx)
* [Nym operators roadmap](tokenomics/mixnet-rewards.mdx#roadmap)

**Maintenance, troubleshooting and FAQ**

* [FAQ](faq/nym-nodes-faq.mdx)
* [Maintenance](nodes/maintenance.mdx)
* [Troubleshooting](troubleshooting/nodes.mdx)

**Community Counsel**

* [Exit Gateway](community-counsel/exit-gateway.mdx)
* [Community Counsel](community-counsel.mdx)
* [How to Add Info](community-counsel/add-content.mdx)

**Archive**

* [FAQ: Project Smoosh](archive/faq/smoosh-faq.mdx)

---
title: Nym Node Changelog & Release History
description: Complete changelog for Nym node releases, binary updates, SDK changes, and network upgrades. Sorted newest first with links to relevant documentation.
url: https://nym.com/docs/operators/changelog
---

export const TestingSteps = () => (

    Testing steps performed

);

export const TryYourself = () => (

    Try yourself

);

export const CiConfig = () => (

    Components of <code>ci-binary-config-checker</code>

);

export const TunnelManagerCommands = () => (

    Commands to update IP tables rules with a new <code>network_tunnel_manager.sh</code>

);

export const LoadEndpointInfo = () => (

    Developer notes behind <code>/load</code> endpoint

);

# Changelog

This page displays a full list of all the changes during our release cycle from `v2024.3-eclipse` onward. Operators can find here the newest updates together with links to relevant documentation. The list is sorted so that the newest changes appear first.

**Note:** Any information published on this page was up to date at the time of writing. We do *not* maintain changelog retrospectively.

## `v2026.9-venaco`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.9-venaco)
- [`nym-node`](nodes/nym-node.mdx) version `1.31.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-05-06T05:19:51.973494120Z
Build Version:      1.31.0
Commit SHA:         f84de25302e886d4bd97a898885c569724c002a7
Commit Date:        2026-05-06T07:16:42.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```
### Operators Updates & Tools

- [**NIP-11 is out, please vote!**](https://governator.nym.com/proposal/prop-fe98cb2a-fa34-4e7d-82ac-4aa0e6e64aa2) Another upgrade of Nym exit policy opened for operators decision, this time expanding ports to support Gemini and enabling partial Telegram support for NymVPN users.

### Features

- [Only init `SHARED_CLIENT` if requested](https://github.com/nymtech/nym/pull/6708): This PR prevents shared reqwest client from being initialized even when `self.reqwest_client` is used instead

- [Return IPv6 addresses](https://github.com/nymtech/nym/pull/6684)

- [Block non-public IPR/NR checks](https://github.com/nymtech/nym/pull/6670)

### Bugfix

- [Fix for v9 IPR ](https://github.com/nymtech/nym/pull/6710)

- [Fixes to crates and CI](https://github.com/nymtech/nym/pull/6686)

- [Fix invalid ticket spend](https://github.com/nymtech/nym/pull/6683)

## `v2026.8-urda`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.8-urda)
- [`nym-node`](nodes/nym-node.mdx) version `1.30.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-04-21T10:11:28.164080002Z
Build Version:      1.30.0
Commit SHA:         0c83ae2408ea9efcc1abae613711c6e4e16148ad
Commit Date:        2026-04-21T12:06:23.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Features

- [Include all gateways in the returned list](https://github.com/nymtech/nym/pull/6649): Ensures gateway APIs return the full gateway set instead of filtered results, improving consistency across services.
- [Max/sdk stream wrapper](https://github.com/nymtech/nym/pull/6320): Introduces a Rust SDK stream abstraction enabling IPR-based mixnet communication and client-side streaming support.
- [Max/sdk docrs](https://github.com/nymtech/nym/pull/6566): Updates SDK documentation to reflect the new stream-based architecture and IPR communication model.

### Refactors & Maintenance

- [Optimize GW probe in NS agent](https://github.com/nymtech/nym/pull/6636): Refactors gateway probe integration from subprocess execution to library usage, removing CLI dependency and improving typed communication between agent and probe.

## `v2026.7-tola`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.7-tola)
- [`nym-node`](nodes/nym-node.mdx) version `1.29.0`

```sh
Binary Name:        nym-node
Build Timestamp:    2026-04-08T10:31:49.141185557Z
Build Version:      1.29.0
Commit SHA:         97068b2aace6626e3dff6864a26e7b1ff35f5725
Commit Date:        2026-04-07T15:51:44.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

The outcome of [NIP-10: Nym Exit Policy Update – Opening Ports for Dash, SIP, Voice, TeamSpeak, & Litecoin Services](https://governator.nym.com/proposal/prop-d67c07c1-8d81-4d04-bc66-a0b28c24ffbd) has been incorporated into the [Network Tunnel Manager (NTM)](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/network-tunnel-manager.sh). Operators are required to rerun the tool on their servers to apply the changes. Follow [these simple steps](#update-nym-exit-policy) to apply the exit policy.

- [New documentation logic to `network/`, `developers/` and `apis/`](https://github.com/nymtech/nym/pull/6494) according to the [diataxis.fr](https://diataxis.fr/) framework, making basis for adding Lewes Protocol documentation. Additionally developer docs now include tutorials for the [Rust SDK modules](/developers/rust), and documentation on the `stream` [Mixnet module](/developers/rust/mixnet). See the pages at:

  - [Network docs](/network)
  - [Developer docs](/developers/integrations)
  - [APIs docs](/apis/introduction)

#### Update Nym exit policy

**Follow these steps to update the exit policy using NTM.**

###### 1. Download the new NTM
- Download the latest NTM and make it executable:
```sh
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o ./network-tunnel-manager.sh && \
chmod +x network-tunnel-manager.sh
```

###### 2. Update the exit policy
- To ensure your routing is clean, run:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```
</ Steps>

### Features

- [Multiple deposit prices](https://github.com/nymtech/nym/pull/6608): Introduces tiered deposit pricing for the ecash contract. Whitelisted addresses can deposit at reduced rates, and gateway redemption flow is simplified by removing the multisig proposal path. Important for operators to manage deposit and token flow efficiently.

- [Nym Node spam logging](https://github.com/nymtech/nym/pull/6621): Prevents spam logs when downstream nodes are slow, improving node stability and log clarity.

- [Update Fallback IP for Nym API](https://github.com/nymtech/nym/pull/6622): Updates fallback IPs for Nym API, ensuring nodes maintain stable connectivity.

### Bugfix

- [Ensure client keys are generated before requesting credentials](https://github.com/nymtech/nym/pull/6579): Fixes authentication order, crucial for nodes to securely request credentials.

- [Fix SOCKS5 gateway probe](https://github.com/nymtech/nym/pull/6576): Resolves regressions in Socks5 gateway probes, maintaining gateway functionality and reliability.

- [Nym node Ansible - download clean NTM on each run](https://github.com/nymtech/nym/pull/6654)

### Refactors & Maintenance

- [Move format_debug_bytes in common crate](https://github.com/nymtech/nym/pull/6580): Refactors debug logging code, improving node log readability and maintainability.

- [Migration for tiered deposit pricing](https://github.com/nymtech/nym/pull/6608): Seeds whitelist and backfills statistics for multiple deposit tiers, ensuring nodes handle deposits correctly after migration.

- [Max/docs-diataxis-ify](https://github.com/nymtech/nym/pull/6494): Rewrites network/, developers/, and apis/ according to the Diataxis framework. Adds Rust SDK tutorials and stream Mixnet module documentation, as well as LLM-friendly doc files (llms.txt and llms-full.txt).

## `v2026.6-stilton`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.6-stilton)
- [`nym-node`](nodes/nym-node.mdx) version `1.28.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-03-25T13:41:43.299729408Z
Build Version:      1.28.0
Commit SHA:         034346917901bd373dee0ca170b26a9359dbd26d
Commit Date:        2026-03-25T07:47:04.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

New release is here and with it a completely new theme of the docs!

**This release introduces implementation of Lewes Protocol (LP). Only nodes upgraded to this version will be able to complete handshake using LP.**

**Please upgrade soon and follow the section below to ensure smooth functionality of your `nym-node`.**

1. **[Network Tunnel Manager (NTM)](#network-tunnel-manager-ntm-updates) is now the single port manager for WireGuard routing and Gateway Nym nodes.**

2. Lewes protocol ports (`41264/tcp` and `51264/udp`) as well as all the essential ports for mixnet operation (before `ufw`) are now included in NTM
- Follow [these steps](#network-tunnel-manager-ntm-updates) to implement changes if you run any Gateway type of Nym node
- For operators running mixnode mode, make sure to open all ports via `ufw` as [documented here](/operators/nodes/preliminary-steps/vps-setup#3-configure-your-firewall), do *not* use NTM as you nodes do *not* need all exress ports (exit policy) opened

#### Network Tunnel Manager (NTM) Updates

Nym team is testing an unreleased version of [Gateway Probe](/operators/performance-and-testing/gateway-probe). This new version checks whether the ports opened align with the governance decision about exit policy. If they don't, the nodes will be taken out of Service grant program and [Delegation program](https://nym.com/network/DP).

NTM is now changed to be a standalone port manager for servers hosting Nym nodes running in a Gateway mode (with or without WireGuard). Operators of these nodes no longer need to manage mixnet fundamental ports by `ufw` separately, as the NTM will take care of it as well as adjusting the ports according to Nym exit policy.

**Follow these steps to update the ports setting of your server using NTM.**

###### 1. Download the new NTM
- Download the latest NTM and make it executable:
```sh
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o ./network-tunnel-manager.sh && \
chmod +x network-tunnel-manager.sh
```

###### 2. Update the exit policy

- Run NTM to become main port manager (including Nym services), run:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```

###### 3. Disable `ufw`

Right now your NTM is handling the port management. You can disable `ufw`.

- We suggest to not uninstall it, just make it innactive for the time being:

```sh
ufw disable
```

###### 4. Re-run NTM

- NTM is fully omnipotent, re-rerun it again now with `ufw` disabled to ensure clean state:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```
</ Steps>

Congratulation, your port configuration is up to date, including LP ports.

### Features

- [Add LP to NS UI](https://github.com/nymtech/nym/pull/6562): Operators can now monitor LP registration status directly from the UI. The gateway list shows post-quantum registration status via emojis (success/failure), and the dashboard view adds LP count columns for success, failure, and untested, making monitoring faster and easier.

- [Introduce /v3/unstable/nym-nodes/semi-skimmed](https://github.com/nymtech/nym/pull/6499): New API endpoint aggregates LP information for nodes, allowing them to discover each other's LP capabilities and establish shared post-quantum connections efficiently.

- [Additional ticket for agent](https://github.com/nymtech/nym/pull/6551): Adds an extra ticket so the agent/probe can perform LP tests automatically without additional configuration.

### Bugfix

- [LP fixes](https://github.com/nymtech/nym/pull/6601): Improvements for LP registration results and preshared key handling to ensure accurate LP status reporting.

- [Allow deserialisation of LP data from either snake_case or lowercase](https://github.com/nymtech/nym/pull/6586): Fixes LP data deserialization issues, making LP information robust across different formats.

### Refactors & Maintenance

- [LP improvements](https://github.com/nymtech/nym/pull/6526): Refactors LP handling code and scaffolds internode handshake processing to simplify future maintenance and reduce potential bugs.

## `v2026.5-raclette`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.5-raclette)
- [`nym-node`](nodes/nym-node.mdx) version `1.27.0`

```sh
Binary Name:        nym-node
Build Timestamp:    2026-03-10T10:14:03.446553605Z
Build Version:      1.27.0
Commit SHA:         7cccf3cfff448f1b38324f7655930a2b621588c6
Commit Date:        2026-03-10T10:46:12.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

**This release has breaking changes, please read and follow up this section to ensure smooth functionality of your `nym-node`.**
</ Callout>

###### 1. [NIP-8](https://governator.nym.com/proposal/prop-706369bb-9964-40cf-96a1-224c6e862fe2) & [NIP-9](https://governator.nym.com/proposal/prop-29027e02-50e0-46d9-a096-7334b67efc94) are finished

-  These decisions are implemented in the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) as well as in [`network-tunnel-manager.sh` (NTM)](/operators/nodes/nym-node/configuration#routing-configuration)

- **Follow the [steps to update your node exit policy](#update-nym-exit-policy)**, required for operators running wireguard or Exit gateway

###### 2. [Lewes Protocol (LP)](#lewes-protocol-lp) is out

- **Follow [these steps](#lewes-protocol-lp) to open your ports for the protocol to work**

###### 3. New and updated guides for [system maintenance](/operators/troubleshooting/vps-isp#system-hygiene)

- Including new guides for [self virtualising design](/operators/troubleshooting/vps-isp#self-managed-vms-hypervisor-host-cleanup--ansible-automated-maintenance), with a new [Ansible playbook](/operators/orchestration/ansible#4-system-maintenance)

- **In case of running out of disk space, follow the [*System Hygiene* chapter](/operators/troubleshooting/vps-isp#system-hygiene)**

#### Update Nym exit policy

Nym team is testing an unreleased version of [Gateway Probe](/operators/performance-and-testing/gateway-probe). This new version checks whether the ports opened align with the governance decision about exit policy. If they don't, the nodes will be taken out of Service grant program and [Delegation program](https://nym.com/network/DP).
</ Callout>

**Follow these steps to update the exit policy using NTM.**

###### 1. Download the new NTM
- Download the latest NTM and make it executable:
```sh
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o ./network-tunnel-manager.sh && \
chmod +x network-tunnel-manager.sh
```

###### 2. Update the exit policy
- To ensure your routing is clean, run:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```
</ Steps>

#### Lewes Protocol (LP)

**Operators must open the following ports to enable LP on their nodes:**

```sh
ufw allow 41264/tcp && ufw allow 51264/udp
```
**Failing to open these ports will prevent LP registration from functioning correctly.**
</ Callout>

Nym nodes send more than encrypted messages. They also transmit control information between clients and other nodes. Users want to send both messages and streams of data (e.g., IP streams).

The current Layer 7 (websocket-based) implementation handles registration, control, and user data at the application level. Lewes Protocol moves these concerns to Layer 3, enabling a packet-based network rather than purely an application-based one.

### Features

- [Lewes Protocol with PSQv2](https://github.com/nymtech/nym/pull/6491)

### Bugfix

- [Correctly populate gateway probe LP data](https://github.com/nymtech/nym/pull/6533)

- [Restore latest_measurement field for nym-node /verloc endpoint](https://github.com/nymtech/nym/pull/6452)

### Refactors & Maintenance

- [Removed redundant LP states](https://github.com/nymtech/nym/pull/6509)
- [Operator & system maintenance guides](https://nym.com/docs/operators/troubleshooting/vps-isp#system-hygiene) - Practical tips for keeping Nym nodes healthy. Covers VPS hygiene, log management, IPv6 setup, and general system upkeep. Helps prevent disk full crashes, runaway logs, and other operational issues for both VPS and self-hosted nodes.

## `v2026.4-quark`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.4-quark)
- [`nym-node`](nodes/nym-node.mdx) version `1.26.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-02-24T13:43:24.098285047Z
Build Version:      1.26.0
Commit SHA:         a2081af6038ef3ef40b3d9368299d2676a2fbb6a
Commit Date:        2026-02-24T12:02:35.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operator & Developer Updates

### Features

- [Stateless handshake improvements for LP Gateway](https://github.com/nymtech/nym/pull/6437)
- [HTTP & DNS improvements](https://github.com/nymtech/nym/pull/6423)
- [Endpoint support for exit gateway IPs](https://github.com/nymtech/nym/pull/6418)

### Tools

- **Diagnostic Tool** - a standalone binary for network diagnostics. It performs DNS, HTTP, and gateway connectivity tests, helping developers identify connectivity issues and monitor network performance. It can also be run via the daemon CLI. Read the full guide [here](https://nym.com/docs/developers/tools/diagnostic-tool).
- **Socks5 Score Calculation** - performed by the Gateway probe, which tests `nym-node --mode exit-gateway` instances over Socks5. The probe assigns a latency-based rating: high, medium, low, or offline. Full guide [here](https://nym.com/docs/operators/performance-and-testing#socks5-score-calculation-process).

## `v2026.3-parmigiano`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.3-parmigiano)
- [`nym-node`](nodes/nym-node.mdx) version `1.25.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-02-10T10:41:14.958988176Z
Build Version:      1.25.0
Commit SHA:         1ecb457c66ccabc4877e3822566f266c7331d29e
Commit Date:        2026-02-10T10:30:45.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operator & Developer Updates

### Features

- [Registration client now properly supports fallback](https://github.com/nymtech/nym/pull/6419)
- [Exposed WireGuard PSK for vpn-client](https://github.com/nymtech/nym/pull/6411)
- [Configurable LP timeouts](https://github.com/nymtech/nym/pull/6409)
- [Improved CLI and behavior for LP Gateway Probe](https://github.com/nymtech/nym/pull/6400)

Note: This code is currently deactivated and doesn’t involve any changes for operators right now, but it will in the future.

### Bugfix

- [Share IP allocation fixes](https://github.com/nymtech/nym/pull/6395)
- [Mixnet registration fixes](https://github.com/nymtech/nym/pull/6356)

### Refactors & Maintenance

- [Cleanup x25519/ed22519 usage](https://github.com/nymtech/nym/pull/6335)

## `v2026.2-oscypek`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.2-oscypek)
- [`nym-node`](nodes/nym-node.mdx) version `1.24.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-01-27T14:54:15.579821601Z
Build Version:      1.24.0
Commit SHA:         83bf9dc7cc2b01f65cab671733f2bf6c3abd471d
Commit Date:        2026-01-27T15:46:52.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

**This release comes with breaking changes - please follow the [steps below](#oscypek-special-update) before upgrading!**

Secondly, the outcome of [NIP-7: Nym Exit Policy Update - Opening Ports for Steam, Discord & SSH](https://governator.nym.com/proposal/prop-281e9ec1-8e10-4e97-848c-311823e83f61), is added to the [Network tunnel manager (NTM)](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/network-tunnel-manager.sh) and operators are required to rerun the tool on their servers.
</ Callout>

#### `oscypek` special update

This release brings changes which would lead into a *foreign constraint bug* if operators just switched binaries and restarted the node. To prevent it we need to do a little `sqlite` tweak on the node database.

To simplify this, we made **a build in command, which operators must run after getting the new binary, but before restarting the node.**

These are the steps to follow:

###### 1. Get `oscypek` binary
- SSH to your machine as root
- Navigate to the destination where you have `nym-node` binary
- Get the latest binary and provide it with permissions to run
```sh
curl -L "https://github.com/nymtech/nym/releases/download/nym-binaries-v2026.2-oscypek/nym-node" -o nym-node && \
chmod +x nym-node
```

###### 2. Run `debug` command
```sh
./nym-node debug reset-providers-gateway-dbs --id <ID>
```

###### 3. Restart your node
- Restart the `nym-node.service`
```sh
systemctl restart nym-node
```
- Additionally look for status or service journal
```sh
service nym-node status
# or
journalctl -u nym-node -f --all
```
</ Steps>

#### Update Nym exit policy

As a result of [NIP-7: Nym Exit Policy Update - Opening Ports for Steam, Discord & SSH](https://governator.nym.com/proposal/prop-281e9ec1-8e10-4e97-848c-311823e83f61), we updated [`network-tunnel-manager.sh` (NTM)](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/network-tunnel-manager.sh). Every operator is required to download and re-run the current version of NTM on the servers hosting Nym nodes.

These are the steps for the exit policy update, using NTM.

###### 1. Get the new NTM
- Download the updated NTM and make executable
```sh
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o ./network-tunnel-manager.sh && \
chmod +x network-tunnel-manager.sh
```

###### 2. Update exit policy
- To be sure that your routing is clean, run this command:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```
</ Steps>

### Features

- [Deriving `Serialize` for `GatewayData`](https://github.com/nymtech/nym/pull/6314): Deriving `Serialize` for gateway data, that will be used by the diagnostic tool in the `vpn-client` repo

- [DNS static table pre-resolve](https://github.com/nymtech/nym/pull/6297): This PR adds pre-resolve stage that returns address if we have used static table previously. This ensures that we don't continually suffer the penalty of a lookup timeout, while also allowing for the possibility of going back to the default internal secure resolver if one or more nameservers becomes usable again at a future time.

- [Add `Copy+Clone` to `nym_api_provider::Config`](https://github.com/nymtech/nym/pull/6296): Add `Copy+Clone` to `nym_client_core::client::topology_control::nym_api_provider::Config`

- [LP Registration + Telescoping + Gateway Probe Localnet Mode](https://github.com/nymtech/nym/pull/6286):  Combines LP registration protocol implementation, adds telescoping/nested sessions support, adds localnet mode for `gateway-probe` testing, integrates KKT & PSQ cryptographic primitives

- [Minor DNS improvements](https://github.com/nymtech/nym/pull/6283): Increase timeouts back to 10 seconds for overall lookup and 5 seconds per query, ignore unreliable test, remove JIT resolution in http client as it is at best not useful, and at worst increasing timeout

- [HTTP client without default features](https://github.com/nymtech/nym/pull/6281): Fix compile issue caused when using the http client using `default-features=false`

- [DNS: reduce number of attempts](https://github.com/nymtech/nym/pull/6278): Reduce number of retry attempts performed by hickory to `0`, define `new_resolver` as infallible, use `ResolverOpts` to build builder

- [Fallback gateway listener and remove legacy key support](https://github.com/nymtech/nym/pull/6249)

- [Fix assertion](https://github.com/nymtech/nym/pull/6238)

- [Initial changes to support extra configurable parameters and to print…](https://github.com/nymtech/nym/pull/6237): This branch adds support for the additional configurable parameters introduced in  `nicolas/sdk-param-support-debug` in the nym vpn client branch and also debugging messages to verify that it works

- [Data Observatory](https://github.com/nymtech/nym/pull/6172): This PR adds the Data Observatory that is:
    - chain scraper
    - parses Cosmos SDK messages
    - parses Cosmwasm messages
    - stores data in pgsql

### Bugfix

- [Downgrade gateway protocol to clients proposed version](https://github.com/nymtech/nym/pull/6377)

- [Ack fix](https://github.com/nymtech/nym/pull/6364)

- [Sqlite transaction escalation was causing errors ](https://github.com/nymtech/nym/pull/6299): Getting tickets from credential storage requires a transaction doing a read and then a write. Running registration in parallel was causing sqlite to return errors, because it can't escalate two transactions, only one.

- [Use proper mixing delay instead of poisson delay in cover traffic](https://github.com/nymtech/nym/pull/6269): Currently the secondary cover traffic loop uses its Poisson process delays instead of a proper mixing delay, this PR fixes that

### Refactors & Maintenance

- [Update nix to `v0.30.1`](https://github.com/nymtech/nym/pull/6316)

- [Remove repetitive words in comment](https://github.com/nymtech/nym/pull/6313)

- [Clippy fixes and use fixed rust version from `REQUIRED_RUSTC_VERSION`](https://github.com/nymtech/nym/pull/6295)

## `v2026.1-niolo`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2026.1-niolo)
- [`nym-node`](nodes/nym-node.mdx) version `1.23.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-12-02T16:21:03.251191389Z
Build Version:      1.23.0
Commit SHA:         46fe1bc8191f42aa27f34743c96e9e9f26453d87
Commit Date:        2025-12-02T15:29:30.000000000Z
Commit Branch:      release/2025.22-niolo
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

We’re excited to announce the first **nym-node release of 2026**.

**Exit Policy Ports Management**

In December 2025, two NIP proposals were approved, introducing new ports to Nym network: [NIP-6](https://governator.nym.com/proposal/prop-ba886b9d-6f6e-4365-b4ed-fe7e604bc375), opening ports for WhatsApp and Session + Port `465` and [NIP-4](https://governator.nym.com/proposal/prop-ca6726ea-38b1-4568-97fe-8bdc5fdc83a0), opening port `587`.

**Due to the concerns raised by the operators we built a rate limiting function to Network tunnel manager (NTM) to prevent spam abuse of the network. You can see the changes [here](https://github.com/nymtech/nym/pull/6317).**

To implement the changes and ensure that the nodes have expected performance, please re-run NTM following these steps:

###### 1. Get the new NTM
- Download the updated NTM and make executable
```sh
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o ./network-tunnel-manager.sh && \
chmod +x network-tunnel-manager.sh
```

###### 2. Update exit policy
- To be sure that your routing is clean, run this command:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```
</ Steps>

**Node Orchestration**

Nym network scaling is done mostly by squads, organizations, DAOs and other entities of collaborating operators administrating multiple nodes. To improve efficiency, user experience and cost we added a new menu item [*Orchestration*](/operators/orchestration) where you can find step by step guides to:

- [Virtualise server using KVM](/operators/nodes/preliminary-steps/vps-setup/advanced): Creating VMs with desired size, bandwidth and capacity for lower cost in comparison to renting VPS
- [Ansible guide](/operators/orchestration/ansible): Orchestrating many nodes effectively using the [Ansible template](https://github.com/nymtech/nym/tree/develop/ansible/nym-node)

Please, let us know how that worked for you.

### Features

- [Merge intermediate upgrade mode changes](https://github.com/nymtech/nym/pull/6174): This PR contains a long changelog on itself, please read the full [in the PR description](https://github.com/nymtech/nym/pull/6174)

- [Config migration](https://github.com/nymtech/nym/pull/6259)

- [Statistics API v2](https://github.com/nymtech/nym/pull/6227): This PRs adds a v2 of the `VpnClientSessionReport` and update the stats API to be able to store it

- [Update chain registry link](https://github.com/nymtech/nym/pull/6219)

### Bugfix

- [Re-exposed 'derive_extended_private_key'](https://github.com/nymtech/nym/pull/6247)

- [`gateway-probe` fixes for run-local](https://github.com/nymtech/nym/pull/6212)

- [Upgrade mode: VPN adjustments](https://github.com/nymtech/nym/pull/6189): This PR further builds up on [\#6174](https://github.com/nymtech/nym/pull/6174) to include changes required by the VPN-client to fully support the upgrade mode, what is relevant here is that this PR modifies the credential storage to allow it to storage an opaque `emergency credential` that lets it be shared between sessions (if it is still valid)

- [Add weighted scoring to NS API](https://github.com/nymtech/nym/pull/6144)

### Refactors & Maintenance

- [Remove run DKG migration](https://github.com/nymtech/nym/pull/6253)

- [Do not re-derive wallet keys on every tx](https://github.com/nymtech/nym/pull/6213): The `cosmrs' trait bounds on `EcdsaSigner` got updated to include `Send` and `Sync`, meaning we no longer need to derive private keys on every transaction and instead we can just do it once, on construction

- [Remove support for legacy mixnode within the performance contract](https://github.com/nymtech/nym/pull/6205): The network no longer supports those nodes, there's no point in having the "brand new" (kinda) contract support them either

## Last Update of 2025

We are not going to do a platform release this year anymore, but we have two important updates to share.

### Governance decisions

During December operators were active in voting about new ports and changes in the quorum.

**As agreed in [NIP-4](https://forum.nym.com/t/nip-4-nym-exit-policy-update-opening-port-587/2029/2) and [NIP-6](https://forum.nym.com/t/nip-6-nym-exit-policy-update-opening-ports-for-whatsapp-and-session/2042/1), we are opening these ports on [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt):**
```ini
*:587 (SMTPSubmission)
*:22021(Session)
*:3478 (WhatsApp)
*:3480 (WhatsApp)
*:3484 (WhatsApp)
```

**Node operators requirements**

In order for these changes to become active, Nym node operators need to update their WireGuard and Mixnet exit policy, by following these simple steps:

###### 1. Update WireGuard exit policy

- WireGuard exit policy is managed by `iptables rules` of each server hosting a `nym-node`
- To simplify the flow, [`network-tunnel-manager.sh` (NTM)](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/network-tunnel-manager.sh) takes care of this
- Please get the new NTM by SSH to your node and running:
```sh
curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/network-tunnel-manager.sh -o network-tunnel-manager.sh && \
chmod +x network-tunnel-manager.sh && \
./network-tunnel-manager.sh --help
```
- Then run either:
```sh
./network-tunnel-manager.sh complete_networking_configuration
```
- Or in case that you are sure that you did `complete_networking_configuration` since the latest release, you can just run the commands needed for the exit policy:
```sh
./network-tunnel-manager.sh exit_policy_clear
./network-tunnel-manager.sh exit_policy_install
./network-tunnel-manager.sh exit_policy_status
./network-tunnel-manager.sh exit_policy_tests
```

###### 2. Update Mixnet exit policy

- Mixnet exit policy is being pulled with `nym-node run` command from this source: [nymtech.net/.wellknown/network-requester/exit-policy.txt](https://nymtech.net/.wellknown/network-requester/exit-policy.txt)
- All you need to do is to restart your node:
```sh
service nym-node restart
```

### Orchestration with Ansible

Finally we release our initial version **[Ansible playbooks](/operators/orchestration) for orchestrating multiple Nym nodes** from local shell. For now we have playbooks to perform these tasks:

- Deploy
- Upgrade
- Bond

Checkout the [docs](/operators/orchestration/ansible) and the [Ansible template](https://github.com/nymtech/nym/tree/develop/ansible/nym-node) and let us know how this flag ship worked for you.

## `v2025.21-mozzarella`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.21-mozzarella)
- [`nym-node`](nodes/nym-node.mdx) version `1.22.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-11-25T14:26:29.627763948Z
Build Version:      1.22.0
Commit SHA:         22793bc45ea21561671d6670497ff42bc36b9d76
Commit Date:        2025-11-25T15:16:42.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.88.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

**We are introducing new `network-tunnel-manager.sh` (NTM), with improved server configuration (see all changes here: [\#6186](https://github.com/nymtech/nym/pull/6186/)). We ask operators to re-run their routing configuration using the new NTM, following [these steps](/operators/nodes/nym-node/configuration#routing-configuration).**

**NOTE THAT THIS IS A NEW TOOL HANDLING VARIOUS COMPLEX SERVER SETTINGS, PLEASE RUN IT ON A FEW NODES AT A TIME, DO THE TESTING, MONITOR YOUR NODES AND [REPORT ANY ISSUES](https://matrix.to/#/#operators:nymtech.chat).**

We will keep `nym-node v1.21.1` as the latest version on API side for another 3 days to not penalize operators taking time for a proper implementation.
</ Callout>

We are proud to announce that there are several improvements on tools aiming to make node operators life easier. Please let us know how do these programs work for you.

- [**New Nym Node CLI version**](/operators/tools#nym-node-cli): This version introduces arguments, allowing the operator to pass all needed variables (ie. hostname, mode etcetra) and let the program setup everything required for `nym-node` installation, server configuration, nginx, routing, tunnels and bridges, without further prompts for these values. This version also installs [QUIC bridge](/operators/nodes/nym-node/configuration#quic-transport-bridge-deployment).

- [**New Network Tunnel Manager**](/operators/nodes/nym-node/configuration#routing-configuration): NTM went through an big overhaul ([\#6186](https://github.com/nymtech/nym/pull/6186/)) - this new version combines old NTM with WG scripts. If run with `complete_networking_configuration` the tool does entire routing configuration, creates interfaces, and configures WireGuard exit policy.

- [**Updated QUIC Deployment Tool**](/operators/nodes/nym-node/configuration#quic-transport-bridge-deployment): The program is lighter, stripped of redundant functions reworking iptables rules.

### Features

- [HTTP API resilience enable & domain rotation conditions](https://github.com/nymtech/nym/pull/6200): Changes to make sure fallback domains are updated / enabled only for relevant

- [Typescript SDK 1.4.1](https://github.com/nymtech/nym/pull/6146): This PR is a new release of the Typescript SDK, `mixFetch` and `WASM` client. It also removes the Harbour Master client from `mixFetch`, replacing it with the Nym API's described endpoint for nym-nodes.

- [Enable URL rotation and retries for mixnet gateway init](https://github.com/nymtech/nym/pull/6126):
  - Multiple URL fallback with configurable retries (defaults to 3)
  - Infallible URL conversion per feedback (`Url::from()` instead of `parse().ok()`)
  - Non-breaking builder pattern for `BuilderConfig` per feedback
  - Reverted redundant node filtering per clarification that API already filters by `supported_roles.entry`

- [Credential proxy jwt](https://github.com/nymtech/nym/pull/5957): This PR is part of the 'Upgrade Mode' that should allow usage of the network in a situation where ecash credentials are unissuable, because, for example, we have lost signing quorum (i.e. we have fewer than the required number of threshold signers responding to requests). This version is more naive. Instead requesting actual 'emergency credentials' that would have been issued by a subset of ecash signers, the credentials proxy creates a JWT, signed with its key, attesting the upgrade mode has been enabled.

### Bugfix

- [Tunnel not waiting on `MixnetClient` to shut down cleanly](https://github.com/nymtech/nym/pull/6225): When there is a wireguard registration error, the mixnet client is signalled to shut down, but the tunnel doesn't wait. Now on errors, the registration client doesn't return until everything is properly stopped

- [Fix credential proxy upgrade mode attestation url arg](https://github.com/nymtech/nym/pull/6202): This includes bringing over changes introduced in [\#6174](https://github.com/nymtech/nym/pull/6174)

- [Remove debug feature from `http-macro` spec in gateway probe](https://github.com/nymtech/nym/pull/6195)

- [DNS reliability and troubleshooting ](https://github.com/nymtech/nym/pull/6179)

- [Distinguish authenticator errors by credential spent](https://github.com/nymtech/nym/pull/6176): This PR introduces a distinction between authenticator client errors that are happening before a credential was taken out of storage, and after

- [Disconnect mixnet client if registration fails](https://github.com/nymtech/nym/pull/6158): Currently the registration client does its job and then handles everything to the `vpn-client`, who then takes care on the mixnet client. However, if the registration fails, nothing is disconnecting the mixnet client, which can lead to errors of the kind of `There is already an open connection to this client`. This PR addresses that

## `v2025.20-leerdammer`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.20-leerdammer)
- [`nym-node`](nodes/nym-node.mdx) version `1.21.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-11-12T08:19:33.288341371Z
Build Version:      1.21.0
Commit SHA:         babf113fe5d396fa8a84fa939ad4b1b5b4d38b83
Commit Date:        2025-11-12T08:39:48.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.88.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- [New **Performance Measurement** page](/operators/performance-and-testing) explaining the logic behind node selection for NymVPN application

- [New **Gateway Probe Details** page](/operators/performance-and-testing/gateway-probe-details) explaining complexity and contradictions when measuring network performance

### Developer Tools

- [Typescript SDK 1.4.1](https://github.com/nymtech/nym/pull/6146): This PR is a new release of the Typescript SDK, `mixFetch` and `WASM` client. It also removes the Harbour Master client from `mixFetch`, replacing it with the Nym API's described endpoint for nym-nodes

- [Overhauled **developer integrations** pages](/developers/integrations) explaining the different restrictions for the different SDK options on offer

- [Fixed `mixFetch` and `WASM Client` playground + examples](/developers/typescript): new versions of the Typescript SDK and `mixFetch` have been published, examples and live playground have been updated accordingly

### Features

- [Tweak ts sdk actions](https://github.com/nymtech/nym/pull/6185): Using `taskset` to limit the number of of CPUs used by `wasm-pack` and `wasm-opt` commands used by ts linting CI

- [Configurable mixnet client startup timeout](https://github.com/nymtech/nym/pull/6148)

- [QUIC bridge deployment script v2](https://github.com/nymtech/nym/pull/6145): Script helping operators to install, configure and deploy QUIC bridge as systemd service

- [Expose more explicit `new_with_fronted_urls` builder for http API client](https://github.com/nymtech/nym/pull/6136)

- [Domain fronting](https://github.com/nymtech/nym/pull/6134): Enable URL rotation and retries for mixnet gateway [`init`](https://github.com/nymtech/nym/pull/6126)

### Bugfix

- [Add circuit breaker](https://github.com/nymtech/nym/pull/6143): When the mixnet client's `mix_tx` channel closes during network drops, `OutQueueControl` would retry sending packets through the closed channel, flooding logs and hanging the daemon. This affects all clients (VPN, SOCKS5, native clients), not just VPN .. (Read more in the [PR description](https://github.com/nymtech/nym/pull/6143))

- [Update internal owner address in transferred share](https://github.com/nymtech/nym/pull/6139)

- [Update quic_bridge_deployment.sh for IPv4 and .deb package](https://github.com/nymtech/nym/pull/6138): Updated ping commands to explicitly use IPv4 and adjusted file permission checks with sudo. Changed the forward address prompt to specify IPv4 and modified the binary download process to fetch and install the latest `.deb` release URL automatically

- [Update stored epoch share when changing ownership](https://github.com/nymtech/nym/pull/6135)

- [Update stored epoch share when changing announce address](https://github.com/nymtech/nym/pull/6131)

### Refactors & Maintenance

- [Re-merge: disconnect mixnet client if registration fails](https://github.com/nymtech/nym/pull/6169) ([\#6158](https://github.com/nymtech/nym/pull/6158))

- [Resolve `clippy 1.91` warnings](https://github.com/nymtech/nym/pull/6168)

- [Remove unused dependencies](https://github.com/nymtech/nym/pull/6151): Removing the crates that only shows up on the workspace `Cargo.toml`

- [Use typed-builder for registration client builder config](https://github.com/nymtech/nym/pull/6150)

- [tommy is too quick](https://github.com/nymtech/nym/pull/6149)

## `v2025.19-kase`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.19-kase)
- [`nym-node`](nodes/nym-node.mdx) version `1.20.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-10-30T12:43:37.933354749Z
Build Version:      1.20.0
Commit SHA:         75a6d3426bd18dca600ad1cfa39b0a3c4f319c69
Commit Date:        2025-10-30T11:59:32.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.88.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

**When this platform release becomes latest, we would like to ask operators ruuning any Gateway mode of `nym-node`, to use new version of [QUIC brige deployment tool](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/quic_bridge_deployment.sh) and install QUIC `nym-bridge` on their server, following [these steps](#quic-transport-bridge-deployment).**

Alongside this platform release we are happy to introduce several improvements and new tools for node operators.

- [Updated version of QUIC brige deployment tool](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/quic_bridge_deployment.sh), **if you run a `nym-node` in any Gateway mode, please install QUIC on your server, following [these steps](#quic-transport-bridge-deployment)**

- [New **Nym Node Status Dashboard**](https://node-status.nym.com)

- [New **Harbourmaster** aka ***Nym Node Status Observatory***](https://harbourmaster.nymtech.net)

### Features

- [Propagate cancel token to mixnet client](https://github.com/nymtech/nym/pull/6105): Ensures cancellation token propagation to mixnet client

- [[DOCs/operators] QUIC deployment script & docs](https://github.com/nymtech/nym/pull/6098): Script and documentation for QUIC deployment, referencing `nym-bridges` repository

- [Move gateway probe to monorepo (Rust edition 2024)](https://github.com/nymtech/nym/pull/6094): Moves `nym-gateway-probe` and related packages into monorepo, updates to Rust 2024 edition

- [Expose reference to Mnemonic from `DirectSecp256k1HdWallet`](https://github.com/nymtech/nym/pull/6083): Adds safer accessors for mnemonic references and deprecates unsafe cloning

### Bugfix

- [Cherry pick - request #6143 from nymtech/bugfix/mix-tx-closed-v2](https://github.com/nymtech/nym/pull/6153): Add circuit breaker
<AccordionTemplate name={<TestingSteps/>}>
 **Summary:**
- Network-requester started successfully
- SOCKS5 client started successfully
- Traffic was proxied through the mixnet
- Shutdown was clean
- No 'channel closed (outside of shutdown!)' errors

- [`nym-credential-proxy` query params parsing regression](https://github.com/nymtech/nym/pull/6121): Fix query deserialization issue with `serde_urlencoded` breaking compatibility with VPN API

- [Revert some dep updates introduced in #6043](https://github.com/nymtech/nym/pull/6120): Revert dependency updates that broke ANSI escape characters within tracing output

- [Skip IPv6 metadata endpoint request](https://github.com/nymtech/nym/pull/6118): Skip querying IPv4-only metadata endpoints during IPv6 probing tests

- [Revert "Propagate cancel token to mixnet client"](https://github.com/nymtech/nym/pull/6115): Reverts earlier change due to premature mixnet exit issues

- [Retrieve and update ticketbook in the same query](https://github.com/nymtech/nym/pull/6101): Fix concurrency issue with multiple agents retrieving ticketbooks simultaneously

- [Include network name in default gateway probe config path](https://github.com/nymtech/nym/pull/6100): Prevents reuse of credentials across different networks

- [Incompatibility fixes](https://github.com/nymtech/nym/pull/6099): Fixes several incompatibilities, including initialization and build mismatches

- [Testnet manager `02sql` migration](https://github.com/nymtech/nym/pull/6096): Fix invalid FK constraint blocking SQL migration

- [Use custom topology provider for list of init gateways](https://github.com/nymtech/nym/pull/6092): Fixes SDK bug where clients ignored custom topology provider on registration

- [Fix `WASM` client + build commands](https://github.com/nymtech/nym/pull/6043): Fixes WASM client hang and runtime time-related issues; improves internal dev testing stability

### Refactors & Maintenance

- [Update to no longer use 1mb files](https://github.com/nymtech/nym/pull/6117)

- [Restore pending DKG contract state migration](https://github.com/nymtech/nym/pull/6116)

- [Update `dirs` to `6.0`](https://github.com/nymtech/nym/pull/6109): Minor dependency update, safe for compatibility

## `v2025.18-jarlsberg`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.18-jarlsberg)
- [`nym-node`](nodes/nym-node.mdx) version `1.19.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-10-15T09:04:32.043934599Z
Build Version:      1.19.0
Commit SHA:         2235a6e1477bea7368ee5443a298f544deb63504
Commit Date:        2025-10-15T10:22:16.000000000+02:00
Commit Branch:      master
rustc Version:      1.92.0-nightly
rustc Channel:      nightly
cargo Profile:      release
```

### API Changes
There have been a few updates to the Node Status API (used by the NymVPN API) to do with Nodes' metadata endpoints, which are used to determine if they are running a QUIC bridge.

- [Node Status API: add bridge information to dVPN endpoint](https://github.com/nymtech/nym/pull/6069)
Scrape the `/api/v1/bridges/client-params` endpoint from nodes to get bridge information and add to the dVPN output:

 ```
 {
 	"identity_key": "3wqfp9ebaajgV8HRKYHeZuZCNXgitnW8BbytxyBH65xZ",
 	"name": "middle winner wing",
 	"authenticator": {
 		"address": "6CQMtm9DqUj7mPVkSD9YarjUuPh7mJaZQnnHWxNpgByh.AGXiTivVieBULeDhL9tuyMKgRydoT67sFCjeoERDN84k@3wqfp9ebaajgV8HRKYHeZuZCNXgitnW8BbytxyBH65xZ"
 	},
 	"ip_packet_router": {
 		"address": "GA47h8294m7f6ciyFuDkjk3mmqrvALqboL2o22jkqFhi.22SdTGBWKFrrBM31hMgzjmgduSH1nosnbE9dgNcY2CXz@3wqfp9ebaajgV8HRKYHeZuZCNXgitnW8BbytxyBH65xZ"
 	},
 	"location": {
 		"two_letter_iso_country_code": "GB",
 		"latitude": 51.5085,
 		"longitude": -0.1257
 	},
 	"last_probe": {
 		"last_updated_utc": "2025-09-02T18:19:10Z",
 		"outcome": {
 		"as_entry": {
 			"can_connect": true,
 			"can_route": true
 		},
 		"as_exit": {
 			"can_connect": true,
 			"can_route_ip_external_v4": true,
 			"can_route_ip_external_v6": true,
 			"can_route_ip_v4": true,
 			"can_route_ip_v6": true
 		},
 		"wg": {
 			"can_handshake_v4": true,
 			"can_handshake_v6": true,
 			"can_register": true,
 			"can_resolve_dns_v4": true,
 			"can_resolve_dns_v6": true,
 			"download_duration_sec_v4": 0,
 			"download_duration_sec_v6": 5,
 			"download_error_v4": "",
 			"download_error_v6": "",
 			"downloaded_file_v4": "https://proof.ovh.net/files/1Mb.dat",
 			"downloaded_file_v6": "https://proof.ovh.net/files/10Mb.dat",
 			"ping_hosts_performance_v4": 1,
 			"ping_hosts_performance_v6": 1,
 			"ping_ips_performance_v4": 1,
 			"ping_ips_performance_v6": 0.6666667,
 			"can_handshake": true,
 			"can_resolve_dns": true,
 			"ping_hosts_performance": 1,
 			"ping_ips_performance": 1
 		}
 		}
 	},
 	"ip_addresses": [
 		"178.79.168.250",
 		"2a01:7e00::f03c:95ff:fef8:77f"
 	],
 	"mix_port": 1789,
 	"role": "EntryGateway",
 	"entry": {
 		"hostname": "nym-circ.anonym.tech",
 		"ws_port": 9000,
 		"wss_port": 9443
 	},
 + 	"bridges":{
 + 		"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"
 + 				}
 + 			}
 + 		]
 + 	}
 	"performance": "1",
 	"build_information": {
 		"build_version": "1.16.0",
 		"commit_branch": "build",
 		"commit_sha": "7f97f13799342f864e1b106e8cafc9f6d6c24c0f"
 	}
 }
 ```

- [ns-api: add new fields for probe output for query_metadata and download file size and duration in ms](https://github.com/nymtech/nym/pull/6091)

This PR adds new fields to the Node Status API:

 ```json
 {
   "node": "ByxGq9hpDQu6Wc8augEh22w7CRWJHPNfDshB1b8nfWkh",
   "used_entry": "ByxGq9hpDQu6Wc8augEh22w7CRWJHPNfDshB1b8nfWkh",
   "outcome": {
     "as_entry": {
       "can_connect": true,
       "can_route": true
     },
     "as_exit": {
       "can_connect": true,
       "can_route_ip_v4": true,
       "can_route_ip_external_v4": true,
       "can_route_ip_v6": true,
       "can_route_ip_external_v6": true
     },
     "wg": {
       "can_register": true,
       "can_query_metadata_v4": true, // <--------------------------------
       "can_handshake_v4": true,
       "can_resolve_dns_v4": true,
       "ping_hosts_performance_v4": 1.0,
       "ping_ips_performance_v4": 1.0,
       "can_handshake_v6": true,
       "can_resolve_dns_v6": true,
       "ping_hosts_performance_v6": 1.0,
       "ping_ips_performance_v6": 0.93333334,
       "download_duration_sec_v4": 2,
       "download_duration_milliseconds_v4": 2034, // <--------------------------------
       "downloaded_file_size_bytes_v4": 1048576, // <--------------------------------
       "downloaded_file_v4": "https://nym-bandwidth-monitoring.ops-d86.workers.dev/1mb.dat",
       "download_error_v4": "",
       "download_duration_sec_v6": 5,
       "downloaded_file_size_bytes_v6": 1048576,
       "download_duration_milliseconds_v6": 5501,
       "downloaded_file_v6": "https://proof.ovh.net/files/1Mb.dat",
       "download_error_v6": ""
     }
   }
 }
 ```

- [ns-api: add descriptions to dVPN gateway responses](https://github.com/nymtech/nym/pull/6102)
This PR adds the `description` field to dVPN gateways in `/dvpn/v1/directory/gateways`.

- [NS API: use new probe download filesize and milliseconds field](https://github.com/nymtech/nym/pull/6097)
This PR uses the new fields in mainnet to calculate the probe download score.

- [ns-api: use download files size from probes instead of parsing filenames](https://github.com/nymtech/nym/pull/6095) This PR uses the new field in the probe results that says how many bytes were downloaded to calculate the speed of download. It only uses downloads on ipv4 and ignores ipv6 for now. This might change in the future.

- [Node Status API: remove sqlite support](https://github.com/nymtech/nym/pull/6004)
This PR removes sqlite support, requiring pgsql to run the NS API.

 It also fixes the following issues:

 - deserialisation of `NodeDescription`
 - defaults for `WireguardDetails` for deserialisation

 It also bumps the version to v4.0.0.

### Operators Updates & Tools

- [Node rewards tracker](https://github.com/nymtech/nym/pull/6064)
This PR introduces a script fetching operators rewards based on provided Nyx account addresses provided in `data/wallet-addresses.csv`.

 **Output is:**
     1. Printed table in terminal
     3. Sheet with complete info stored in `data/node-balances.csv`
     4. Historical data yaml file stored in `data/data.yaml` - this file should not be changed manually, as
     all values older than 30 days get auto-removed

 **RUN**

 Before you start fill first column of `data/wallet-addresses.csv` called `addresses` with your Nyx account addresses and (optionally) second column called `tag` with an entity, for example *"mysquad"* and *"personal"* to get sorted output per entity.

 - Csv example with `tag`s:
 ```
 n1foofoofoo, personal
 n1barbarbar, personal
 n1bazbazbaz, mysquad
 n1lollollol, mysquad
 ```
 - For operators having all nodes under one entity, the tag field will be left empty. Example:
 ```csv
 n1foofoofoo
 n1barbarbar
 n1bazbazbaz
 ```

Documentation coming soon.

- [Bugfix/bloomfilters purge](https://github.com/nymtech/nym/pull/6089)
This PR fixes bug where old replay protection bloomfilters were never getting removed.

### Features
- [Get wireguard keypair as arg instead of reading it from disk](https://github.com/nymtech/nym/pull/6078)

- [Registration Client](https://github.com/nymtech/nym/pull/6059)
 This PR introduces the `RegistrationClient` whose eventual job will be to handle registration with gateway and bandwidth control. This is step 1, where it only handles registration and then hands back the control channel to the vpn-client.

 **nym-wg-gateway-client**
 This crate has been smooshed with the nym-authenticator-client as they were doing the same thing : talking with the Authenticator.

 **nym-authenticator-client**
 The job of the `AuthenticatorClient` is to talk to the `Authenticator`s via the mixnet. They both make use of a `AuthClientMixnetListener` that handles interaction with the mixnet client. No more `SharedMixnetClient`, only clear owners. That component could be turned into an actual multiplexer, but that's out of scope.

 It is designed to be able to shut down, since it won't be necessary for bandwidth top up in the future.

 Lots of types and traits were copied in both repos, some of them are sadly still there. Further work could be done to improve messaging ( `ClientMessage` and `AuthenticatorRequests` for example)

 **nym-ip-packet-client**
 This crate has minor changes, focused on getting rid of the `SharedMixnetClient`. It still talks to the `IpPacketRouter` but it owns the `MixnetClient`

 **Nym-registration-client**
 Brand new crates, whose current job is to run a `MixnetClient` with the given options,  register with the component related to the tunnel type, and hand back the necessary component for running the tunnel.

 **authenticator-requests**
 Mostly refactoring, lots of code was duplicated in the vpn-client repo

 **misc**
 The rest are qol changes that might not be needed right away but that is preparing the future improvements coming soon™

- [Feature: Ping probe all nodes /described nodes from a server](https://github.com/nymtech/nym/pull/6074)
This script should be ran from a node hosting server. It pings all IPs listed in /described endpoint and returns a file with unreachable IPs. Such list gives operator an idea on IPs potentially blocking their IP.

- [Feature: Nym node html landing page](https://github.com/nymtech/nym/pull/6053)
This PR introduces a new landing page which contains:
  - no more deprecated tornul
  - new nym theme
  - bold text about DMCA
  - hook for nym-node-cli to use it and add $EMAIL prompted to the operator

- [feat: DKG contract method for updating announce address](https://github.com/nymtech/nym/pull/6050)

- [feat: NS ticket faucet](https://github.com/nymtech/nym/pull/6047)
Overview: modifies the Node Status API so that it keeps a buffer of tickets inside its storage that it gives out when new test runs get requested. it also slightly adjusts the ticketbook API in a bit hacky way to allow importing ticketbooks with specific index ranges. However, those changes also involve modifying cli arguments passed to both NS API and gateway probes. The associated vpn-client repo branch is `feature/ticket-faucet-probe` which for the same reason is not yet ready

**Node Status API**
**Added**
 - `--config-env-file` / `-c` (optional) - helper allowing testing locally on non-mainnet networks without passing everything through env variables
 - `--mnemonic` (env: `NYM_NODE_STATUS_API_MNEMONIC`) - account used for obtaining ticketbooks
 - `--max-concurrent-deposits` (env: `NYM_NODE_STATUS_API_MAX_CONCURRENT_DEPOSITS`) (optional; default: 5) - Specifies the maximum number of deposits the node status api can make in a single transaction. Note that each deposit batch is followed by the same number of sequential signing requests
 - `--tickets-buffer-size` (env: `NYM_NODE_STATUS_API_TICKETS_BUFFER`) (optional; default: 50) - Specifies the size of the tickets buffer the node status api should have available at any time for each ticket type.
 - `--tickets-buffer-check-interval` (env: `NYM_NODE_STATUS_API_TICKETS_CHECK_INTERVAL`) (optional; default: 1min) - Specifies interval at which the node status api should check if it has sufficient number of tickets buffered
 - `--quorum-check-interval` (env: `NYM_NODE_STATUS_API_QUORUM_CHECK_INTERVAL`) (optional; default: 5min) - Specifies interval at which the node status api should check if signing quorum is available
 - `--buffered-ticket-types` (env: `NYM_NODE_STATUS_BUFFERED_TICKET_TYPES`) (optional; default: `[V1MixnetEntry, V1WireguardEntry, V1WireguardExit]`) - Specifies types of tickets to buffer
 - `--ecash-client-identifier-bs58` (env: `NYM_NODE_STATUS_API_ECASH_CLIENT_IDENTIFIER_BS58`) - Identifier used for deriving keys embedded in the issued ticketbooks (i.e. seed for the client identity). It can be a random string, but make sure it has sufficient entropy. it has to be base58 encoded.

**Node Status Agent**
**Removed**
 - `--mnemonic` - no longer needed as tickets are obtained throught the faucet

**Gateway Probe (vpn-client repo)**
**Added**
 - `--ticket-materials` - all the encoded generated tickets (and global data) needed by the probe
 - `--ticket-materials-revision` - revision of the serialisation to help with decoding (not strictly needed, but it was already available)
**Removed**
 - `--mnemonic` - no longer needed as tickets are obtained throught the faucet

- [Bridge proto client params in Self-Described](https://github.com/nymtech/nym/pull/6035)
This PR gives the nym-node a way to expose information about the bridge protocols that the node supports, and the parameters that are necessary to connect using those protocols.

 This is meant to be usable by the node status API to be be included into node descriptors that are compiled for the vpn client.

 - Adds a new field to the nym-node config `gateway_tasks.storage_paths.bridge_client_params`
   - IF the new config field is present a new self-described endpoint is available at `/v1/bridges/client-params`
   - IF the new config field is NOT present the endpoint is not exposed.

 I arbitrarily chose config v8 as the oldest nym-node configuration version that supports the option. This can probably be propogated further backwards if necessary.

 NOTE: The new `/bridges/client-params` endpoint does not have swagger / utopia docs associated. This interface will likely change in several upcoming iterations and serving from file (for now) means that the types are not defined internally.

 tested as working on node `3wqfp9eb` both when file is provided in config (sucessful response) and when file is not specified in config (path gives 404).

### Refactors & Maintenance
- [[chore] Clippy fix](https://github.com/nymtech/nym/pull/6060)

- [Bugfix: Nym node CLI download nym-node exception](https://github.com/nymtech/nym/pull/6058)
This PR fixes a case when the "Latest" platform release doesn't include `nym-node` by prompting user to insert binary URL instead of failing. Additionally it fixes fetching new landing page script in the CLI.

- [Benny/ci contract fix](https://github.com/nymtech/nym/pull/5962)

- [frontdoor typo fix](https://github.com/nymtech/nym/pull/6067)

- [Hotfix: Update API source in node ping tester script](https://github.com/nymtech/nym/pull/6082)
This PR fixes initial development bug where a wrong API endpoint was used.
 `https://validator.nymtech.net/api/v1/nym-nodes/described` gets all nym nodes, not just gateways.
 Code is simplified accordingly.

## QUIC Transport Bridge Deployment

## `v2025.17-isabirra`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.17-isabirra)
- [`nym-node`](nodes/nym-node.mdx) version `1.18.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-10-01T10:42:58.647419869Z
Build Version:      1.18.0
Commit SHA:         bbea2ff9e913f49cb7bf6c7bafa9d9b158c80de5
Commit Date:        2025-10-01T12:06:07.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.88.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

**With `nym-node` version `1.18.0` operators need to make `tcp/51830` reachable on the WG interface (for bandwidth queries/topup).**

This is inside the tunnel - no need to expose it publicly unless you want an external test.
**Run this command to expose it:**
```
ufw allow in on nymwg to any port 51830 proto tcp
```

With this platform upgrade we are releasing several tools to improve operator experience. Check them out and let us know what you think.

- **New program for `nym-node` automated installation**: [`nym-node-cli.py`](tools#nym-node-cli)

- **New node reward tracker**: [`node_rewards_tracker.py`](tools#cmd-reward-tracker)

- **New server ping testing diagnostic tool**: [`test-nodes-pings.sh`](tools#node-ping-tester)

- **New [Tools page](tools)**

- **New Gateway landing page [template](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/landing-page.html)** and simplified [documentation for reverse proxy configuration](nodes/nym-node/configuration/proxy-configuration#html-file-customization)

- SpectreDAO Explorer has a new [Delegation Wizzard](https://explorer.nym.spectredao.net/delegate): Allowing for a smart multi-delegation with optimal node selection form Keplr Wallet

### API Changes

Please read carefully below to follow up with API removal and changes to ensure that your development is up to date.

#### Nym API Removed Routes

All of the routes removed had already been deprecated over a year ago. This is mostly due to the fact that either they were returning only data on legacy nodes (that could never be used anyway) or required some non-sense conversions. Open the dropdown below to see removed routes

### Legacy mixnodes related:

- `/v1/mixnodes`
- `/v1/mixnodes/active`
- `/v1/mixnodes/active/detailed`
- `/v1/mixnodes/described`
- `/v1/mixnodes/rewarded`
- `/v1/mixnodes/rewarded/detailed`
- `/v1/mixnodes/detailed`
- `/v1/mixnodes/blacklisted`
- `/v1/status/mixnodes/active/detailed`
- `/v1/status/mixnodes/rewarded/detailed`
- `/v1/status/mixnodes/detailed`
- `/v1/status/mixnodes/inclusion-probability`
- `/v1/status/mixnodes/inclusion-probability`
- `/v1/status/mixnode/{mix_id}/inclusion-probability`
- `/v1/status/mixnode/{mix_id}/stake-saturation`
- `/v1/status/mixnode/{mix_id}/status`
- `/v1/status/mixnode/{mix_id}/reward-estimation`
- `/v1/status/mixnode/{mix_id}/compute-reward-estimation`
- `/v1/status/mixnodes/detailed-unfiltered`
- `/v1/status/mixnode/{mix_id}/report`
- `/v1/status/mixnode/{mix_id}/avg_uptime`

### Legacy gateways related:

- `/v1/gateways`
- `/v1/gateways/described`
- `/v1/gateways/blacklisted`
- `/v1/status/gateways/detailed`
- `/v1/status/gateways/detailed-unfiltered`
- `/v1/status/gateway/{identity}/report`
- `/v1/status/gateway/{identity}/avg_uptime`

#### Structs changes:

- `MixnodeUptimeHistoryResponse` no longer has `owner` field
- `GatewayUptimeHistoryResponse` no longer has `owner` field

#### New Routes Added

- `/v1/nym-nodes/stake-saturation/{node_id}` - as a better replacement for `/v1/status/mixnode/{mix_id}/stake-saturation` as this information might be potentially useful and can be applied to any nym-node, not just a legacy mixnode.
- `/v1/legacy/mixnodes` - returns a list of bonded legacy mixnodes that haven't migrated to nym-nodes
- `/v1/legacy/gateways` - returns a list of bonded legacy gateways that haven't migrated to nym-nodes

#### Node Status API

Furthermore the changes remove all scraping of legacy mixnodes from NS and the following routes are removed:

- `/v2/mixnodes/{mix_id}`
- `/v2/mixnodes`

### Features

- [Refresh mixnet contract on epoch progression](https://github.com/nymtech/nym/pull/6023): Currently when an epoch has advanced, `nym-api` might still be serving data from the previous iteration. This PR makes sure the data is refreshed as soon as possible so new role assignment would be available quickly after.

- [Explorer-v2: Replace recommended servers with automated selection](https://github.com/nymtech/nym/pull/6019): Use params to get 10 nodes, no more manual paste.

- [Credential proxy crate](https://github.com/nymtech/nym/pull/6018): This PR moves 90% of the credential proxy functionalities into a common crate instead.

- [Moving clients crate from vpn-client repo to here](https://github.com/nymtech/nym/pull/6015): As part of the registration-client work, moved `nym-authenticator-client`, `nym-ip-packet-client` and `nym-wg-gateway-client` from the vpn-client repo into this repository.

- [Cancellation migration](https://github.com/nymtech/nym/pull/6014): Migrates shutdown watchers from `TaskManager` into the new `ShutdownManager`, which relies on tokio’s `CancellationToken` and `TaskTracker`.

- [Use `ShutdownToken` for nym-api](https://github.com/nymtech/nym/pull/5997): Makes `nym-api` use `ShutdownToken` (tokio `CancellationToken` inside) for cancellation; groundwork for migrating clients to the same approach.

- [Delegation program stake checker and adjuster](https://github.com/nymtech/nym/pull/5980): Adds a script to generate a CSV for delegation adjustments according to Delegation Program rules, including node/stake/uptime/version and other fields.

- [Domain fronting integration](https://github.com/nymtech/nym/pull/5974): Completes migration to `nym_http_api_client::Client`, enabling domain fronting and unifying HTTP client usage across the monorepo.

- [Shared library for attempting to retrieve update mode attestation](https://github.com/nymtech/nym/pull/5954): Part of NET-341, provides a shared library to attempt retrieving update mode attestation.

- [Credential proxy deposit pool](https://github.com/nymtech/nym/pull/5945): Changes the credential proxy to hold a pool of available deposits and monitor quorum state, reducing wastage and improving reliability.

- [Nym signers monitor](https://github.com/nymtech/nym/pull/5933): Independent tool for checking the status of network signers and sending notifications if “upgrade” mode is detected.

- [Nym node autorun CLI](https://github.com/nymtech/nym/pull/5916): Adds an interactive CLI to install, set up, and configure `nym-node` as a systemd service, improving operator experience.

### Bugfix

- [Fix the registration handshake](https://github.com/nymtech/nym/pull/6062): Resolves issues in the registration handshake process.

- [Return from MixTrafficController if client request channel has closed](https://github.com/nymtech/nym/pull/6002): Ensures the MixTrafficController exits properly when the client request channel closes.

- [Use default value for the ports until api is deployed](https://github.com/nymtech/nym/pull/6007): Fixes VPN querying mainnet for the API and not finding some of the newly added values by using default port values until the API is deployed.

- [Recipient deserialisation for deserialisers missing bytes specialisation](https://github.com/nymtech/nym/pull/5991): Fixes deserialization where formats like TOML/JSON defaulted incorrectly, ignoring bytes-related optimisations.

- [Use WASM compatible time API in client](https://github.com/nymtech/nym/pull/5948): Prevents client crashes in WASM by replacing time APIs unavailable in that environment.

### Refactors & Maintenance

- [Convenience for ShutdownTracker](https://github.com/nymtech/nym/pull/6038): Adds a method to create a `ShutdownToken` from a `CancellationToken`. Exposes `ShutdownTracker` in the SDK.

- [Made http-api-client-macro doctest compile](https://github.com/nymtech/nym/pull/6037): Adjusts doctests in `http-api-client-macro` so they compile.

- [Remove legacy nodes from nym api](https://github.com/nymtech/nym/pull/6021): Removes nearly all references to legacy nodes from `nym-api` and node status API; cleans up deprecated endpoints and adjusts structs.

- [Upgraded syn to 2.0 and removed nym-execute](https://github.com/nymtech/nym/pull/5998): Updates the `syn` dependency and removes `nym-execute`.

- [Use updated version of simulate endpoint](https://github.com/nymtech/nym/pull/5988): Switches to the updated simulate endpoint.

- [Purge temp databases on build](https://github.com/nymtech/nym/pull/5984): Prevents build failures when switching to branches without DB migrations by cleaning temp databases during builds.

- [Internal hidden command to force advance nyx epoch](https://github.com/nymtech/nym/pull/5964): Adds a hidden developer command to advance the Nyx epoch manually.

- [Create an axum_test client for more integrated unit testing](https://github.com/nymtech/nym/pull/5956): Adds an `axum_test` client to support more integrated unit tests.

- [Revert "Create an axum_test client for more integrated unit testing"](https://github.com/nymtech/nym/pull/5999): Reverts PR #5956 due to OpenSSL dependency issues.

## `v2025.16-halloumi`

- **[`nym-node`](nodes/nym-node.mdx) is not part of the release, the latest stays on version `1.16.0`**
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.16-halloumi)

### Operators Updates & Tools

Nodes receiving stake as a part of [**Nym Delegation Program**](https://nym.com/network/DP) are updated weekly based on the [rules](https://forms.nym.com/form/#/2/form/view/BRh8QroXFinjOF4D3FHgYiX76zbiRvUV2Sy+czaoKFQ) without prior notification given to the operators.

[**Nym Delegation account**](https://explorer.nym.spectredao.net/account/n1rnxpdpx3kldygsklfft0gech7fhfcux4zst5lw) `n1rnxpdpx3kldygsklfft0gech7fhfcux4zst5lw` is a single source of truth. If you expect your node to have Nym team stake and it doesn't, please reach out in in the [**Node Operators Matrix channel**](https://matrix.to/#/#operators:nymtech.chat).

- New [Delegation Program page is out](https://nym.com/network/DP)
- Complete rules and application form are [here](https://forms.nym.com/form/#/2/form/view/BRh8QroXFinjOF4D3FHgYiX76zbiRvUV2Sy+czaoKFQ)

### Features

- [Wireguard private metadata](https://github.com/nymtech/nym/pull/5915)

- [Change PK/FK on expiration date signatures tables](https://github.com/nymtech/nym/pull/5934)

- [Introduce additional checks when attempting to send to bounded channels](https://github.com/nymtech/nym/pull/5941)

- [Wireguard metadata client library](https://github.com/nymtech/nym/pull/5943): Tested end to end using [\#3316](https://github.com/nymtech/nym-vpn-client/pull/3316) in canary, with a pair of gateways that has the changes deployed:
```
nym-vpnc connect --enable-two-hop  --entry-gateway-id 7CWjY3QFoA9dgE535u9bQiXCfzgMZvSpJu842GA1Wn42 --exit-gateway-id 7fp3cmzCvgeRgbB1ycTnK6RokjH
```

- [Feature/testing utils](https://github.com/nymtech/nym/pull/5963): This PR introduces a couple of general helpers, in particular some mocks for sending across values using Stream/Sink and AsyncRead/AsyncWrite without actual underlying networking. Example implementation are with NymNoise (which was the original inspiration) and gateway handshake.

- [Backport metadata endpoint](https://github.com/nymtech/nym/pull/6010)

### Bugfix

- [Fix rust `1.89` `clippy` issues](https://github.com/nymtech/nym/pull/5944)

- [`http api` client adjustment](https://github.com/nymtech/nym/pull/5953): It fixes missing `feature-lock` when cloning the client and adds helper macro for user agent creation

- [Fix `ci-build` for linux (and use updated runner)](https://github.com/nymtech/nym/pull/5958): This PR fixes our build pipeline by using correct (updated) linux runner and updates all the conditional steps that were behind `ubuntu` runners (which no longer exist)

- [Fixing the ci for ns agent](https://github.com/nymtech/nym/pull/5965)

- [Manually calculate per node work on rewarded set changes](https://github.com/nymtech/nym/pull/5972): This PR fixes:
    1. Nym rewarded set was set to X, for argument sake say 200
    2. We sent transaction to update it to Y, say 100
    3. This internally updated the interval rewarding parameters inside the mixnet contract including the default active and standby node work factors. Note that the rewarded set itself stayed the same, as it only changes after epoch rolls over and new one is assigned (by the `nym-api`)
   4. Epoch has finished and `nym-api` wanted to do the rewarding. It grabbed the **current** rewarded set (of X, 200) and started calculating the total work in the system. But since the contract already had new parameters (adjusted for size of Y, 100), the result was greater than 1 thus `nym-api` was preventably blowing up.
    To fix it we introduce additional checks, so that if the current rewarded set does not match the specification defined in the contract rewarding parameters, `nym-api` will attempt to do its best to manually calculate work factors for this epoch.

- [Fix the ns api ci workflow](https://github.com/nymtech/nym/pull/5981)

- [Make sure tables are removed in correct order to not trigger FK constraint issue](https://github.com/nymtech/nym/pull/5987)

### Refactors & Maintenance

- [Move credential verifier in peer controller](https://github.com/nymtech/nym/pull/5938): This PR is to not duplicate the verifier code (minus the actual verification operation, which is harder to unit test because of expiration checks)

- [Remove unused import](https://github.com/nymtech/nym/pull/5942)

- [Updated refs to cheddar rev of nym repo](https://github.com/nymtech/nym/pull/5955)

- [Update `sysinfo` to the latest](https://github.com/nymtech/nym/pull/5976): Shakes out `windows@0.57` from the tree

- [Remove freshness check on testrun submit](https://github.com/nymtech/nym/pull/5977):
    - Freshness is enforced by a background task that marks test runs as stale after a configured amount of time
    - Make existing freshness period configurable to avoid code changes in the future
    - Added `humantime` for parsing

- [Move authenticator into gateway crate](https://github.com/nymtech/nym/pull/5982)

## `v2025.15-gruyere`

- **[`nym-node`](nodes/nym-node.mdx) is not part of the release, the latest stays on version `1.16.0`**
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.15-gruyere)

### Operators Updates & Tools

- [**NIP-3: Nym Exit Policy Update**](https://forum.nym.com/t/nip-3-nym-exit-policy-update/1462/2) resulted by operators [governance](https://governator.nym.com/proposal/prop-d0c0d398-43bd-4a6f-b008-1921b64ae4ed) is implemented.

- If you operate a node routing wireguard, please re-run [these steps](nodes/nym-node/configuration#wireguard-exit-policy-configuration) to update your wireguard exit policy through IP tables rules.

- [**NIP-2: Changing stake saturation**](https://governator.nym.com/proposal/prop-8dfa4a28-55b1-45a5-968f-f2897c2670df) will be implemented soon, with that we are going to adjust rules of Delegation Program. **Join [Community call ](https://www.youtube.com/watch?v=KaO6-WLWzMo) on Thursday August 21st, 14:00UTC** to find out more info.

### Features

- [Remove old free credential handle](https://github.com/nymtech/nym/pull/5864): And create some traits for unit testing purposes.

- [Ecash liveness check](https://github.com/nymtech/nym/pull/5890)

- [Basic zulip client for sending messages](https://github.com/nymtech/nym/pull/5913): In order to be able to send zulip notifications about *emergency* upgrade mode being activated, we need some sort of client. Unfortunately there isn't any rust library that's maintained (the only one had last commit 4 years ago). This simple thing now currently only supports message sending

- [`nym-node` debug command to reset providers db](https://github.com/nymtech/nym/pull/5914)

- [Make DNS Resolver fallback optional](https://github.com/nymtech/nym/pull/5920): Default to no dns system fallback, but keep support in the custom hickory dns resolver used for resolving internal domains.

- [WG exit policy scripts update](https://github.com/nymtech/nym/pull/5921): This PR modifies the scripts `wireguard-exit-policy-manager.sh` and `exit-policy-tests.sh` supporting operators to easily configure and test their IP tables rules in order to have same exit policy for WG as the one for NR, adding the ports decided to be enabled in [NIP-3](https://governator.nym.com/proposal/prop-d0c0d398-43bd-4a6f-b008-1921b64ae4ed) protocol upgrade.

### Refactors & Maintenance

- [Allow compatibility with 'CDLA-Permissive-2.0'](https://github.com/nymtech/nym/pull/5910): This license is present in the included `webpki-roots`

- [Migrate strum to `0.27.2`](https://github.com/nymtech/nym/pull/5960): This PR migrates strum to the latest. Notably all macros' were moved into `strum_macros`. The rest stays the same.

## `v2025.14-feta`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.14-feta)
- [`nym-node`](nodes/nym-node.mdx) version `1.16.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-08-05T09:14:30.322593213Z
Build Version:      1.16.0
Commit SHA:         7f97f13799342f864e1b106e8cafc9f6d6c24c0f
Commit Date:        2025-07-24T11:00:58.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

-  Stark Industries is on a sanction list by EU. IP addresses managed by Stark Ind. and their subsidies (ASN 44477 / ASN 33993) had been put on [spamhaus.org](http://spamhaus.org/) [list](https://www.spamhaus.org/drop/asndrop.json). The effect on NymVPN user experience is that Exit Gateways IPs hosted on Stark Ind. are seen as a spam proxies by many online services.

- We ask operators - especially Exit Gateways - to consider moving to another ISP. Visit an updated [ISP list](community-counsel/isp-list) and feel free to add more providers, following [these steps](community-counsel/add-content).

### Features

- [Allow PG database backend](https://github.com/nymtech/nym/pull/5880):
    - Added PostgreSQL database support alongside existing SQLite through Cargo feature flags
    - Implemented runtime query conversion from SQLite `?` placeholders to PostgreSQL `$1`, `$2`, ... format
    - Single codebase now supports both databases without query duplication

- [Support mnemonic in the NS agent](https://github.com/nymtech/nym/pull/5883)

- [`sqlx-pool-guard`: allocate more memory on windows](https://github.com/nymtech/nym/pull/5896):
    - Allocate 1.5x more memory than reported by the system to provide a safety margin
    - Increase number of retry attempts to 5

- [dkg epoch dealers query](https://github.com/nymtech/nym/pull/5899)

- [dkg snapshot epoch](https://github.com/nymtech/nym/pull/5900): In order to determine if signer quorum has been down at particular height, we need to know with certainty the dkg epoch id corresponding to given block height. This PR makes it possible. Every time epoch state is changed (due to DKG progress), snapshot is saved and can be queried. This doesn't work for past data, but given mainnet has only had a single DKG instance, that's not an issue.

- [`sqlx-pool-guard`: obtain filename from connect options](https://github.com/nymtech/nym/pull/5905):

### Refactors & Maintenance

- [Nym node tokio console](https://github.com/nymtech/nym/pull/5909)

## `v2025.13-emmental`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.13-emmental)
- [`nym-node`](nodes/nym-node.mdx) version `1.15.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-07-22T09:24:35.790560275Z
Build Version:      1.15.0
Commit SHA:         578c9b0567656d86812aa21eb0b4c93b5a7235bd
Commit Date:        2025-07-22T11:09:35.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- [**NIP-3: Nym Exit Policy Update**](https://forum.nym.com/t/nip-3-nym-exit-policy-update/1462/2) is out - **VOTE [HERE](https://governator.nym.com/proposal/prop-d0c0d398-43bd-4a6f-b008-1921b64ae4ed)!**

- `nym-node` can only run one `--mode` at a time. Multiple mode nodes will fail to start.

### Features

- [Initial performance contract](https://github.com/nymtech/nym/pull/5833): Introduces the foundational structure of the performance contract. Not yet integrated into any system.

- [Basic performance contract integration within Nym API](https://github.com/nymtech/nym/pull/5871): Integrates the performance contract into `nym-api`, enabling node score source selection from the contract (disabled by default).

- [Forbid running `mixnode` + `entry-gateway` on the same node](https://github.com/nymtech/nym/pull/5878): Prevents configuration of `mixnode` and `entry-gateway` node on the same host.

- [HTTP Discovery objects & network defaults](https://github.com/nymtech/nym/pull/5814): Adds config options for expanded API URLs via discovery environment objects.

- [Add build info endpoints](https://github.com/nymtech/nym/pull/5857)

- [Batch SQL writes for packet stats](https://github.com/nymtech/nym/pull/5874)

- [Update push-node-status-agent.yaml](https://github.com/nymtech/nym/pull/5882): Adds input for setting release tag and prefixes image tag with `golden-`.

- [Make Mix hops optional for Mixnet Client SURBs](https://github.com/nymtech/nym/pull/5861): Allows SURBs to be configured to only use gateways in the mixnet return path.

- [Check gateway supported versions](https://github.com/nymtech/nym/pull/5860)

- [Clear out screaming logs](https://github.com/nymtech/nym/pull/5856): Removes unnecessary alarming log messages.

- [Use display when printing paths](https://github.com/nymtech/nym/pull/5853): Uses Rust’s `display()` method for better path output.

- [Remove old explorer references](https://github.com/nymtech/nym/pull/5846)

- [Listen for shutdown signals during nym-node startup](https://github.com/nymtech/nym/pull/5879): This is to avoid situation where the process can't be killed without 'kill -9' because the logic to listen to shutdown signals hasn't been hit yet

### Bugfix

- [Don't allow mixnode running in exit mode](https://github.com/nymtech/nym/pull/5898)

- [Fix contract build process in Makefile](https://github.com/nymtech/nym/pull/5892)

- [Ignore 'Send' responses when claiming bandwidth](https://github.com/nymtech/nym/pull/5884)

- [Fix the broken link](https://github.com/nymtech/nym/pull/5873)

- [Scraper bugfix: ignore precommits from missing validators](https://github.com/nymtech/nym/pull/5867)

- [Fix removal of qa env](https://github.com/nymtech/nym/pull/5855)

- [Return true remaining](https://github.com/nymtech/nym/pull/5866)

### Refactors & Maintenance

- [chore: 1.88 clippy](https://github.com/nymtech/nym/pull/5877): Applies clippy fixes based on recent compiler version update.

- [Security patches for the `dkg` crate](https://github.com/nymtech/nym/pull/5828): Addresses overflows, unsafe RNGs, and integrity checks as per Cryspen audit.

## `v2025.12-dolcelatte`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.12-dolcelatte)
- [`nym-node`](nodes/nym-node.mdx) version `1.14.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-07-09T12:50:32.123212812Z
Build Version:      1.14.0
Commit SHA:         089c47cce70ef8ea5ecfe3d00b52e510d006e120
Commit Date:        2025-07-07T15:44:15.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- **[Nym Governator](https://governator.nym.com) is out!** Make sure to check out this new operators governance tool and vote on:
    - [**NIP-1:** Proposing NIP as process to propose and log changes to the Nym network](https://governator.nym.com/proposal/prop-9719838a-e86d-4227-8141-dfd5c651ed92)
    - [**NIP-2:** Change stake saturation and active set to improve network decentralisation and efficiency](https://governator.nym.com/proposal/prop-8dfa4a28-55b1-45a5-968f-f2897c2670df)

### Features

- [Nympool contract](https://github.com/nymtech/nym/pull/5464): This is the first iteration of the nympool contract. It's currently **not yet** integrated with the mixnet contract.

- [Noise XKpsk3 integration (2025 version)](https://github.com/nymtech/nym/pull/5692)

- [Key rotation](https://github.com/nymtech/nym/pull/5777)

- [HTTP Client Retries, Fallbacks, and Redirects](https://github.com/nymtech/nym/pull/5789)

- [Close sqlite pool before moving or reopening databases](https://github.com/nymtech/nym/pull/5796): Our sqlite db recovery and backup strategies don't work on Windows because the OS prevents moving the already open file. This PR attempts to address this and in principle it attempts to close all connections to the database and ensure that sqlx relinquishes the access to db file(s). Short summary of what this PR introduces:

  1. Close sqlx connection pools in order to close/release the db file
  2. Poll until there are no more db file descriptors left open.

- [Replace chrono with time in NS API](https://github.com/nymtech/nym/pull/5811)

- [Use the same client bandwidth for top up](https://github.com/nymtech/nym/pull/5813)

- [ Node status dvpn directory](https://github.com/nymtech/nym/pull/5829)

- [Removing test-net faucet](https://github.com/nymtech/nym/pull/5840)

- [Amended the buy section](https://github.com/nymtech/nym/pull/5841): Change the wallet to include the buy options for NYM

- [Remove bity dir](https://github.com/nymtech/nym/pull/5844)

- [Remove not used old `mock-api`](https://github.com/nymtech/nym/pull/5845)

- [Remove qa env](https://github.com/nymtech/nym/pull/5847)

- [Remove/old env references](https://github.com/nymtech/nym/pull/5848)

- [Updated browser extension piece removal](https://github.com/nymtech/nym/pull/5849): Keep all the `internal-dev wasm` pieces as future examples
  - everything previously was going to be removed
  - shows functioning `wasm` interaction with the `js`

### Bugfix

- [Fixed typo in API endpoint parameter](https://github.com/nymtech/nym/pull/5449)

- [Adjust heuristic for wireguard peer activity](https://github.com/nymtech/nym/pull/5818)

- [Url scheme warning log](https://github.com/nymtech/nym/pull/5819): Fix conditions for logging about url scheme. Warns only if the provided urls are not HTTP or HTTPS, as intended.

- [Bug Fix for Wallet build](https://github.com/nymtech/nym/pull/5820): Revert url used for `connection-tester` to default `url::Url`.

- [Fix swapped total and circulating supplies](https://github.com/nymtech/nym/pull/5822)

- [Fixed client route for obtaining v2 list of gateways](https://github.com/nymtech/nym/pull/5859)

- [Allow gateways to permit authentication from v4 clients](https://github.com/nymtech/nym/pull/5862)

- [Backwards compat](https://github.com/nymtech/nym/pull/5865)

## `v2025.11-cheddar`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.11-cheddar)
- [`nym-node`](nodes/nym-node.mdx) version `1.13.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-06-10T09:41:31.291089877Z
Build Version:      1.13.0
Commit SHA:         ef220882d4bcf0a8a703ea62f9273e017c9ebb51
Commit Date:        2025-06-10T11:39:20.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```
### Operators Updates & Tools

- **Nym Improvement Proposals**: NIPs are being introduced, allowing us to propose changes to the Nym network and ecosystem, and decentralise governance
- **NIP1** will outline the governance process: Its draft will be published soon for discussion
- **NIP2** will be about reducing the stake saturation point variable, which would make reward distribution across the network more equitable
- **Join the Operator AMA next Tuesday** for an in-depth overview of what this all means (feat Nym Chief Scientist Claudia Diaz)
- Keep an eye on our channels for information about how to participate in the upcoming voting (no need for forum registration, we are building something new!)

### Features

- [Track wireguard credential retries](https://github.com/nymtech/nym/pull/5783)

- [Swap a decode into a `fromrow` to please future `postgres` feature](https://github.com/nymtech/nym/pull/5785): This PR change a sqlx derive from `Decode` to `FromRow` because a future PR will bring the `postgres` feature and it doesn't like that `Decode` there

- [Fix contains ticketbook function that always returned true](https://github.com/nymtech/nym/pull/5787)

- [QoL: `RequestPath` trait for `http-api-client`](https://github.com/nymtech/nym/pull/5788): Those `PathSegments` in `ApiClient` weren't very user-friendly. Instead we've defined a `RequestPath` trait that allows you to also pass a good old `&str` or `String` and internally it does exactly the same sanitization as before. `PathSegments` are also fully supported to not break any existing compatibility.

- [Nym Statistics API](https://github.com/nymtech/nym/pull/5800):
    - Types for `nym-vpn-client`: It introduces `VpnClientStatsReport` which will be used by nym vpn clients to report statistics. Those types are in the monorepo because they're used by the `num-statistics-API`
    - Nym Statistics API: Basically a `REST API` with a `postgres` backend. In this first iteration, it only accepts `VpnClientStatsReport` and stores them in its database. It optionally connects to the Nym API to confirm reports are coming from the network and attach country code to them if it's the case (exit node country code).

- [Resolve 1.87 clippy warnings](https://github.com/nymtech/nym/pull/5802)

- [Adjusted wallet storybook mocks to fix the build](https://github.com/nymtech/nym/pull/5804)

- [Set cached storage counters to 0](https://github.com/nymtech/nym/pull/5812)

- [No autoremoval of peers](https://github.com/nymtech/nym/pull/5831)

## `v2025.10-brie`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.10-brie)
- [`nym-node`](nodes/nym-node.mdx) version `1.12.0`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-05-27T10:13:18.511075453Z
Build Version:      1.12.0
Commit SHA:         1c6db86259d08d80e8bcfbc4fcc71ccb147fcfd0
Commit Date:        2025-05-27T12:11:13.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- [**Reward calculator**](tokenomics/mixnet-rewards#rewards-logic--calculation): A quick app to calculate rewards for any node included in the Mixnet active set
- **Backup your nodes: Stark Industries Solutions and its subsidy PQ.Hosting were added to EU's sanction list**. Everyone running a node on PQ or Stark in Europe should get additional service free of charge and back up their node there.
- **We recommend operators using Stark Industries Solutions and PQ.Hosting to start looking for alternatives.** Here are some useful pages:
  - [Backup a node](nodes/maintenance#backup-a-node)
  - [Backup proxy conf](nodes/maintenance#backup-proxy-configuration)
  - [Restore a node](nodes/maintenance#restoring-a-node)
  - [Restore proxy conf](nodes/maintenance#restoring-proxy-configuration)
  - [Move a node](nodes/maintenance#moving-a-node)

-  **Nym Squad League (NSL) now supports monthly payments.** Report your monthly contributions before the end of the week (May 30, Friday) to get your tokens next week. Alternatively, you can report everything all at once at the end Spring Season (Deadline: Wednesday, June 18). Read more about NSL at [forum.nym.com](https://forum.nym.com/).

### Features

- [`RememberMe` is the new don't `ForgetMe`](https://github.com/nymtech/nym/pull/5742): Sessions stats collected from gateway proved themselves to be incredibly noisy. In an effort to reduce the noise, `ForgetMe` was introduced at the end of sessions to prompt gateways to forget a specific session. This flag helped reduce the amount of noise, but alone it's not enough (e.g. `ForgetMe` can't be sent by non-sdk client). Therefore we're turning the whole thing and around and introducing a `RememberMe` flag, to prompt the gateways to actually remember said session. Read more in the [dev description of the PR](https://github.com/nymtech/nym/pull/5742).

- [Remove old test directory - Update validator docker](https://github.com/nymtech/nym/pull/5743): The docker directory was extremely old - replaced it with a validator start up with docker compose

- [`nym-api` `bincode` and `yaml` support](https://github.com/nymtech/nym/pull/5745): Support for `nym-api` to return responses as either `bincode` or `yaml` (on top of existing, default, `json`). Furthermore, initial client support for nodes-related queries is introduced. further endpoints can be enhanced by simply pushing `("output", "bincode")` params. Here is the sample response size difference when using `json` vs `bincode` (with and without `gzip` enabled on top of it):

| Endpoint                                            | `json`    | `json` + `gzip` | `bincode` | `bincode` + `gzip` |
| --------------------------------------------------- | ------- | ----------- | ------- | -------------- |
| `/v1/nym-nodes/described`                           | 882,684 | 204,265     | 437,204 | 192,752        |
| `/v1/unstable/nym-nodes/skimmed/entry-gateways/all` | 116,268 | 27,991      | 39,755  | 25,589         |
| `/v1/unstable/nym-nodes/skimmed/mixnodes/active`    | 44,646  | 11,371      | 14,021  | 10,235         |
| `/v1/ecash/aggregated-coin-indices-signatures`      | 11,669  | 6,037       | 4,952   | 4,980          |
| `/v1/network/chain-status`                          | 1,523   | 828         | 1,004   | 585            |
| `/v1/nym-nodes/rewarded-set`                        | 1,221   | 616         | 679     | 529            |

- [Decrease default average packet delay to 15 ms](https://github.com/nymtech/nym/pull/5754)

- [Expires header for `/active` `nym-api` responses](https://github.com/nymtech/nym/pull/5755)

- [Raw route submissions](https://github.com/nymtech/nym/pull/5756)

- [Add `node_bonded` field to delegations](https://github.com/nymtech/nym/pull/5759): Clarifies whether the delegation is to a bonded or un-bonded node and include delegations to unbonded nodes in the returned list

- [Instrument `create_request`](https://github.com/nymtech/nym/pull/5760): In the `vpn-api` client we create requests directly, so let's instrument them as well as the currently instrumented top-level function `get_json` doesn't capture that

- [Use bincode by default in NymApiClient + remove feature-lock](https://github.com/nymtech/nym/pull/5761)

- [Fetch the topology from the `nym-api` concurrently](https://github.com/nymtech/nym/pull/5767): When fetching the topology from the `nym-api`, multiple `GET` are done. We can do these concurrently as a simple way to speed things up. Some basic testing locally shows about 30% less time for the mixnet client to connect.

- [Skip refreshing the topology on startup as we already have an initial set](https://github.com/nymtech/nym/pull/5768)

- [Teach `HttpClientError` how to report its status code and timeout](https://github.com/nymtech/nym/pull/5770): Provide two delegated methods so that we don't have to use `reqwest` in the vpn client repo to access this information

- [Expanded `Accept Encoding` for `reqwest`](https://github.com/nymtech/nym/pull/5779): The accept encoding that we are sending has a logic fallacy in that it is supposed to prefer `gzip`, and fall back to plaintext. What it actually requests is `gzip`, but if that isn't available, anything else is fine. This is an issue because some cloud cached API endpoints are optimistic about support for `br` and the `reqwest` client isn't  actually configured to handle decompressing that so it returns the still encoded value to the calling application instead of the expected json. Enable support for more content encoding types through `reqwest`. This gives the server side more flexibility, which it seems to want, and we now only request the specific `content-encodings` that we will definitely be able to parse. Applications using the api client should no longer receive data still encoded as `reqwest` should manage decompressing it for us.

### Bugfix

- [Fix parallel feature in ecash crate with `Send + Sync`](https://github.com/nymtech/nym/pull/5744): In the current state, the `nym-compact-ecash` crate doesn't compile with the feature flag `par_verify` and `par_signing` because generic type `B` is not `Send + Sync` and so `par_iter` can't be called on it.

- [Downgrade deranged crate to `0.4.0`](https://github.com/nymtech/nym/pull/5746): Downgrade the crate `deranged` from `0.4.1` to `0.4.0`, as `0.4.1` was yanked
 and is flagged by `cargo audit`

- [Upgrade prometheus crate to fix security warning](https://github.com/nymtech/nym/pull/5747): Upgrade the `prometheus` crate to bump the version of the `protobuf`
 crate, which is flagged by `cargo audit` as having a security issue:

```bash
 Crate:     protobuf
 Version:   2.28.0
 Title:     Crash due to uncontrolled recursion in protobuf crate
 Date:      2024-12-12
 ID:        RUSTSEC-2024-0437
 URL:       https://rustsec.org/advisories/RUSTSEC-2024-0437
 Solution:  Upgrade to >=3.7.2
 Dependency tree:
 protobuf 2.28.0
 └── prometheus 0.13.4
```
- [Update `pretty_env_logger` to latest to not depend on unmaintained crate atty](https://github.com/nymtech/nym/pull/5748): The crate `atty` is flagged to be unmaintained and also having some security issues.

- [Remove `pretty_env_logger` and switch remaining crates to use tracing](https://github.com/nymtech/nym/pull/5749)

## `v2025.9-appenzeller`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.9-appenzeller)
- [`nym-node`](nodes/nym-node.mdx) version `1.11.0`

```shell
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-05-13T14:48:01.050934949Z
Build Version:      1.11.0
Commit SHA:         3f6acbfd6658cb8ada8db218ba037c3c2b744b9d
Commit Date:        2025-05-13T11:42:50.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- [Reward page updated](tokenomics/mixnet-rewards#rewards-logic--calculation) with [detailed explanation of rewards calculation](tokenomics/mixnet-rewards#rewards-calculation)
- [Nym Explorer v2 upgraded](https://nym.com/explorer) with new search, interactive map and advanced filters

### Features

- [Add contains ticketbook data db query](https://github.com/nymtech/nym/pull/5670)
- [Add `/account/{address}`](https://github.com/nymtech/nym/pull/5673): Meant to replace `https://explorer.nymtech.net/api/v1/tmp/unstable/account/{address}` for Explorer v2

### Bugfix

- [Use node saturation instead of its stake for selection weight](https://github.com/nymtech/nym/pull/5717)

## `v2025.8-tourist`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.8-tourist)
- [`nym-node`](nodes/nym-node.mdx) version `1.10.0`

```shell
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-04-29T11:36:50.614557168Z
Build Version:      1.10.0
Commit SHA:         e594630314d4676cbe9bba9ab07bd405a9cf679a
Commit Date:        2025-04-29T12:19:54.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```
### Operators Updates & Tools

- [New Nym wallet](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.18) is out: Release version `1.2.18`

**Documentation Updates**

- [Tokenomics page](tokenomics.mdx) updated
- [Node operators rewards page](tokenomics/mixnet-rewards.mdx) updated with new parts added:
    - [Node performance calculation](tokenomics/mixnet-rewards#node-performance-calculation)
    - [Stake saturation calculation](tokenomics/mixnet-rewards#stake-saturation)
    - [Rewards calculation](tokenomics/mixnet-rewards#rewards-calculation)
    - [Rewards distribution](tokenomics/mixnet-rewards#rewards-distribution)

### Features

- [Adding fresh nym-api tests and workflow](https://github.com/nymtech/nym/pull/5659)

- [Replay protection](https://github.com/nymtech/nym/pull/5682): Introduces replay detection into a `nym-node`. Currently it uses a bloomfilter that's reset every 25h. In the future this will be controlled by the key rotation. The bloomfilter is also periodically flushed to disk in order to be able to recover from a crash/shutdown.

- [Tauri V2 - Wallet Migration](https://github.com/nymtech/nym/pull/5687):
  - The core of the lifting was done via the migrate command
  - A lot of API's changed
  - Improved styling
  - Pipelines are fixed for all platforms

- [Make mix hops optional for Mixnet Client](https://github.com/nymtech/nym/pull/5696): As is the route selection for packets, reply SURBs, and acknowledgements are selected deep withing the `MixnetClient` machinery. This makes custom route selection (i.e. for authenticating / registering wiregaurd mode vpn clients) is not supported. This PR adds configuration toggle that allows `MixnetClient` to be built where packets are sent direct through entry to Exit Gateway nodes -- no mix hops.

- [Bump the `nym-vpn deb` metapackage to `1.0`](https://github.com/nymtech/nym/pull/5697)

- [Updated sphinx payload keys](https://github.com/nymtech/nym/pull/5698): This PR uses the new version of the `sphinx-packet` that allows us to derive payload encryption keys from the seed rather than having to attach the keys themselves. In practice each reply surb is now ~60% smaller. However, currently all of those functionalities are **DISABLED** by default. It is because it required nodes to actually understand the new scheme. it shouldn't be enabled until sufficient number of nodes, particularly mixnodes, had upgraded.

- [Allow copy and paste on logins fields for the wallet](https://github.com/nymtech/nym/pull/5699): Allow shell open for url links (some platforms it's not working as expected)

- [Removed old explorer-api](https://github.com/nymtech/nym/pull/5701)

- [Peer handle should die more gracefully](https://github.com/nymtech/nym/pull/5704)

- [Update `hickory` DNS `0.24.4` to `0.25`](https://github.com/nymtech/nym/pull/5709): Update the dependency on `hickory` DNS to the latest minor version

- [Remove inactive peers](https://github.com/nymtech/nym/pull/5721)

- [Add reserved byte to reply surb serialisation](https://github.com/nymtech/nym/pull/5731)

## `v2025.7-tex`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.7-tex)
- [`nym-node`](nodes/nym-node.mdx) version `1.9.0`

```shell
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-04-15T14:36:52.729991996Z
Build Version:      1.9.0
Commit SHA:         08b6be93c49e8c225e74ffabb5529493bd4b13b6
Commit Date:        2025-04-15T15:29:46.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.86.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- **[Nym release binaries](https://github.com/nymtech/nym/releases) no longer work on distributions Debian bullseye/sid (11) / Ubuntu 20.04 LTS and older! Please upgrade your sever to Debian bookworm (Debian 12) / Ubuntu 22.04 (and newer)!** Alternatively compile the binaries from source.

- The Nym Squad League Winter Season has concluded. Changes are coming to NSL, including the new NSL council, monthly payments for contributions, revamped reports, and more. Details available in the [Winter Season report](https://forum.nym.com/t/nym-squad-league-winter-season-report/1265).

- [New scripts to inititialise and configure multiple VMs](nodes/preliminary-steps/vps-setup/advanced#setting-up-virtual-machines): KVM setup for virtualising nodes proved to be a good approach for admins orchestrating multiple nodes on a dedicated or bare metal machines. Now there is an option of running bash scripts speeding up the process of VM initialisation and configuration, while leaving some flexibility via interactive prompts.

### Features

- [Move all workflows on ubuntu-20 to ubuntu-22](https://github.com/nymtech/nym/pull/5455): Ubuntu 20.04 runners are scheduled to be removed from set of github hosted runners. Now is as good a time as any to finally take the plunge to switch away from ubuntu-20.04 to the shiny oh so modern ubuntu-22.04 runners

- [Bump `elliptic` from `6.5.5` to `6.6.1`](https://github.com/nymtech/nym/pull/5483): Bumps [`elliptic`](https://github.com/indutny/elliptic)

- [Bump `blake3` from `1.6.1` to `1.7.0`](https://github.com/nymtech/nym/pull/5658): Bumps [`blake3`](https://github.com/BLAKE3-team/BLAKE3)

- [Mix throughput tester](https://github.com/nymtech/nym/pull/5661): A utility to measure mixing throughput of a node. Especially since there are some design choices with non-obvious performance penalties. For example 1 bloomfilter per connection vs 1 global bloomfilter with additional locking for replay protection.

- [Update log crate](https://github.com/nymtech/nym/pull/5667): Update `log crate` to latest, fix `format_in_format_args`, fix `to_string_in_format_args`

- [Bump the patch-updates group across 1 directory with 7 updates](https://github.com/nymtech/nym/pull/5668):

| Package | From | To |
| --- | --- | --- |
| [`clap`](https://github.com/clap-rs/clap) | `4.5.32` | `4.5.34` |
| [`clap_complete`](https://github.com/clap-rs/clap) | `4.5.46` | `4.5.47` |
| [`once_cell`](https://github.com/matklad/once_cell) | `1.21.1` | `1.21.3` |
| [`reqwest`](https://github.com/seanmonstar/reqwest) | `0.12.4` | `0.12.15` |
| [`tempfile`](https://github.com/Stebalien/tempfile) | `3.19.0` | `3.19.1` |
| [`time`](https://github.com/time-rs/time) | `0.3.39` | `0.3.41` |
| [`uniffi`](https://github.com/mozilla/uniffi-rs) | `0.29.0` | `0.29.1` |

- [Improve explorer caching](https://github.com/nymtech/nym/pull/5669): Fix:
    - `tanstack` caching
    - graphs data bug
    - "auto" gas fee for redeem rewards

- [Update node versions in CI](https://github.com/nymtech/nym/pull/5677)

- [Bash scripts to init and configure VMs conveniently and update docs](https://github.com/nymtech/nym/pull/5681): KVM setup for virtualising nodes proved to be a good approach for admins orchestrating multiple nodes on a dedicated/bare machines. This PR adds an option of running bash scripts speeding up the process of VM initialisation and configuration, while leaving some flexibility to the users via interactive prompts.
    - Script to initialise new VM on host machine and prompting user for needed vars
    - Script to config the VM from within and prompting user for needed vars
    - Documentation of the above
    - Lift headers so the main chapters come out in the side menu for easier navigation

- [`clippy` for `1.86`](https://github.com/nymtech/nym/pull/5685)

- [Expand `/v3/nym-nodes` with geodata](https://github.com/nymtech/nym/pull/5686): Includes node description and geodata.

### Bugfix

- [Minor fixes involving key cloning and hashing](https://github.com/nymtech/nym/pull/5664): Adds fixes for several minor key related issues:
    - Copying a private keys to perform a DH
    - Perform DH against the reference to the static key to prevent memory copy of secret key material
    - Hashing an `x25519` public key without first converting to a canonical representation
    - Use derived `Hash` implementation which internally [converts to a canonical representation](https://github.com/dalek-cryptography/curve25519-dalek/blob/fbf1fb5339b22eaf9925e520c90f1821f79ef5db/curve25519-dalek/src/montgomery.rs#L103) before hashing

- [Fix the mac build of the wallet](https://github.com/nymtech/nym/pull/5684)

## `v2025.6-chuckles`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.8-chuckles)
- [`nym-node`](nodes/nym-node.mdx) version `1.8.0`

```shell
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-04-01T09:55:02.982234741Z
Build Version:      1.8.0
Commit SHA:         a429d6528e99b878a310b71bdbe6d31923c52d84
Commit Date:        2025-04-01T11:41:15.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.85.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- [**Nym Wallet v1.2.16**](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.16): Operators can change their parameters in the GUI interface again. Remember that while changing node settings will take effect in the next epoch (max 60 min), *Operator cost* and *Profit margin* will be updated with the change of interval (720 epochs). You can track the state of epochs and intervals [here](https://explorer.nym.spectredao.net/dashboard). Currently we are less than 24h from the end of interval, **if you were to change OC or PM, do it now!**

- [**Nym Explorer v2.1.0**](https://nym.com/explorer) is out as a beta release

- Since last release [**Wireguard exit policy is out!**](nodes/nym-node/configuration#wireguard-exit-policy-configuration). Make sure to apply it on the servers hosting `nym-node` in `exit-gateway` mode.

#### Community Tools

Nym operators are coming with diverse backgrounds. While for some running a `nym-node` is an introduction to sys-administration, others are well seasoned builders and hackers. It's amazing to see the effort people put in order to lift each other by day-to-day mutual problem solving support in [Matrix channel](https://matrix.to/#/#operators:nymtech.chat). More and more people take it further and build tools to improve network monitoring and node administration.

While we are planning to make a page aggregating these tools together, here are some tools released lately by the technical community:

- [SpectreDAO token dashboard](https://explorer.nym.spectredao.net/token): Including stats, distribution, alongside all fundamental stats

- [SpectreDAO privacy check](https://explorer.nym.spectredao.net/privacy-check): Testing users browser, IP info, WebRTC leaks, fingerprinting, extensions and most importantly whether you access via [NymVPN](https://nym.com/)

- Service status dashboards: Uptime dashboards showing status of Nym Nodes, either squads using self-hosted [Uptime Kuma](https://uptime.kuma.pet/) or a custom dashboard, like the one from [Oceanus](https://oceanus.p17o.com/)

- [Nym Node Widget](https://github.com/koutakou/NymNodeWidget): A MacOS widget following status of your nodes by [koutakou](https://github.com/koutakou/)

- [Nymesis](https://nymesis.vercel.app/): Beta version of an explorer tracking node rewards in a simple graph

### Features

- [Bump `http-proxy-middleware` from `2.0.6` to `2.0.7`](https://github.com/nymtech/nym/pull/5019): Bumps [`http-proxy-middleware`](https://github.com/chimurai/http-proxy-middleware)

- [Bump `next` from `13.5.7` to `14.2.15` in `/documentation/docs`](https://github.com/nymtech/nym/pull/5281): Bumps [`next`](https://github.com/vercel/next.js)

- [Bump `next` from `14.1.4` to `14.2.21` in `/explorer-nextjs`](https://github.com/nymtech/nym/pull/5308): Bumps [`next`](https://github.com/vercel/next.js)

- [Bump `nanoid` from `3.3.7` to `3.3.8` in `/documentation/docs`](https://github.com/nymtech/nym/pull/5335): Bumps [`nanoid`](https://github.com/ai/nanoid)

- [Bump `store2` from `2.14.3` to `2.14.4`](https://github.com/nymtech/nym/pull/5391): Bumps [`store2`](https://github.com/nbubna/store)

- [Bump `@octokit/plugin-paginate-rest` and `@actions/github` in `/.github/actions/nym-hash-releases/src`](https://github.com/nymtech/nym/pull/5488): Bumps [`@octokit/plugin-paginate-rest`](https://github.com/octokit/plugin-paginate-rest.js)

- [Clean stale partially received buffers](https://github.com/nymtech/nym/pull/5536): Clean up old `ReconstructionBuffer`s that have not received fragments in a long time. The motivation is that we want to allow the client to cap the number of re-transmissions done, meaning we can't assume that these will eventually arrive

- [Explorer V2](https://github.com/nymtech/nym/pull/5548)

- [Bump `braces` from `3.0.2` to `3.0.3` in `/sdk/typescript/packages/mix-fetch-node`](https://github.com/nymtech/nym/pull/5612): Bumps [`braces`](https://github.com/micromatch/braces)

- [Bump `golang.org/x/net` from `0.23.0` to `0.36.0` in `/wasm/mix-fetch/go-mix-conn`](https://github.com/nymtech/nym/pull/5613): Bumps [golang.org/x/net](https://github.com/golang/net)

- [Bump `ws` from `8.13.0` to `8.18.1` in `/wasm/client/internal-dev`](https://github.com/nymtech/nym/pull/5614): Bumps [`ws`](https://github.com/websockets/ws)

- [Bump webpack from `5.77.0` to `5.98.0` in `/wasm/client/internal-dev`](https://github.com/nymtech/nym/pull/5615): Bumps [`webpack`](https://github.com/webpack/webpack)

- [Feature/paginated ticketbooks challenge](https://github.com/nymtech/nym/pull/5619): This PR makes changes to how ticketbook rewarding works and in particular the challenge portion of the exchange. Rather than requesting merkle proof alongside all binary data of the associated ticketbooks in a single `/issued-ticketbooks-challenge` query (that could have potentially lead to ddos of nym-apis as it made them load all of the data into the memory at once) the query got split into `/issued-ticketbooks-challenge-commitment` for obtaining the merkle proof and `/issued-ticketbooks-data` for obtaining the binary data. Note that the latter query might have to be called multiple times with different arguments due to the enforced limit on the maximum number of values returned at once.

- added:
  - `/issued-ticketbooks-count`
  - `/issued-ticketbooks-for-count/:expiration_date`
  - `/issued-ticketbooks-on-count/:issuance_date`
  - `/issued-ticketbooks-challenge-commitment`
  - `/issued-ticketbooks-data`

- removed:
  - `/issued-ticketbooks-challenge`

<AccordionTemplate name={<TestingSteps/>}>
Testing Steps Performed:
New issue ticketbook related endpoints work -  tickets are issued and consumed as before.
Redeeming tickets is happening as normal on the gateway side.

Notes (if any):
Chuckles will not require the rewarder binary to be updated; as there will be additional changes to rewarding, this will be extensively tested in the future.

- [Bump `@babel/runtime` from `7.16.3` to `7.26.10` in `/testnet-faucet`](https://github.com/nymtech/nym/pull/5621): Bumps [`@babel/runtime`](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime)

- [Bump the `patch-updates` group with 8 updates](https://github.com/nymtech/nym/pull/5624):

| Package | From | To |
| --- | --- | --- |
| [`async-trait`](https://github.com/dtolnay/async-trait) | `0.1.87` | `0.1.88` |
| [`clap`](https://github.com/clap-rs/clap) | `4.5.31` | `4.5.32` |
| [`env_logger`](https://github.com/rust-cli/env_logger) | `0.11.6` | `0.11.7` |
| [`http-body-util`](https://github.com/hyperium/http-body) | `0.1.2` | `0.1.3` |
| [`quote`](https://github.com/dtolnay/quote) | `1.0.39` | `1.0.40` |
| [`tokio`](https://github.com/tokio-rs/tokio) | `1.44.0` | `1.44.1` |
| [`tokio-util`](https://github.com/tokio-rs/tokio) | `0.7.13` | `0.7.14` |
| [`indexed_db_futures`](https://github.com/Alorel/rust-indexed-db) | `0.6.0` | `0.6.1` |

- [Bump `humantime` from `2.1.0` to `2.2.0`](https://github.com/nymtech/nym/pull/5625): Bumps [`humantime`](https://github.com/chronotope/humantime)

- [Bump `http` from `1.2.0` to `1.3.1`](https://github.com/nymtech/nym/pull/5626): Bumps [`http`](https://github.com/hyperium/http)

- [Bump `celes` from `2.5.0` to `2.6.0`](https://github.com/nymtech/nym/pull/5627)

- [Bump `uuid` from `1.15.1` to `1.16.0`](https://github.com/nymtech/nym/pull/5628): Bumps [`uuid`](https://github.com/uuid-rs/uuid)

- [Bump `once_cell` from `1.20.3` to `1.21.1`](https://github.com/nymtech/nym/pull/5629): Bumps [`once_cell`](https://github.com/matklad/once_cell)

- [Bump `zeroize` from `1.6.0` to `1.8.1`](https://github.com/nymtech/nym/pull/5630): Bumps [`zeroize`](https://github.com/RustCrypto/utils)

- [Bump `tempfile` from `3.18.0` to `3.19.0`](https://github.com/nymtech/nym/pull/5631): Bumps [`tempfile`](https://github.com/Stebalien/tempfile)

- [Rework IPR codec to extract out timer and implement AsyncWrite](https://github.com/nymtech/nym/pull/5632): The goal is to be able to handle back pressure in the vpn client. For that we need to extract out the timer from the codec since we want to move control over that to the mixnet processor. Once the timer is removed we can reformulate the mixnet sender as a `Sink` wrapped in a `FramedWrite`

  - Extract out timer from IPR codec
  - Implement AsyncWrite on mixnet client sender
  - Add functions to wait for lanes to clear on `LaneQueueLenghts`

- [Remove `explorer-api` from the main workspace](https://github.com/nymtech/nym/pull/5635)

- [Bump `dtolnay/rust-toolchain` from `1.90.0` to `1.100.0`](https://github.com/nymtech/nym/pull/5638): Bumps [`dtolnay/rust-toolchain`](https://github.com/dtolnay/rust-toolchain)

- [Bump `zip` from `2.2.2` to `2.4.1`](https://github.com/nymtech/nym/pull/5639): Bumps [`zip`](https://github.com/zip-rs/zip2)

- [Add `max_retransmissions` flag on each message](https://github.com/nymtech/nym/pull/5642): Add an optional `max_retransmissions` field on `InputMessage`, to be able to selectively disable or turn down the number of `retransmissions` done for specific packets

- [Upgrade `sha2` to workspace version for validator-client](https://github.com/nymtech/nym/pull/5644)

- [Add `RUSTUP_PERMIT_COPY_RENAME` in two workflows that we forgot about](https://github.com/nymtech/nym/pull/5646)

- [Remove `UNIQUE` constraint on node pubkey](https://github.com/nymtech/nym/pull/5649): This accounts for the case when a node rebonds with the same key remove nodes that weren't updated in a week

- [Add concurrency limit to CI](https://github.com/nymtech/nym/pull/5651): For `ci-build` workflow only

- [Update wallet to include Interval Operator Cost and Profit Margin](https://github.com/nymtech/nym/pull/5652): Created a new modal for Interval Operator Cost and Profit Margin changes
  - Uses existing update node operating cost functionality for old mixnodes (If it works it works)
  - Prompts a warning that a user "Can send the request as many times as they want but it will only update the last message when the interval changes"

- [Wallet-revamp to be in line with new nym-theming](https://github.com/nymtech/nym/pull/5653): Updating colour palette to match the [nym.com](https://nym.com) sites:
  - Used the same font too
  - Updated icons

- [Add `fd` callback for initial authentication](https://github.com/nymtech/nym/pull/5654): One thing that was missed was the registration `ws` connection that happens before the actual connection, if it's the first time connecting to a gateway. This PR extends connection `fd` callback to that initial connection, so that it can also be allowed by firewalls.

- [Revert using `AsyncWrite` sink in IPR](https://github.com/nymtech/nym/pull/5656): Revert the use of the `AsyncWrite` sink in the IPR until it's fully ready.

- [Remove Google public DNS](https://github.com/nymtech/nym/pull/5660): We had a lot of complaints about Google, so we're removing this in VPN client, Nym should follow to avoid issues with firewall.

### Bugfix

- [Corrected typos](https://github.com/nymtech/nym/pull/5497) in `CHANGELOG.md`

## `v2025.5-chokito`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.5-chokito)
- [`nym-node`](nodes/nym-node.mdx) version `1.7.0`

```shell
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-03-18T12:17:10.782554174Z
Build Version:      1.7.0
Commit SHA:         82e82943aa14e530ab4eb3aaab28ce86d47e5298
Commit Date:        2025-03-18T10:39:55.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.85.0
rustc Channel:      stable
cargo Profile:      release
```

### Release Summary

1. WebSocket Connection Counter Fix (this is the fix for which we have a [pre-release branch](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina-nym-node-patch) out already which will be replaced by this release): Prevents incorrect session tracking for WebSockets

2. Security Fixes in Dependencies: Address known security vulnerabilities, making updating highly recommended

3. Authorisation & Timestamp Changes: Modifies how timestamps are validated in Auth v2 - this is going to be what the clients use. For example: the clients will start to use v2 variants of everything (prepping the network for the breaking change to come on April 1st which will force clients to only use v2).

4. Wireguard exit policy [scripts](https://github.com/nymtech/nym/tree/develop/scripts/wireguard-exit-policy)

### Operators Updates & Tools

- [**Wireguard exit policy is out!**](nodes/nym-node/configuration#wireguard-exit-policy-configuration) Operators can use a new guide with our scripts to setup wireguard exit policy using IP tables rules.

- [Setup commands for `nym-node` simplified](nodes/nym-node/setup#setup--run): `config.toml` defaults to correct binding addresses and ports, no need to specify unless operators want to change those values.

- [Virtualising dedicated server with KVM now includes IPv6 setup](nodes/preliminary-steps/vps-setup/advanced#installing-kvm-on-a-server-with-ubuntu-2204): Thanks to [LunarDAO](https://lunardao.net) squad we caught a missing IPv6 configuration in KVM installation guide. Operators can now run a bare metal or dedicated server and virtualise it into VMs each with a fully functional node, having all specs fully under control.

- [NTP time synchronization guide](nodes/preliminary-steps/vps-setup#2-synchronize-time-of-your-server): Some servers had an issue with incorrect time. Please use [this guide](nodes/preliminary-steps/vps-setup#2-synchronize-time-of-your-server) to update time on your server to synchronize your node operation with the rest of the network.

- [New community managed token page by SpectreDAO](https://explorer.nym.spectredao.net/token): Based on community request, one of the squad administrating several Nym Nodes created a live token dashboard [explorer.nym.spectredao.net/token](https://explorer.nym.spectredao.net/token).

### Features

- [Display error messages if IPv4 or IPv6 address not found on nymtun0](https://github.com/nymtech/nym/pull/5465): This is with regards to issue [\#5461](https://github.com/nymtech/nym/pull/5461)

- [Connection `fd` callback before actual connection](https://github.com/nymtech/nym/pull/5494)

- [Add extra args for the probe](https://github.com/nymtech/nym/pull/5499)

- [Use ct_eq for checking bearer token](https://github.com/nymtech/nym/pull/5501)

- [Update version in Cargo.toml](https://github.com/nymtech/nym/pull/5503)

- [Treat Gateways as Nym Nodes](https://github.com/nymtech/nym/pull/5504): entry/exit nodes are also scraped for description & packets mixed data. Generate a random moniker for nodes that don't have one set.

- [Bump the patch-updates group with 2 updates](https://github.com/nymtech/nym/pull/5505): [log](https://github.com/rust-lang/log) and [tar](https://github.com/alexcrichton/tar-rs).

- [Bump itertools from `0.13.0` to `0.14.0`](https://github.com/nymtech/nym/pull/5509): Bumps [itertools](https://github.com/rust-itertools/itertools).

- [Bump flate2 from `1.0.35` to `1.1.0`](https://github.com/nymtech/nym/pull/5510): Bumps [flate2](https://github.com/rust-lang/flate2-rs).

- [Make sure any terminated task kills the watcher and write run info to db](https://github.com/nymtech/nym/pull/5517)

- [Make "Memo" visible per default on send NYM](https://github.com/nymtech/nym/pull/5524)

- [Disallow routing mix packets to nodes not present in the topology](https://github.com/nymtech/nym/pull/5526)

- [Set `RUSTUP_PERMIT_COPY_RENAME`](https://github.com/nymtech/nym/pull/5533): Try to fix rustup issues on our self-hosted runners by setting `RUSTUP_PERMIT_COPY_RENAME`

- [v2 authentication request](https://github.com/nymtech/nym/pull/5537): This PR creates new v2 variant of client-gateway authentication message that increases protection against possible connection hijacking.

- [Bump `rs_merkle` from `1.4.2` to `1.5.0`](https://github.com/nymtech/nym/pull/5541): Bumps [rs_merkle](https://github.com/antouhou/rs-merkle)

- [Bump `uuid` from `1.13.2` to `1.15.1`](https://github.com/nymtech/nym/pull/5542): Bumps [`uuid`](https://github.com/uuid-rs/uuid)

- [Bump the `patch-updates` group across 1 directory with 14 updates](https://github.com/nymtech/nym/pull/5549):

| Package | From | To |
| --- | --- | --- |
| [`anyhow`](https://github.com/dtolnay/anyhow) | `1.0.96` | `1.0.97` |
| [`async-trait`](https://github.com/dtolnay/async-trait) | `0.1.86` | `0.1.87` |
| [`blake3`](https://github.com/BLAKE3-team/BLAKE3) | `1.6.0` | `1.6.1` |
| [`chrono`](https://github.com/chronotope/chrono) | `0.4.39` | `0.4.40` |
| [`clap`](https://github.com/clap-rs/clap) | `4.5.30` | `4.5.31` |
| [`clap_complete`](https://github.com/clap-rs/clap) | `4.5.45` | `4.5.46` |
| [`console`](https://github.com/console-rs/console) | `0.15.10` | `0.15.11` |
| [`getset`](https://github.com/jbaublitz/getset) | `0.1.4` | `0.1.5` |
| [`pin-project`](https://github.com/taiki-e/pin-project) | `1.1.9` | `1.1.10` |
| [`quote`](https://github.com/dtolnay/quote) | `1.0.38` | `1.0.39` |
| [`schemars`](https://github.com/GREsau/schemars) | `0.8.21` | `0.8.22` |
| [`serde_bytes`](https://github.com/serde-rs/bytes) | `0.11.15` | `0.11.16` |
| [`serde_json`](https://github.com/serde-rs/json) | `1.0.139` | `1.0.140` |
| [`thiserror`](https://github.com/dtolnay/thiserror) | `2.0.11` | `2.0.12` |

- [Start sending v2 sphinx packets](https://github.com/nymtech/nym/pull/5554)

- [Add /v3/nym-nodes](https://github.com/nymtech/nym/pull/5569): Returns extended node info from local DB
  - Endpoint caching
  - Add `bond_info` & `self_described` to DB `nym_nodes`
  - Update mixnode & gateway bond status on data refresh
  - Add `active` column to DB `nym_nodes`
  - Use only active & bonded nodes in scraping/testrun tasks

- [Rust SDK SURB example: change hardcoded file to tempdir](https://github.com/nymtech/nym/pull/5576): Change hardcoded filepath for client to tempdir

- [Server Side internal DoT/DoH opt out](https://github.com/nymtech/nym/pull/5577): Allow server side (nodes and nym-api) to use nym-http-api-client without  DoH/DoT resolver.

- [Delete double memo field in send modal](https://github.com/nymtech/nym/pull/5578)

- [Bump ring from `0.17.3` to `0.17.13` in /nym-wallet](https://github.com/nymtech/nym/pull/5582): Bumps [ring](https://github.com/briansmith/ring)

- [Bump the patch-updates group with 8 updates](https://github.com/nymtech/nym/pull/5585):

| Package | From | To |
| --- | --- | --- |
| [`bytes`](https://github.com/tokio-rs/bytes) | `1.10.0` | `1.10.1` |
| [`semver`](https://github.com/dtolnay/semver) | `1.0.25` | `1.0.26` |
| [`serde`](https://github.com/serde-rs/serde) | `1.0.218` | `1.0.219` |
| [`serde_bytes`](https://github.com/serde-rs/bytes) | `0.11.16` | `0.11.17` |
| [`serde_derive`](https://github.com/serde-rs/serde) | `1.0.218` | `1.0.219` |
| [`serde_repr`](https://github.com/dtolnay/serde-repr) | `0.1.19` | `0.1.20` |
| [`time`](https://github.com/time-rs/time) | `0.3.37` | `0.3.39` |
| [`ff`](https://github.com/zkcrypto/ff) | `0.13.0` | `0.13.1` |

- [Bump `tokio` from `1.43.0` to `1.44.0`](https://github.com/nymtech/nym/pull/5587): Bumps [tokio](https://github.com/tokio-rs/tokio)

- [Bump `tempfile` from `3.17.1` to `3.18.0`](https://github.com/nymtech/nym/pull/5588): Bumps [tempfile](https://github.com/Stebalien/tempfile)

- [Bump `webpack-dev-middleware` from `5.3.3` to `5.3.4` in `/wasm/zknym-lib/internal-dev]`(https://github.com/nymtech/nym/pull/5589): Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware)

- [Bump `braces` from `3.0.2` to `3.0.3` in /wasm/zknym-lib/internal-dev](https://github.com/nymtech/nym/pull/5590): Bumps [braces](https://github.com/micromatch/braces)

- [Bump `cookie` and `express` in `/wasm/client/internal-dev`](https://github.com/nymtech/nym/pull/5592): Bumps [cookie](https://github.com/jshttp/cookie)

- [Bump `ws` from `8.13.0` to `8.18.1` in `/wasm/mix-fetch/internal-dev`](https://github.com/nymtech/nym/pull/5593): Bumps [ws](https://github.com/websockets/ws)

- [Bump `serve-static` and `express` in `/wasm/mix-fetch/internal-dev`](https://github.com/nymtech/nym/pull/5594): Bumps [serve-static](https://github.com/expressjs/serve-static)

- [Bump `body-parser` and express in `/wasm/mix-fetch/internal-dev`](https://github.com/nymtech/nym/pull/5596): Bumps [body-parser](https://github.com/expressjs/body-parser)

- [Bump `webpack` from `5.77.0` to `5.98.0` in /wasm/mix-fetch/internal-dev`](https://github.com/nymtech/nym/pull/5597): Bumps [webpack](https://github.com/webpack/webpack)

- [Introduce internal tool for checking signer status](https://github.com/nymtech/nym/pull/5598)

- [Allow resetting all `SURB` sender tags](https://github.com/nymtech/nym/pull/5600)

- [Chore/payment watcher debug endpoints](https://github.com/nymtech/nym/pull/5601)

- [Change `auth` v2 timestamp skew and allow values from the future](https://github.com/nymtech/nym/pull/5604)

- [Update bls12 381 fork](https://github.com/nymtech/nym/pull/5605)

- [Bump `@babel/helpers` from `7.24.4` to `7.26.10`](https://github.com/nymtech/nym/pull/5606): Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers)

- [Chore/more payment watcher debug endpoints](https://github.com/nymtech/nym/pull/5608)

- [Export lane queue lengths in sdk](https://github.com/nymtech/nym/pull/5609): Export the lane queue length type to be able to implement backpressure outside of the sdk mixnet client

- [Bump `webpack-dev-middleware` from `5.3.3` to `5.3.4` in `/wasm/client/internal-dev`](https://github.com/nymtech/nym/pull/5610): Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware)

- [Bump `braces` from `3.0.2` to `3.0.3` in `/sdk/typescript/packages/nodejs-client`](https://github.com/nymtech/nym/pull/5611): Bumps [braces](https://github.com/micromatch/braces)

- [Remove explorer-api from ci-build-binaries](https://github.com/nymtech/nym/pull/5616)

### Bugfix

- [`Cargo.lock` for contracts](https://github.com/nymtech/nym/pull/5489)

- [Fix stats bug & remove HM caching](https://github.com/nymtech/nym/pull/5495)

- [Fix `total_stake` on SQL update](https://github.com/nymtech/nym/pull/5514)

- [Another `total_stake` SQL fix](https://github.com/nymtech/nym/pull/5516)

- [Correctly increment `ws` connection counter](https://github.com/nymtech/nym/pull/5620)

## `v2025.4-dorina-patched`

Patched version of `dorina` with a few fixes and tweaks to the release. We would like to ask `nym-node` operators to upgrade to this version as quickly as possible to implement the fixes across the network and improve general quality before NymVPN launch.

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina-patched)
- [`nym-node`](nodes/nym-node.mdx) version `1.6.2`

```shell
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-03-06T20:32:36.922212778Z
Build Version:      1.6.2
Commit SHA:         247ebb7c4339de0a298a7fcb2574122a8306c3b8
Commit Date:        2025-03-06T21:26:16.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.85.0
rustc Channel:      stable
cargo Profile:      release
```

- Use legacy crypto for constructing SURB headers ([#5579])
- Bugfix: make sure to correctly decode response content when putting it into error message ([#5571])
- Tweak surb management to be more conservative ([#5570])
- Deserialize v5 authenticator requests ([#5568])
- Chore: additional logs when attempting to load ecash keys ([#5567])
- Add full response body to error message upon decoding failure ([#5566])
- Hotfix: ensure we bail on merkle leaves insertion upon missing data ([#5565])
- Feature: v2 authentication request (#5537) ([#5563])
- Create authenticator v5 request/response types ([#5561])

[#5579]: https://github.com/nymtech/nym/pull/5579
[#5571]: https://github.com/nymtech/nym/pull/5571
[#5570]: https://github.com/nymtech/nym/pull/5570
[#5568]: https://github.com/nymtech/nym/pull/5568
[#5567]: https://github.com/nymtech/nym/pull/5567
[#5566]: https://github.com/nymtech/nym/pull/5566
[#5565]: https://github.com/nymtech/nym/pull/5565
[#5563]: https://github.com/nymtech/nym/pull/5563
[#5561]: https://github.com/nymtech/nym/pull/5561

## `v2025.4-dorina`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina)
- [`nym-node`](nodes/nym-node.mdx) version `1.6.0`
```shell
Binary Name:        nym-node
Build Timestamp:    2025-03-04T09:03:11.322601809Z
Build Version:      1.6.0
Commit SHA:         7060fa6dad58f17543f5086c73b1854ad1ceae60
Commit Date:        2025-03-03T17:24:10.000000000Z
Commit Branch:      release/2025.4-dorina
rustc Version:      1.86.0-nightly
rustc Channel:      nightly
cargo Profile:      release
```

### Operators Updates & Tools

- New advanced [guide to virtualise a dedicated server](nodes/preliminary-steps/vps-setup/advanced), providing steps for experienced operators and aspiring sys-admins who seek for higher optimisation and better efficiency of their work orchestrating multiple nodes.
- New Service Grant program is being implemented by operators setting up new ~150 Exit Gateways following the updated [specs for `nym-node`](nodes#minimum-requirements)

### Features
- [Feature/chain status api](https://github.com/nymtech/nym/pull/5539):
this PR introduces `/v1/network/chain-status` endpoint on nym api to give basic information about the current block as seen by this API (with some caching) and updates `/health` endpoint to give stall information.

- [Add SURBs soft threshold](https://github.com/nymtech/nym/pull/5535): the IPR should try to keep a buffer of available SURBs to reduce latency.

- [Simplify IPR v8](https://github.com/nymtech/nym/pull/5532): purge stuff from IPR v8 to simplify; use protocol field in v8.

- [Shared instance for DNS AsyncResolver](https://github.com/nymtech/nym/pull/5523):
make the `HickoryDnsResolver` use a shared instance by default to limit fd use. Now the multiple `nym_http_api_client::Client`s that get built should take advantage of a shared connection pool for DNS lookups. If for some reason a client does need an independent AsyncResolver this can still be done with the added `thread_resolver`  function.

- [cherry-pick 17d3ff2d775f61aee381d90a304ed416c08f33fc onto dorina](https://github.com/nymtech/nym/pull/5519)

- [cherry-pick 6e5d0dac1b75413c5f09122b0d953f8ec6ef48df onto dorina](https://github.com/nymtech/nym/pull/5518)

- [feat: add config option for maximum number of client connections](https://github.com/nymtech/nym/pull/5513)

- [IPR request types v8](https://github.com/nymtech/nym/pull/5498): Bump IPR request/response types to v8

- [Support static routes for HTTP requests](https://github.com/nymtech/nym/pull/5487)

- [added missing import to doctest](https://github.com/nymtech/nym/pull/5480)

- [adjusted TestSetup::new_complex to ensure bonded node's existence](https://github.com/nymtech/nym/pull/5478)

- [Trigger contracts CI on main workspace Cargo changes](https://github.com/nymtech/nym/pull/5477): since the contracts workspace depends on the common code in the main workspace, and since the contracts are critical to not have regressions in, trigger contracts CI on any changes to the workspace Cargo.toml and lock files.

- [Run cargo autoinherit](https://github.com/nymtech/nym/pull/5460): run `cargo autoinherit` to move a bunch of dependencies to the workspace level. `Cargo.lock` remains untouched.

- [Disable debug in wasm and wallet workflows too](https://github.com/nymtech/nym/pull/5459)

- [Fix clippy::precedence](https://github.com/nymtech/nym/pull/5457): fix clippy warnings for the Rust beta toolchain.

- [Provide Interval context with node descriptor endpoints](https://github.com/nymtech/nym/pull/5456): add current interval context information to existing enpoints using `build_skimmed_nodes_response` under the hood. This allows clients checking for a refresh to send the `epoch_uid` as a query parameter when fetching updates so the server can tell it that there have been no changes, instead of sending duplicate data over and over. The changes in this PR should be backwards compatible and never interfere with existing clients. The additions to the `NodeParams` are optional, so there is no error if a client does not send them. Old clients will not send `epoch_uid` by accident so they cannot accidentally clear their set of known nodes. In the response the status field is optional so if it is missing (e.g. if a new client talks to an old server) the connection still works. For old clients speaking to new servers, the json parsing will simply ignore extra information not included in the objects json spec.

<AccordionTemplate name={<TestingSteps/>}>

 Made a request to the `/api/v1/unstable/nym-nodes/semi-skimmed` endpoint:
 - without entering an epoch_id
 - with entering the current epoch_id
 - with entering an old epoch_id
 - with entering a future epoch_id
 All results returned the same data, as expected

- [Feature/add gbp currency](https://github.com/nymtech/nym/pull/5453)

- [Add helper to extract a list of sqlite files with journal files wal/shm](https://github.com/nymtech/nym/pull/5452)

- [Add a middleware layer to the nym api allowing for data compression](https://github.com/nymtech/nym/pull/5451): after Testing in a minimal example, this does work as expected. Routes still default to plain encoding, however if a client indicates support for a compressed encoding using the `Accept-Encoding` header then the served response will be compressed with the appropriate `Content-Encoding` header. ([Proof-of-Concept](https://gist.github.com/jmwample/c15a983e804fc338fee3d1b037d216b0))

<AccordionTemplate name={<TestingSteps/>}>
 Sent requests with and without Accept-Encoding: gzip to observe response behaviour
 Verified if responses included content-encoding: gzip when compression was requested
 Checked response file output to confirm actual compression occurred

- [Condense core API functionalities and enable gzip decompression for reqwest payloads](https://github.com/nymtech/nym/pull/5450): this PR is intended to take out variables from our usage of HTTP requests in the `nym-http-api-client`. To do this the PR: (1) adds the `ApiClientCore` trait with the minimal feature required to send a request, (2) turns all request sending into trait extension automatically implemented for any type that implements `ApiClientCore`. This has the benefit of consistent expected behavior for all clients using `nym-http-api-client`, including features added going forward. FOR EXAMPLE this pr adds a default header `"accept-encoding: gzip;q=1.0, *;q=0.5"` which indicates that compression is preferred whenever available. Other features to keep in mind here are things like configurable retries, domain fallbacks, etc. Note: the `Apiclient` interface could be simplified, but that would require refactoring our downstream usages of the API. For now this isn't necessary as `ApiClient` is implemented automatically so it costs nothing to have it this way. It just allows divergent usage in downstream crates.

<AccordionTemplate name={<TestingSteps/>}>
 Measured nym-api response times before and after updating the API client using curl
 Checked if the client automatically decompressed Gzip responses

- [Seedable clients](https://github.com/nymtech/nym/pull/5440): Adds `DerivationMaterial` and accompanying methods to builders. `DerivationMaterial` encapsulates parameters for deterministic key derivation using HKDF (SHA-512). Use the `derive_secret()` method to generate a 32-byte secret. To prepare for a new derivation, call the `next()` method which increments the index. **It is the caller's responsibility to track and persist the derivation index if keys need to be rederived.**

 ```rust
 let master_key = [0u8; 32]; // your secret master key
 let salt = "unique-salt-value".to_string();
 let material = DerivationMaterial::new(master_key, 0, salt.as_bytes());

 // Derive a secret
 let secret = material.derive_secret().expect("Failed to derive secret");

 // Prepare for the next derivation
 let next_material = material.next();
 ```

- [Remove all recv_with_delay and add shutdown condition to loops in client-core](https://github.com/nymtech/nym/pull/5435): inside client-core we want to prepare the ground for moving a behaviour close to what we have in the vpn client. Remove all the recv_with_delay since we want to just stop. Add shutdown condition to all select loops to guard against the shutdown listener being polled inside the select blocks. Remove unwraps when sending on unbounded channels in case the receiver exits before the sender. Move `TaskClient` to be a member field so make it easier to wrap log errors in a shutdown check. Update all fork names to use underscore consistently, since the task separator is hyphen

<AccordionTemplate name={<TestingSteps/>}>
 Validated that all binaries including `nym-node`, `nym-client`, `nym-network-requester`, and `nym-socks5-client` are behaving well without indicating the presence of any unexpected errors or crashes

- [Disable the test for checking the remaining bandwidth in nym-node-status-api](https://github.com/nymtech/nym/pull/5425): this check fails almost every time on CI, possibly due to rate limiting? It's not good to disable the check, but it's blocking CI as it stands now. Given that we have the check above for locating the ip, we at least have a little coverage.

- [Dz nym node stats](https://github.com/nymtech/nym/pull/5418): removed obsolete fields from stats (blacklisted mixnodes, blacklisted gateways, bonded mixnodes, bonded gateways). Introduced nym-node scraping, beside just mixnodes. `/mixnodes/stats` now returns data for nym-nodes as well, which results in much more accurate "packets mixed" stats.

- [Nymnode entrypoint docker](https://github.com/nymtech/nym/pull/5300)

### Bugfix
- [bugfix: dont query for ecash apis unless necessary when spending ticketbooks](https://github.com/nymtech/nym/pull/5508)

- [bugfix: bound check when recovering a reply SURB](https://github.com/nymtech/nym/pull/5502)

- [fix: update fx average rate calcs to ignore 0 values](https://github.com/nymtech/nym/pull/5454)

### Chore
- [chore: workspace global panic preventing lints](https://github.com/nymtech/nym/pull/5512)

- [chore: removed all old coconut code](https://github.com/nymtech/nym/pull/5500)

- [build(deps): bump the patch-updates group across 1 directory with 3 updates](https://github.com/nymtech/nym/pull/5482): updates `clap` from 4.5.28 to 4.5.30, updates `clap` from 4.5.28 to 4.5.30, updates `prost` from 0.13.4 to 0.13.5.

- [build(deps): bump http from 1.1.0 to 1.2.0](https://github.com/nymtech/nym/pull/5472)

- [build(deps): bump utoipa-swagger-ui from 8.0.3 to 8.1.0](https://github.com/nymtech/nym/pull/5471)

- [build(deps): bump colored from 2.1.0 to 2.2.0](https://github.com/nymtech/nym/pull/5470)

- [build(deps): bump celes from 2.4.0 to 2.5.0](https://github.com/nymtech/nym/pull/5469)

- [build(deps): bump the patch-updates group with 2 updates](https://github.com/nymtech/nym/pull/5467): updates `clap` from 4.5.28 to 4.5.29, updates `prost` from 0.13.4 to 0.13.5.

- [build(deps): bump elliptic from 6.5.4 to 6.6.1 in /docker/typescript_client/upload_contract](https://github.com/nymtech/nym/pull/5463): bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.4 to 6.6.1.

- [build(deps): bump uniffi_build from 0.25.3 to 0.29.0](https://github.com/nymtech/nym/pull/5448)

- [Upgrade tower to 0.5.2](https://github.com/nymtech/nym/pull/5446)

- [build(deps): bump hickory-proto from 0.24.2 to 0.24.3 in /nym-wallet](https://github.com/nymtech/nym/pull/5445)

- [build(deps): bump hickory-proto from 0.24.2 to 0.24.3](https://github.com/nymtech/nym/pull/5444)

- [build(deps): bump the patch-updates group across 1 directory with 10 updates](https://github.com/nymtech/nym/pull/5439):
Bumps the patch-updates group with 10 updates in the directory:

| Package | From | To |
| --- | --- | --- |
| [async-trait](https://github.com/dtolnay/async-trait) | `0.1.85` | `0.1.86` |
| [clap](https://github.com/clap-rs/clap) | `4.5.27` | `4.5.28` |
| [comfy-table](https://github.com/nukesor/comfy-table) | `7.1.3` | `7.1.4` |
| [hickory-resolver](https://github.com/hickory-dns/hickory-dns) | `0.24.2` | `0.24.3` |
| [once_cell](https://github.com/matklad/once_cell) | `1.20.2` | `1.20.3` |
| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.8` | `1.1.9` |
| [serde_json_path](https://github.com/hiltontj/serde_json_path) | `0.7.1` | `0.7.2` |
| [toml](https://github.com/toml-rs/toml) | `0.8.19` | `0.8.20` |
| [cosmrs](https://github.com/cosmos/cosmos-rust) | `0.21.0` | `0.21.1` |
| [tokio-postgres](https://github.com/sfackler/rust-postgres) | `0.7.12` | `0.7.13` |

- [build(deps): bump openssl from 0.10.56 to 0.10.70 in /nym-wallet](https://github.com/nymtech/nym/pull/5422)

- [build(deps): bump hyper from 1.4.1 to 1.6.0](https://github.com/nymtech/nym/pull/5416)

- [build(deps): bump publicsuffix from 2.2.3 to 2.3.0](https://github.com/nymtech/nym/pull/5367)

## `v2025.3-ruta`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.3-ruta)
- [`nym-node`](nodes/nym-node.mdx) version `1.5.0`

```
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-02-13T11:49:34.670488195Z
Build Version:      1.5.0
Commit SHA:         a3e19b4563843055b305ea9a397eb1ad84b5c378
Commit Date:        2025-02-10T18:14:47.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.84.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

- **Operators who use Debian based distributions must run their `nym-node` on Debian bookworm (Debian 12)/ Ubuntu 22.04 (and newer).** In case of running older operation system make sure to upgrade your server.

#### Service Grant Program v2 (SGPv2)

As we announced in [`hu` release notes](#service-grant-program-v2), we are opened a second iteration Service Grant Program to bootstrap node operations in key target geographies for Nym and ensures the network can provide a good quality of service.

##### Conditions to join of SGPv2

**If you are interested to become a part of SGPv2, read the point below. Do *not* buy new machines and do *not* migrate nodes just yet!**

- [Read specs & rules first](#service-grant-program-v2)
- The program will start from March 1st.
- Accepted participants are expected to run their nodes in assigned location and with [new specs](#service-grant-program-v2) by February 28th the latest.
- Squads orchestrating multiple nodes will be prioritized in locations with more slots.
- There is no final budget, neither a size per node as we expect that the next round of Service Grants program will be individual grants of varying sizes, depending on how many nodes, location, specs etc.
- Every participant of SGPv1 can submit for SGPv2 as many nodes as they currently have grant for, more slots may be offered later on.
- New submissions can only do one node per operator unless people come in squads (or DAOs) and can orchestrate multiple nodes on larger dedicated servers.
- Actual locations and approximate slots are listed below. If you want to have a node in a location which is not listed but it's near by some of the listed ones, it's not a problem, be honest in the form so we know where you planning to run nodes.
- February is the last month we proceed with grants under SGPv1.

##### How to Join

1. Have a look at the remaining [locations](#locations), specs and providers. You can contact them directly and make a calculation how much running a node on their service would cost and what size of a grant you expect to receive.
2. To apply for a service grant, the first step is to fill in [this form](https://nymtech2.typeform.com/to/LyPJer49) per each node.
3. Be responsive on Element for follow up communication.

##### Locations

These locations and slots are approximate and constantly change based on new operators submissions. Please keep in mind that we are going to chose people with respect to empty slots in the given location at the time of their submission. In case of competing submissions in the same location we will take the one with better specs vs price ratio.

| LOCATION       | SLOTS |
| :--            | --:   |
| India          | 3     |
| Austria        | 1     |
| Poland         | 1     |
| Russia         | 2     |
| Canada         | 1     |
| South Africa   | 2     |
| Sweden         | 2     |
| Latvia         | 2     |
| Lithuania      | 1     |
| Bahrain        | 1     |
| Czech Republic | 1     |
| Denmark        | 1     |
| Norway         | 1     |
| South Korea    | 1     |
| Ukraine        | 1     |
| Vietnam        | 1     |
| Argentina      | 1     |
| Belarus        | 1     |
| Croatia        | 1     |
| Cyprus         | 1     |
| Ecuador        | 1     |
| Hungary        | 1     |
| Malta          | 1     |
| New Zealand    | 1     |

##### ISPs

- Have a look into our [ISP list](community-counsel/isp-list) page
- Further you can check out Tor community [Good Bad ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/) page
- With any findings or feedback, please add it to this [csv](https://github.com/nymtech/nym/blob/develop/documentation/docs/data/csv/isp-sheet.csv), issue a [Pull Request](community-counsel/add-content) and ping me for review.
- We will add much more providers in the coming days

### Features

- [DNS resolver configuration for internal HTTP client lookups](https://github.com/nymtech/nym/pull/5355): The resolver itself is the set combination of the google, cloudflare, and quad9 endpoints supporting DoH, DoT, and for google DoH3 as well. This resolver implements a fallback mechanism where, should the DNS-over-X resolution fail, a followup resolution will be done using the hosts configured default (e.g. `/etc/resolve.conf` on linux).

- [Bump tokio from `1.40.0` to `1.43.0`](https://github.com/nymtech/nym/pull/5370)

- [Uncouple storage reference for bandwidth client](https://github.com/nymtech/nym/pull/5372): Because of the `Storage` reference in the bandwidth client, the client can't be separated and used in a different place, as it will be linked to the `DisconnectedClient`. Cloning it ensures we uncouple this unnecessary dependence.

- [`MixnetClient` can send `ClientRequests`](https://github.com/nymtech/nym/pull/5381): Adding a channel to the `MixnetClient`, so that it can signal to the `MixTrafficController` that can send a `ClientRequest` via its `GatewayTransciver`. Additionaly adds a sleep to the `disconnect` call as the socket would close before the channel message got processed.

- [Use secure DNS for websocket connection establishment](https://github.com/nymtech/nym/pull/5386): Adjust the websocket connection establishment (using `tokio_tungstenite`) to use a custom DNS resolver that tries DoH and DoT. Instead of relying on the `tokio_tungstenite` to open the `tokio::net::TcpStream` ([which it does here](https://github.com/snapview/tokio-tungstenite/blob/aafb2f9e036162f7bffa002cfea502376a690724/src/connect.rs#L91)) which would kick in the default network resolver we do the resolution and open the `TcpStream` ourselves before handing off to the websocket libary.

- [Reduce log severity for checking topology validity](https://github.com/nymtech/nym/pull/5395)

- [Change Explorer URL to new smooshed nodes](https://github.com/nymtech/nym/pull/5396)

- [Send shutdown instead of panic when reaching max fail](https://github.com/nymtech/nym/pull/5398): Remove a panic and an unwrap inside `client-core` that is hit occasionally in the vpn client. This is a change that can have wide ranging impact since it changes the task handling and it's inside `client-core`, which is used in many components and services, so preventing regressions is important.

- [Relocate a validator api function](https://github.com/nymtech/nym/pull/5401): Adds a function to the `nym-validator-client` crate that hits the network details endpoint and returns an object parsed from `json`. This was floating loose in the `nym-vpn-client` repo.

- [Bump the patch-updates group across 1 directory with 9 updates](https://github.com/nymtech/nym/pull/5406)

- [Upgrade to `thiserror` 2.0](https://github.com/nymtech/nym/pull/5414)

- [Make `wait_for_graceful_shutdown` to be pub](https://github.com/nymtech/nym/pull/5424)

- [Fix statistics shutdown](https://github.com/nymtech/nym/pull/5426)

- [Push down forget me to client configs](https://github.com/nymtech/nym/pull/5431)

### Bugfix

- [Fix missing path triggers for CI](https://github.com/nymtech/nym/pull/5380): Fix missing path triggers for CI and sort crate list alphabetically to make it easier to maintain.

## `v2025.2-hu`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.2-hu)
- [`nym-node`](nodes/nym-node.mdx) version `1.4.0`

```
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-02-04T09:35:42.399220545Z
Build Version:      1.4.0
Commit SHA:         4c2bf3642e8eec0d55c7753e14429d73ac2d0e99
Commit Date:        2025-02-04T10:29:48.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.84.1
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

From `nym-node v1.3.0` operators can technically choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).

**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes!**

**WE ASK OPERATORS TO ASSIGN ONLY ONE FUNCTIONALITY TO `--mode` OPTION PER NODE. PLEASE SELECT ONE MODE ARGUMENT OUT OF: `mixnode` or `entry-gateway` or `exit-gateway`!**

- Updated maintenance guides to [backup](nodes/maintenance#backup-a-node), [restore](nodes/maintenance#restoring-a-node) and [move](nodes/maintenance#moving-a-node) a node, containing a new and important commands to backup and restore `clients.sqlite` database.

- [New explanation of `nym-node` functionalities](nodes/nym-node/setup#functionality-mode) describing how Gateways get selected in Mixnet mode and Wireguard mode.

Wireguard nodes route data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run a node with active wireguard routing, please read our [Community Counsel pages](community-counsel/exit-gateway) containing more information and some legal content.

**Wireguard mode has no exit policy right now - we are working on the implementation.**

#### Legal support

We have been notified that a handful of nodes have been taken down by abuse reports. We created new pages with [legal suggestions](community-counsel/legal) and email [templates](community-counsel/templates). Here are some useful points on legal support:

- Here is the first version of a response template tailored for Nym operators.

- We are starting Operators Legal Clinic with Alexis Roussel, every Wednesday, 14:30 UTC (60 min) in our [Operator Legal Forum channel on Matrix](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org&via=matrix.su4ka.icu). Come and share your findigs and questions with the rest of the operators.

- Join [Operator Legal Forum channel](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org&via=matrix.su4ka.icu) and share as much as possible (like screen prints, provider, location etc).

- Join [Community legal counsel](https://nym.com/docs/operators/community-counsel) - our collective knowledge hub. Add your findings by opening a [Pull Request](https://nym.com/docs/operators/add-content)

- While we are working on a new list of more friendly providers, consider to move away from these provides as soon as possible:

    - Servinga / VPS2day (AS39378)
    - Frantech / Ponynet / BuyVM (AS53667)
    - OVH SAS / OVHcloud (AS16276)
    - Online S.A.S. / Scaleway (AS12876)
    - Hetzner Online GmbH (AS24940)
    - IONOS SE (AS8560)
    - Psychz Networks (AS40676)
    - 1337 Services GmbH / RDP.sh (AS210558)

- Backup your nodes to have access to `.nym` directory locally. Follow [node](nodes/maintenance#backup-a-node) and [proxy configuration](nodes/maintenance#backup-proxy-configuration) backup guides to be able to [restore your node](nodes/maintenance#restoring-a-node) later on on another machine, without losing your delegation.

- We would like to ask operators who use reverse proxy and a domain (required for Gateways) to start using a common convention starting with `nym-exit` for their nodes URL. The entire address should have this new format:
```
nym-exit.<CUSTOM>.<DOMAIN>.<TLD>
```

For example:

```
# for squads running multiple nodes a format can look like this:
nym-exit.ch-node1.mysquad.org

# or like this
nym-exit.3-jamaica.mysquad.org

# for operators having one node per location, the format can look like this:
nym-exit.brazil.mysquad.org

# or if operators decide to not have any custom, they can simply have this format:
nym-exit.mysquad.org
```

**The `NYM-EXIT` part in the beginning is what's important.**

- When registering a domain, check [Top Level Domain (TLD)](https://www.techopedia.com/definition/1348/top-level-domain-tld) terms and conditions. For example `.icu` is a no go. Having a wrong TLD may lead to your domain being taken away from you when facing a DMCA report.

- Write a message to your provider and introduce your intention to run a Nym Node on their service

- New page with [templates for VPS provider](community-counsel/templates)

#### Delegation Program

**If you are interested to sign up to delegation program que, message Merve on Element for the time being as we are working on CRM upgrade. We review nodes dynamically and delegate to new ones once a month.** New operators interested to join DP must follow the rules specified [here](https://delegations.explorenym.net/), run one of two latest binary version and have [Terms & Conditions](nodes/nym-node/setup#terms--conditions) accepted.

Note: Due to the token price we allow operators to have Operators cost 1000 NYM, the profit margin maximum remains 20%.

**Delegation and undelegation in January**

Delegated to all these nodes:

```
AMnDNd1Xgw7Em9R5vehP7r12ZNWUZ3jmitDHya6gpvGR
DLkKyYcA5feq43rqZdx6nJBNZvQsdX7kb2f1f6ED4cs2
26ZmTxTVBKHZg8MTKwypHkXZVJhDC7QHuv3BdsyRyTuk
5ZWdDN9pQ18vYkYYs5ZERh4P4JLtMiijscZ6FvwSfVxR
3uBgUJR393acoCRysu6SiLsximiwAMM85QFxq9WD8puC
5rXcNe2a44vXisK3uqLHCzpzvEwcnsijDMU7hg4fcYk8
nuMerN7ahqsptK8zDUZhnxMyDqePza8vWDf8k171EEs
86cNnnRxNpGdEtSX9UP1GpT6xrNvNuxFdHNkZcK7pAJg
9ngFADaYpT54F9i8iYFZLYR7SB7hrubsPArwpqe1RXQb
FQBbq1crAkCrjVBnEN85VqgZgGRMLJV65NJk8bPADdw
FUH3E3dghXjC9hdt3jeAhSsxwozsw1yzBXkoaFqkL4ci
5wF5wN7T2UuSsiUcQyL77NwdnXwAXxFttpZ1dR1nu4kR
4pVq4QSCcq4zNCnBNCfyugPjVhVyGDCBDSW5rghg8oZS
8XW1WWN1PuuAYz2TXQ9iWRekMFEJXjdEq4asMyE2qCCN
CxgjcTTAnRJzDxMbqtX73vEbWwLQmVoW8zS8RZEicgfT
7fwyXd4Cmh92d4piEPHmdFm1Wz1QCFQDf6bnDGNT3M6P
```

Undelegated from 8 nodes for not meeting the rules (being offline):

```
# Gateways
DLxLKsd3LTnfudSSmHanPaZACsh1x4MGEzfJS4jQibir
DiciBkjHovXzTDE2EFJKPNj3TGw2oQjr7HPSas2YQPiQ
ADjpymCgjFsE5m7YvnZFxLMscg85dCUUesR5g8yN3Mzz
C9dEABjtFRMD1x4ZnbqnsELGJgutT73bPCfYzqBe7sHB

# Mixnodes
2FGgY5zWq6JP1BvpnLPbedWRYYAZELFCT9rMybNhnxpo
4nKkwPSbkbtkw3yrRKQVAVdviNgFgcNskgcSGdT2Sucy
DjY3T7n6VoHGcETMnmtZKmUU7NZP6AhCs8CoRsSSbViC
FAKhiQ8nW5sAWAxks1WB8u1MAWsapToCSE3KmF9LuGRQ
```

Undelegated due to high saturation:
```
5omopSZy59UyNPpx9P97vjBnN6PwPw9x5MVUx5kuNaXt
```

#### Service Grant Program v2

Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to support Exit Gateway operators before they will be rewarded by collecting [zk-nym tickets](../network/cryptography/zk-nym) from users subscription. Operators included in SGP are long term active community members with the highest requirements on the technical setup and upgrading pace. We are about to start a second iteration of SGP very soon (SGPv2). The final slots and locations are yet to be concluded. Priority to participate in SGPv2 will be given to the current operators in SGP. Based on the number of slots, we will then determine how many more operators can sign up.

##### Rules of SGPv2

**We will share more info soon in the channels. The rules are not set in stone and could potentially be altered or updated in the future! Do *not* purchase new servers neither migrate your nodes just yet.**

As we finalising last details of *"Project Smoosh"*, where one binary - `nym-node` - can run as an `entry-gateway`, `mixnode` or `exit-gateway` in Mixnet mode as well as `entry-gateway` or `exit-gateway` in Wireguard mode, we plan to step up the game. SGPv2 grants will be higher if operators can meet new requirements.

**Minimum Specs & Requirements**

These are minimum requirements to become a part of SGPv2. We aim to have nodes on dedicated servers, with exceptions for much stronger VPS to meet the needed criteria while sharing server with other users.

  <Tabs items={[
    <><code>nym-node</code> - dedicated server</>,
    <><code>nym-node</code> - VPS</>,
    ]} defaultIndex="0">

#### `nym-node` - dedicated server

| **Hardware**   | **Minimum Specification**          |
| :---           | ---:                               |
| Type of server | Dedicated or bare metal            |
| CPU Cores      | 4                                  |
| Memory         | 8-16 GB RAM                        |
| Storage        | 50 GB (preferably 80 GB)           |
| Connectivity   | IPv4, IPv6, TCP/IP, UDP            |
| Bandwidth      | Unmetered if possible, or {" >"} 40Tb  |
| Port speed     | 1Gbps                              |

          - Exit Gateways only
          - [Terms & Conditions](nodes/nym-node/setup#terms--conditions) accepted
          - Nodes are [bonded](nodes/nym-node/bonding#migrate-to-nym-node-in-mixnet-smart-contract) as `nym-node` not as a legacy node
          - Only `Latest` binary version is accepted to enter the program
          - Timely upgrades without direct message notifications: Only `Latest` version and the two preceding are accepted to stay in the program
          - Dedicated (or bare metal) machine is to ensure that the numbers above are *dedicated* for `nym-node` operation
          - Unmetered bandwidth is to ensure smooth user experience without data allowance limitation - 40Tb is a minimum for locations where unlimited bandwidth is not an option.
          - 1Gbps is an expected speed of Nym network in order to meet expectations of NymVPN users
          - Squads operating more than 2 nodes are expected to run larger servers and divide them for multiple nodes - We will share a how-to guide soon
          - Operators need to run [reverse proxy](nodes/nym-node/configuration) with landing page URL starting with `nym-exit` and [Web Secure Socket](nodes/nym-node/configuration) configuration
          - Operators must write their providers upfront that they will run a Nym Exit Gateway on their servers, using [this template](community-counsel/templates#introduction-to-server-provider)
          - If a node remains offline for more than 5 days for any reason, including abuse reports, and the operator doesn't resolve it neither doesn't communicate the blockers, they will be removed from the program

#### `nym-node` - VPS

| **Hardware**   | **Minimum Specification**          |
| :---           | ---:                               |
| Type of server | VPS           |
| CPU Cores      | 4                                  |
| Memory         | 8-16 GB RAM                        |
| Storage        | 50 GB (preferably 80 GB)           |
| Connectivity   | IPv4, IPv6, TCP/IP, UDP            |
| Bandwidth      | Unmetered if possible, or {" >"} 40Tb  |
| Port speed     | 10Gbps                              |

          - Exit Gateways only
          - [Terms & Conditions](nodes/nym-node/setup#terms--conditions) accepted
          - Nodes are [bonded](nodes/nym-node/bonding#migrate-to-nym-node-in-mixnet-smart-contract) as `nym-node` not as a legacy node
          - Only `Latest` binary version is accepted to enter the program
          - Timely upgrades without direct message notifications: Only `Latest` version and the two preceding are accepted to stay in the program
          - Unmetered bandwidth is to ensure smooth user experience without data allowance limitation - 40Tb is a minimum for locations where unlimited bandwidth is not an option
          - 10Gbps is to ensure that the expected speed of 1Gbps is met even when sharing a server with other users
          - Squads operating more than 2 nodes are expected to run larger servers and divide them for multiple nodes - We will share a how-to guide soon
          - Operators need to run [reverse proxy](nodes/nym-node/configuration) with landing page URL starting with `nym-exit` and [Web Secure Socket](nodes/nym-node/configuration) configuration
          - Operators must write their providers upfront that they will run a Nym Exit Gateway on their servers, using [this template](community-counsel/templates#introduction-to-server-provider)
          - If a node remains offline for more than 5 days for any reason, including abuse reports, and the operator doesn't resolve it neither doesn't communicate the blockers, they will be removed from the program

**Operators interested in joining SGPv2 can start by searching for servers that meet the above criteria, where they may eventually migrate their nodes, and then share their findings by submitting a form which will be shared shortly. Do *not* buy a new server, neither migrate a node just yet! We will be first reaching to the current participants of Service Grant Program. Everything will be announced, sending DMs to devrel will not speed up the process!**

### Features

- [build(deps): bump criterion from `0.4.0` to `0.5.1`](https://github.com/nymtech/nym/pull/4911): Bumps [criterion](https://github.com/bheisler/criterion.rs) from `0.4.0` to `0.5.1`.

- [NS API: add mixnet scraper](https://github.com/nymtech/nym/pull/5200)

- [build(deps): bump http from `1.1.0` to `1.2.0`](https://github.com/nymtech/nym/pull/5228): Bumps [http](https://github.com/hyperium/http) from `1.1.0` to `1.2.0`.

- [`http-api-client`: deduplicate code](https://github.com/nymtech/nym/pull/5267): After adding PATCH support in [\#5260](https://github.com/nymtech/nym/pull/5260), it's now time to de-duplicate some of the code

- [Add windows to CI builds](https://github.com/nymtech/nym/pull/5269)

- [nym topology revamp](https://github.com/nymtech/nym/pull/5271): This PR changes the internals of the `NymTopology` to blur the lines between explicit mixnodes and gateways so that what used to be considered a "mixnode" could be a valid egress point of the network. `NymTopology` is no longer divided into `BTreeMap<MixLayer, Vec<mix::Node>>` and `Vec<gateway::Node>`. instead there's information about the current rewarded set (to support future VRF work) and a simple map of `HashMap<NodeId, RoutingNode>`. The new features are mostly controlled via 2 new flags/config values:
    - `use_extended_topology` that tells the client to retrieve **all** network nodes rather than the ones that got assigned "active" mixnode role (or support being a gateway)
    - `ignore_egress_epoch_role` that tells the client it's  fine to construct egress packets to nodes that are **not** assigned entry or exit gateway role

- [Nyx Chain Watcher](https://github.com/nymtech/nym/pull/5274)

- [Include `IPINFO_API_TOKEN` in nightly CI](https://github.com/nymtech/nym/pull/5285)

- [Move tun constants to network defaults](https://github.com/nymtech/nym/pull/5286):
<AccordionTemplate name={<TestingSteps/>}>
1. **Regression Testing**:
- Verified no issues arose when running tests for the affected files.
- Tested TUN behaviour with new nym-nodes in the hu branch.

**Results**:

- **No bugs detected**.
- Tunnels are functioning as expected, with traffic routing and IP generation working seamlessly.

- [Add dependabot assignes for the root cargo ecosystem](https://github.com/nymtech/nym/pull/5297)

- [build(deps): bump the patch-updates group across 1 directory with 35 updates](https://github.com/nymtech/nym/pull/5310): Bumps the `patch-updates` group with 33 updates

- [Periodically remove stale gateway messages](https://github.com/nymtech/nym/pull/5312): This PR introduces a simple task that removes gateway messages that haven't been retrieved in (by default) 24h.
<AccordionTemplate name={<TestingSteps/>}>
**Automation Script for Data Cleanup Validation**

Test Objective: Validate that the stale message cleanup mechanism in the database correctly removes records older than the configured threshold (24 hours).

Test Setup:
1. Environment:
    * SQLite database
    * Bash script: used to insert data.

Steps Performed:
1. Ran the insert_data.sh script to populate the database with test data:
    * Recent records inserted successfully.
2. Verified the database content post-insertion: sqlite3 clients.sqlite "SELECT * FROM message_store;"
3. Confirmed that all 20 records (10 recent + 10 stale) were present.
4. Allowed the system to run for 24 hours to trigger the cleanup mechanism.
5. Queried the database again after 24 hours: sqlite3 gateway_storage.db "SELECT * FROM message_store;"
6.

 Expected Result:
* All stale records (older than 24 hours) should be removed.
* Recent records should remain in the database.
Actual Result:
* Query after 24 hours showed only the 10 recent records.
* All 10 stale records were successfully removed.

- [Use expect in geodata test to give error message on failure](https://github.com/nymtech/nym/pull/5314): Keep hitting this error on CI, from what I think is network hickup. But it's hard to tell form the log since the error is swallowed.  Explicitly unwrap the result so we get a more detailed error output.
<AccordionTemplate name={<TestingSteps/>}>
**Quick Code Review**

**Summary**
1. **CI Workflow**: Adjusted paths to optimise build triggers, avoiding unnecessary CI runs while ensuring coverage for key directories
2. **Geolocation Test**: Improved error handling by replacing assertions with `.expect` for clearer debugging in API regression tests

**Conclusion**

Regression testing confirms everything works as intended. **Approved**.

- [`CancellationToken`-based shutdowns](https://github.com/nymtech/nym/pull/5325): This PR introduces scaffolding for using `CancellationToken` and `TaskTracker` for our graceful shutdowns rather than the existing `TaskClient` and `TaskManager`.

- [Introduce `/load` endpoint for self-reported quantised Nym Node load](https://github.com/nymtech/nym/pull/5326): This PR introduces a new `/load` endpoint on a `NymNode` to return its current load. It returns the following data:
```rust
pub struct NodeLoad {
    pub total: Load,
    pub machine: Load,
    pub network: Load,
}
```
Where `Load` is quantised into the following buckets / tiers:
```rust
pub enum Load {
    Negligible, // 0 - 0.1
    Low,        // 0.1 - 0.3
    Medium,     // 0.3 - 0.6
    High,       // 0.6 - 0.8
    VeryHigh,   // 0.8 - 0.95
    AtCapacity, // >= 0.95
}
```
<AccordionTemplate name={<LoadEndpointInfo/>}>
The actual values  for`NodeLoad` are determined as follows:
- For network we approximate current rx/tx rates on all `eth` interfaces and scale them to the range of 0-1Gbps (for this initial iteration we assume the maximum network speed is 1Gbps which would be treated as fully saturated). So for example, if the node is sending at 0.5Gbps, it would get a `Load` of 0.5 and thus value of `Load::Medium`, 0.9Gbps would get `Load` of 0.9 and value of `Load::VeryHigh`, etc. we take the bigger value between rx and tx
- For machine load there's a bit more logic in there:
    - Firstly we determine what I call a "base load" of the machine. we do this by taking the average load from the last 5min (via `getloadavg`) and dividing it by the number of CPUs in the machine. For example if the average load of the machine in the last 5min was `1.23` and it has 2 CPUs, then it's `Load` would be `Load::High` (`1.23 / 2 = 0.615`)
    - However, whilst CPU utilisation is one of the most important factors, it does not tell the whole story. I tried to also take memory/swap utilisation into consideration (whilst not making it the main factor)
    - Thus we calculate two additional auxiliary `Load` values, for memory usage and swap usage, i.e.: `used_memory / total_memory` and `used_swap / total_swap` respectively.
    - Then we check whether either of the `MemoryLoad` or `SwapLoad` is bigger than the current base `Load` of the machine we have determined, if so, it's increased by one tier / bucket. For example, say the current machine load is `Load::Low`, but the memory usage is at 90% (`Load::VeryHigh`). that would result in the reported `Load` being bumped up to `Load::Medium` instead. The same logic applies with swap load, **however, only if the total swap > 1GB**. this is to prevent weird edge cases where the machine has hardly any swap.
    - Finally, the `.total` `Load` uses the same "tier bumping" behaviour using the `.total` and `.network` loads, i.e. `if network > machine`, then `total = machine + 1`. for example if `machine` `Load` is `Load::Low`, but `network` `Load` is `Load::Medium`, then the `total` `Load` is set to `Load::Medium` instead.

- [Bump the `patch-updates` group with 8 updates](https://github.com/nymtech/nym/pull/5336)

- [Bump `tempfile` from `3.14.0` to `3.15.0`](https://github.com/nymtech/nym/pull/5337)

- [Bump `ts-rs` from `10.0.0` to `10.1.0`](https://github.com/nymtech/nym/pull/5338)

- [Updated `cosmrs` and `tendermint-rpc` to their most recent versions](https://github.com/nymtech/nym/pull/5339)

- [Bump mikefarah/yq from `4.44.6` to `4.45.1`](https://github.com/nymtech/nym/pull/5342)

- [Update `indexed_db_futures`](https://github.com/nymtech/nym/pull/5347): Updates the `indexed_db_futures` dependency to stop relying on the fork.

- [Refresh wasm sdk](https://github.com/nymtech/nym/pull/5353): This PR refreshes the wasm clients to make them usable in the current network

- [Client gateway selection](https://github.com/nymtech/nym/pull/5358): Changed how gateway is selected.
    - For init the target gateway can't support mixing
    - For egress, unless `ignore_epoch_roles` is specified, the gateway can't be currently assigned to a mixing layer. But it can be standby or inactive

- [Exposed `NymApiClient` method for obtaining node performance history](https://github.com/nymtech/nym/pull/5360)

- [Bind to `[::]` on `nym-node` for both IP versions](https://github.com/nymtech/nym/pull/5361)
<AccordionTemplate name={<TestingSteps/>}>
**IPv4 Configuration and Migration Testing**

Testing Steps:
- Initiated and ran a nym-node with version 1.3.1 on an IPv4-only machine, then updated it to the new 'hu', 1.4.0 version.
- Initiated and ran a new nym-node with 'hu', 1.4.0 always on a machine with only IPv4.
- Initiated and ran a new nym-node with 'hu', 1.4.0 on a machine with both IPv4 and IPv6 for regression testing.

Results:
- No functional issues during version updates.
- Logged message on all versions: "no registered client for destination: ff02::2"

Status: Pass
</ AccordionTemplate>

- [Remove empty ephemeral keys](https://github.com/nymtech/nym/pull/5376)

- [Handle ecash network errors differently](https://github.com/nymtech/nym/pull/5378): For errors that could be caused by network problems, we should mark the ticket as still pending, not as bad. This won't fix the underlying problem, but should not assume anymore that the client is the culprit and penalise its bandwidth quota.

- [Make client ignore dual mode nodes by default](https://github.com/nymtech/nym/pull/5388)

<AccordionTemplate name={<TestingSteps/>}>
**Testing Steps:**
- Ensured a client is able to select a node which aside from a gateway, can also act as a mixnode
- Verified 'ignore_epoch_roles' is the default mode
- _note; this is most likely not going to be a permanent solution_

**Results:**
- Clients and topology are behaving correctly

Status: Pass
</ AccordionTemplate>

- [Update version of chain watcher and validator rewarder](https://github.com/nymtech/nym/pull/5394)

### Bugfix

- [Remove unnecessary arguments for nym-api swagger endpoints](https://github.com/nymtech/nym/pull/5272)
- [Fixed sql migration for adding default message timestamp](https://github.com/nymtech/nym/pull/5374)
- [Terminate mixnet socket listener on shutdown](https://github.com/nymtech/nym/pull/5389)
- [Correctly handle ingore epoch roles flag](https://github.com/nymtech/nym/pull/5390)

## `v2025.1-reeses`

- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.1-reeses)
- [`nym-node`](nodes/nym-node.mdx) version `1.3.1`

```
nym-node
Binary Name:        nym-node
Build Timestamp:    2025-01-16T11:54:17.079662337Z
Build Version:      1.3.1
Commit SHA:         5ab164d229f85bd2dd27ec6e38292c281df2f678
Commit Date:        2025-01-16T12:51:53.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.84.0
rustc Channel:      stable
cargo Profile:      release
```

### Operators Updates & Tools

From `nym-node v1.3.0` operators can choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).

**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes and therefore we ask operators to sign only one functionality to `--mode` option at a time. Please chose out of: `mixnode` or `entry-gateway` or `exit-gateway`.**

We are developing a design where operators can enable multiple modes, and let the Nym API to position the node according the network's needs in the beginning of each epoch.

- [Node functionality info updated](nodes/nym-node/setup#functionality-mode)
- [Fund your `nym-node` inbuilt Nyx account](nodes/nym-node/bonding#fund-nym-node-client-nyx-account) to prepare for gateway ticket rewarding
- `config.toml` changes:
    - Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
    - Added `maximum_forward_packet_delay` to `mixnet.debug` section
    - Moved `verloc` section from `mixnode.verloc` to top level
    - Removed `mixnode` section
    - Removed `entry_gateway` section to `gateway_tasks`
    - Moved `authenticator` section from `gateway_tasks` (`entry_gateway`) to `service_providers` (`exit_gateway`)
    - Renamed `exit_gateway` section to `service_providers`
    - Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
    - Added general `debug` section
    - Added `metrics` section
- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation.
    - Updated [network architecture diagrams](https://nym.com/docs/network/architecture)
    - New blow-by-blow mixnet [traffic flow](https://nym.com/docs/network/architecture) section
- [Winter Nym Squad League started](https://forum.nym.com/t/nym-squad-league-farewell-fall-welcome-winter/977)
- From this release onward (New Year) Operators Updates & Tools will be on top of each release changelog followed by features, cryptography and bugfix parts.
- All 2024 release notes were moved to the bottom section called [Archived changelog](#archived-changelog)

### Features

- [build(deps): bump micromatch from `4.0.4` to `4.0.8` in `/testnet-faucet`](https://github.com/nymtech/nym/pull/4813): Bumps [micromatch](https://github.com/micromatch/micromatch) from `4.0.4` to `4.0.8`.
- [Move NS client to separate package under NS API](https://github.com/nymtech/nym/pull/5171):
    - Moving NS API client code to separate package outside NS Agent makes the code cleaner & more modular
    - NS agent now imports NS API client that it uses
    - No functionality change in NS API or NS agent
- [Introduced initial internal commands for nym-cli: ecash key and request generation](https://github.com/nymtech/nym/pull/5174)
- [NS API - Gateway stats scraping](https://github.com/nymtech/nym/pull/5180): This PR adds a metrics scraper that fetches metrics from the `metrics/sessions` endpoint on gateway. The entries are stored and served on the API for one year
- [Remove explorer dependency](https://github.com/nymtech/nym/pull/5190)
- [Hopefully final steps of the smoosh™️](https://github.com/nymtech/nym/pull/5201): this PR is a bit more extensive than initially planned because of all the spaghetti that had to be untangled to make it all happen. The general idea is that now it's possible to run your node simultaneously in multiple modes. for example `mixnode` + `entry` or `entry` + `exit`, etc. The modes do the following:
    - `mixnode`: allows the node to handle **forward** sphinx packets
    - `entry-gateway`: allows the node to accepts websocket connections from incoming clients and to handle **final hop** sphinx packets
    - `exit-gateway`: allows the node to handle **final hop** sphinx packets as well as starts NR and IPR service providers
    Furthermore, if node runs with `wireguard` enabled, it will start local `authenticator` service provider which will also implicitly enable final hop packet handling regardless of the underlying mode. There are also various of other smaller (and bigger) changes:
    - Upon receiving a forward packet, its delay is now clamped so that one could not dos the node by asking it to delay it for, for example, a year
    - As mentioned above, node can now run in multiple modes at the same time,
    - `/metrics/mixing` endpoint got deprecated (it still provides the same information, however) and might be removed in future release
    - Introduced `/metrics/packet-stats` endpoint that provides more extensive information about packets received/sent
    - It is now possible to control whether the node should log its statistics to console
    - The console logs are also updated with the current packet rates
    - All nodes now run the "verloc" protocol and measure every other node on the network
    - Metrics got revamped and unified:
    - All running metrics are stored in a single `NymNodeMetrics` struct
    - There exists a `MetricsAggregator` that listens to any metrics events that might require additional processing
    - Any new metrics event types can be easily added by registering a new handler via `register_handler`. the type must implement `MetricsHandler` trait and use unique variant of `MetricsEvent` enum. for example `GatewaySessionStatsHandler`. It is, however, possible to have opaque handlers, such as the already implemented `LegacyMixingStatsUpdater` and `MixnetMetricsCleaner`
    - Everything in `mixnode` directory has been removed because there was nothing really left there. The mixing socket listener was unified in `nym-node` and similarly `verloc` was also moved there
    - `gateway` directory was similarly reduced in size. Now it also creates appropriate tasks as opposed to the whole gateway process. eventually it might also be further stripped, but today is not that day.
    - Removed the generic parameter on the `GatewayStorage` to simplify all the generics down the stack. it wasn't used anyway

CLI:
    - Added `--modes` argument to specify all node modes with a single command (or `env` variable). for example: `--modes="mixnode,entry"`. Can't be used alongside `--modes`
    - Extended `--mode` argument to allow specifying it multiple times, for example: `--mode mixnode --mode entry`. can't be used alongside `--mode`

Config changes:
    - Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
    - Added `maximum_forward_packet_delay` to `mixnet.debug` section
    - Moved `verloc` section from `mixnode.verloc` to top level
    - Removed `mixnode` section
    - Removed `entry_gateway` section to `gateway_tasks`
    - Moved `authenticator` section from `gateway_tasks` (`entry_gateway`) to `service_providers` (`exit_gateway`)
    - Renamed `exit_gateway` section to `service_providers`
    - Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
    - Added general `debug` section
    - Added `metrics` section
- [Better date serialization](https://github.com/nymtech/nym/pull/5207): Proper date serialization for NS API session stats
- [Restore Location fields](https://github.com/nymtech/nym/pull/5208): restore `latitude` and `longitude` fields
- [Derive serialize for UserAgent](https://github.com/nymtech/nym/pull/5210)
- [Change sqlite journal mode to WAL](https://github.com/nymtech/nym/pull/5213)
- [Shipping raw metrics to PG](https://github.com/nymtech/nym/pull/5216)
- [Extend raw ws fd for gateway client](https://github.com/nymtech/nym/pull/5218)
- [Add fd callback to client core](https://github.com/nymtech/nym/pull/5230)
- [TicketType derive Hash and Eq](https://github.com/nymtech/nym/pull/5233): It's useful to keep `TicketType` in maps, which require `Hash`. Also derive `Eq` since it's useful.
- [Extend swagger docs](https://github.com/nymtech/nym/pull/5235)
- [Add FromStr impl for UserAgent](https://github.com/nymtech/nym/pull/5236): Add `FromStr` implementation for `UserAgent` to make it easier to pass in custom user agent in vpn clients as a CLI argument.
- [Remove unneeded async function annotation](https://github.com/nymtech/nym/pull/5246)
- [Add control messages to `GatewayTransciver`](https://github.com/nymtech/nym/pull/5247)
<AccordionTemplate name={<TestingSteps/>}>
**Review and Testing: Forget Me Implementation**

- Validated the encryption and delivery of `ForgetMe` control messages to the gateway

**Testing: MixTrafficController Integration**

- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown
- Tested behaviour for gateway transceiver failures while sending control messages

**Testing: Gateway Storage Updates**
- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage

- [Add conversion unit tests for auth msg](https://github.com/nymtech/nym/pull/5251)
- [Update TS bindings](https://github.com/nymtech/nym/pull/5255)
- [Removed legacy socks5 listener](https://github.com/nymtech/nym/pull/5259)
- [Add PATCH support to `nym-http-api-client`](https://github.com/nymtech/nym/pull/5260):  Add `PATCH` support to `nym-http-api-client` crate
- [Wireguard metrics](https://github.com/nymtech/nym/pull/5278): With this PR on each peer controller update the following global metrics information are also updated:
    - total bytes tx
    - total bytes rx
    - current active peers
    - total peers registered
    - The former two are exposed with REST endpoints `/api/v1/metrics/wireguard-stats`, while the rest will be accessible via prometheus (soon ™️ ). The wireguard stats are also logged to the console (assuming they're non-zero)
- [Add close to credential storage](https://github.com/nymtech/nym/pull/5283): Add close method to credential storage
<AccordionTemplate name={<TestingSteps/>}>
1. **Review File: `common/credential-storage/src/backends/sqlite.rs`**
- Verified addition of `close` method for the SQLite backend

2. **Review File: `common/credential-storage/src/ephemeral_storage.rs`**
- Confirmed addition of `close` method for ephemeral storage with no action required

3. **Review File: `common/credential-storage/src/persistent_storage/mod.rs`**
- Ensured `close` method integration for persistent storage

4. **Review File: `common/credential-storage/src/storage.rs`**
- Verified updates to the `Storage` trait to include `close` and `cleanup_expired` methods

- [Cherry picked \#5286](https://github.com/nymtech/nym/pull/5287)
<AccordionTemplate name={<TestingSteps/>}>
1. **Review File: `common/network-defaults/src/constants.rs`**
- Confirmed updated `mixnet_vpn` constants were added.

2. **Review File: `service-providers/ip-packet-router/src/constants.rs`**
- Checked replacement of legacy `TUN_*` constants with new `mixnet_vpn` constants.
- Validated alignment of routing traffic configurations.

3. **Review File: `service-providers/ip-packet-router/src/ip_packet_router.rs`**
- Ensured new `nym_network_defaults::constants::mixnet_vpn` constants replaced old references.
- Verified `TunDeviceConfig` consistency.

4. **Review File: `service-providers/ip-packet-router/src/util/generate_new_ip.rs`**
- Confirmed substitution of `TUN_DEVICE_*` constants with `NYM_TUN_DEVICE_*` constants.
- Tested functionality for generating random IPs within subnet.

- [Expand `nym-node` prometheus metrics](https://github.com/nymtech/nym/pull/5298): This PR undusts the `/api/v1/metrics/prometheus` and introduces the following **37** new data points:

 - mixnet:
   - ingress:
     - `nym_node_mixnet_ingress_forward_hop_packets_received`
     - `nym_node_mixnet_ingress_final_hop_packets_received`
     - `nym_node_mixnet_ingress_malformed_packets_received`
     - `nym_node_mixnet_ingress_excessive_delay_packets`
     - `nym_node_mixnet_ingress_forward_hop_packets_dropped`
     - `nym_node_mixnet_ingress_final_hop_packets_dropped`

     - `nym_node_mixnet_ingress_forward_hop_packets_received_rate`
     - `nym_node_mixnet_ingress_final_hop_packets_received_rate`
     - `nym_node_mixnet_ingress_malformed_packets_received_rate`
     - `nym_node_mixnet_ingress_excessive_delay_packets_rate`
     - `nym_node_mixnet_ingress_forward_hop_packets_dropped_rate`
     - `nym_node_mixnet_ingress_final_hop_packets_dropped_rate`

   - egress:
     - `nym_node_mixnet_egress_stored_on_disk_final_hop_packets`
     - `nym_node_mixnet_egress_forward_hop_packets_sent`
     - `nym_node_mixnet_egress_ack_packets_sent`
     - `nym_node_mixnet_egress_forward_hop_packets_dropped`

     - `nym_node_mixnet_egress_forward_hop_packets_sent_rate`
     - `nym_node_mixnet_egress_ack_packets_sent_rate`
     - `nym_node_mixnet_egress_forward_hop_packets_dropped_rate`

 - client sessions
   - `nym_node_entry_client_sessions_unique_users`
   - `nym_node_entry_client_sessions_sessions_started`
   - `nym_node_entry_client_sessions_finished_sessions`
   - `nym_node_entry_client_sessions_durations_{TYP}` (histogram), for example `nym_node_entry_client_sessions_durations_vpn`

 - wireguard:
   - `nym_node_wireguard_bytes_rx`
   - `nym_node_wireguard_bytes_tx`
   - `nym_node_wireguard_bytes_total_peers`
   - `nym_node_wireguard_bytes_active_peers`

   - `nym_node_wireguard_bytes_rx_rate`
   - `nym_node_wireguard_bytes_tx_rate`

 - network
   - `nym_node_network_active_ingress_mixnet_connections`
   - `nym_node_network_active_ingress_web_socket_connections`
   - `nym_node_network_active_egress_mixnet_connections`

 - process
   - `nym_node_process_forward_hop_packets_being_delayed`
   - `nym_node_process_packet_forwarder_queue_size`
   - `nym_node_process_topology_query_resolution_latency` (histogram)
   - `nym_node_process_final_hop_packets_pending_delivery`
   - `nym_node_process_forward_hop_packets_pending_delivery`

- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb
- [Warn users if node is run in exit mode only](https://github.com/nymtech/nym/pull/5320): Throws a warning if node is run in "exit" mode only as by default, this will **NOT** enable entry capabilities, i.e. opening the websocket. thus making it ineligible for rewarded set selection (and rewards)
- [Reduce log severity for number of packets being delayed](https://github.com/nymtech/nym/pull/5321)
- [Apply 1.84 linter suggestions](https://github.com/nymtech/nym/pull/5330)
- [Readjusted --mode behaviour to fix the regression](https://github.com/nymtech/nym/pull/5331)
- [Legacy alert](https://github.com/nymtech/nym/pull/5346): alert moved into `nav` components

### Bugfix

- [Fix overflow](https://github.com/nymtech/nym/pull/5184)
- [Fix overflow again](https://github.com/nymtech/nym/pull/5204)
- [Make sure to update timestamp of last batch verification to prevent double redemption](https://github.com/nymtech/nym/pull/5239)
- [Make sure to apply gateway score filtering when choosing initial node](https://github.com/nymtech/nym/pull/5256)
- [Fixed client session histogram buckets](https://github.com/nymtech/nym/pull/5316)
- [Contract version assignment](https://github.com/nymtech/nym/pull/5318): This PR fixes updates to current nym-node version as well as introduces migration to fix the existing state of the mainnet contract
 - [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness)

## Archived Changelog

To allow reading through older changelogs, we store them below sorted by years.

</ AccordionTemplate>

## `v2024.14-crunch-patched`
Patch for `v2024.14-crunch` release. [Fixes an issue](https://github.com/nymtech/nym/commit/b656003306184061588f25df0b8b4555b41157f4) to allow only one private IP pair & compatibility issues between nym-nodes and older clients.

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.14-crunch-patched)
- [`nym-node`](nodes/nym-node.mdx) version `1.2.1`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-12-18T10:18:42.978852430Z
Build Version:      1.2.1
Commit SHA:         8d5a41a790e96ae5e821964865affaa7d3343eab
Commit Date:        2024-12-18T11:07:49.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.83.0
rustc Channel:      stable
cargo Profile:      release
```

## `v2024.14-crunch`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.14-crunch)
- [`nym-node`](nodes/nym-node.mdx) version `1.2.0`
- [Operators updates and tools](changelog#operators-updates--tools)
- [Github CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.14-crunch/CHANGELOG.md)

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-12-11T13:49:11.974104790Z
Build Version:      1.2.0
Commit SHA:         a491e6a71a8cf862d77defd740a4ee8d65d8292a
Commit Date:        2024-12-11T10:28:47.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.83.0
rustc Channel:      stable
cargo Profile:      release
```

### Features

- [Bump elliptic from `6.5.4` to `6.5.7` in /testnet-faucet](https://github.com/nymtech/nym/pull/4768): Bumps [elliptic](https://github.com/indutny/elliptic) from `6.5.4` to `6.5.7`.

- [build(deps): bump micromatch from `4.0.4` to `4.0.8` in /nym-wallet/webdriver](https://github.com/nymtech/nym/pull/4789): Bumps [micromatch](https://github.com/micromatch/micromatch) from `4.0.4` to `4.0.8`.

- [build(deps): bump axios from 1.6.0 to 1.7.5 in /nym-api/tests](https://github.com/nymtech/nym/pull/4790) Bumps [axios](https://github.com/axios/axios) from 1.6.0 to 1.7.5.

- [Sync code with `.env` in build.rs](https://github.com/nymtech/nym/pull/4876): Keep `dotenv` file always up to date

- [build(deps): bump lazy_static from `1.4.0` to `1.5.0`](https://github.com/nymtech/nym/pull/4913): Bumps [lazy_static](https://github.com/rust-lang-nursery/lazy-static.rs) from `1.4.0` to `1.5.0`.

- [Create TaskStatusEvent trait instead of piggybacking on Error](https://github.com/nymtech/nym/pull/4919)

- [build(deps): bump once_cell from `1.19.0` to `1.20.2`](https://github.com/nymtech/nym/pull/4952): Bumps [`once_cell`](https://github.com/matklad/once_cell) from `1.19.0` to `1.20.2`

- [Bump the patch-updates group across 1 directory with 10 updates](https://github.com/nymtech/nym/pull/5011): Bumps the patch-updates group with 9 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [anyhow](https://github.com/dtolnay/anyhow) | `1.0.89` | `1.0.90` |
| [clap](https://github.com/clap-rs/clap) | `4.5.18` | `4.5.20` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.29` | `4.5.33` |
| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.5` | `1.1.6` |
| [serde](https://github.com/serde-rs/serde) | `1.0.210` | `1.0.211` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.128` | `1.0.132` |
| [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) | `0.2.93` | `0.2.95` |
| [wasm-bindgen-futures](https://github.com/rustwasm/wasm-bindgen) | `0.4.43` | `0.4.45` |
| [web-sys](https://github.com/rustwasm/wasm-bindgen) | `0.3.70` | `0.3.72` |
| Updates `anyhow` | `1.0.89` | `1.0.90` |

- [[Product Data] Introduce data persistence on gateways](https://github.com/nymtech/nym/pull/5022): This PR builds on top of [\#4974](https://github.com/nymtech/nym/pull/4974), not changing the behavior of the data collection, but persisting them in a sqlite database so they can be kept across restarts and crashes. It also leave the door open for other stats module to use that storage if needed. Here are some points of interest:
    - New [`gateway_stats_storage`](https://github.com/nymtech/nym/tree/simon/gateway_stats_persistence/common/gateway-stats-storage) crate
    - [Config migration](https://github.com/nymtech/nym/blob/simon/gateway_stats_persistence/nym-node/src/config/old_configs/old_config_v4.rs) resulting from the added database.
    - Resulting changes in the [`statistics`](https://github.com/nymtech/nym/tree/simon/gateway_stats_persistence/gateway/src/node/statistics) module to account the new storage system

- [Integrate nym-credential-proxy into workspace](https://github.com/nymtech/nym/pull/5027): Integrate `nym-credential-proxy` into the main workspace

- [Authenticator CLI client mode](https://github.com/nymtech/nym/pull/5044)

- [Node Status API](https://github.com/nymtech/nym/pull/5050): merging a long-diverged feature branch - all commits here were their own merge requests

- [IPv6 support for wireguard](https://github.com/nymtech/nym/pull/5059)

- [Add nym node GH workflow](https://github.com/nymtech/nym/pull/5080)

- [[Product Data] Better unique user count on gateways](https://github.com/nymtech/nym/pull/5084): To avoid double counting clients across gateways, we add a user ID to the gateway session data.

- [chore: ecash contract migration to remove unused 'redemption_gateway_share'](https://github.com/nymtech/nym/pull/5104)

- [[Product Data] Client-side stats collection ](https://github.com/nymtech/nym/pull/5107): The goal is to anonymously gather stats from nym-clients. These stats will be sent through the mixnet to a Nym run service provider that will gather them. This PR sets the scene to send stats in a mixnet message to an address. The address can be set when the client is created. Current stats include some infos on sent packets along with platform information. If a receiving address is set, the client will send a mixnet packet every 5min to this address. Otherwise, nothing happens and the client runs as usual.

- [Send mixnet packet stats using task client](https://github.com/nymtech/nym/pull/5109)

- [Add granular log on nym-node](https://github.com/nymtech/nym/pull/5111) and make use of it for `defguard_wireguard_rs` big info logs

- [Rewarding for ticketbook issuance](https://github.com/nymtech/nym/pull/5112): Revamps the current validator rewarder to allow for rewards for issuing the zk-nym ticketbooks.

- [[Product Data] Add stats reporting configuration in client config ](https://github.com/nymtech/nym/pull/5115): Adds the stats reporting address to client configs. It can be set in the config file, as a CLI argument and as an env var in a `.env` file. As the stats reporting config in now in the `DebugConfig`, the `StatsReportingConfig` is no longer required, making the propagation of these changes more readable

- [config score](https://github.com/nymtech/nym/pull/5117): introduces a concept of a `config_score` to a nym node which influences performance and thus rewarding amounts and chances of being in the rewarded set. Currently it's influenced by the following factors:
    - Accepting terms and conditions (not accepted: 0)
    - Exposing self-described API (not exposed: 0)
    - Running "nym-node" binary (legacy binary: 0)
    - Number of versions behind the core (`score = 0.995 ^ (X * versions_behind ^ 1.65)`)
    - The old performance is now treated as `routing_score`
    - the "new" performance = `routing_score * config_score`

- [Add Dockerfile and add env vars for clap arguments](https://github.com/nymtech/nym/pull/5118)

- [Aadd GH workflow for nym-validator-rewarder](https://github.com/nymtech/nym/pull/5119)

- [[Product data] Data consumption with ecash ticket](https://github.com/nymtech/nym/pull/5120): Send an event each time an ecash ticket get successfully spent. This allows to approximate how much data each client is using.

- [[Product Data] Config deserialization bug fix](https://github.com/nymtech/nym/pull/5126): Fixes a bug where a `None` value was serialized into an empty string, and incorrectly deserialized into a `Some` variant.

- [NS Agent auth with NS API](https://github.com/nymtech/nym/pull/5127): NS Agent authenticates with key that was registered with NS API
    - Added flag to Agent to generate keypairs
    - Agent requests are signed by agent
    - Server-side requests are checked for authentication

- [CI: reduce jobs running on cluster](https://github.com/nymtech/nym/pull/5132)

- [Removed ci-nym-api-tests.yml which was running outdated (and broken) tests](https://github.com/nymtech/nym/pull/5133)

- [[Product Data] Set up country reporting from vpn-client](https://github.com/nymtech/nym/pull/5134): Add the ability to report exit country, along with a small refactoring of a module.

- [chore: remove standalone legacy mixnode/gateway binaries](https://github.com/nymtech/nym/pull/5135)

- [Update `serde_json_path` due to compilation issue](https://github.com/nymtech/nym/pull/5144)

- [Add version to clientStatsReport](https://github.com/nymtech/nym/pull/5147): Add a `kind` and `api_version` field for `ClientStatsReport`

- [Start session collection for exit gateways](https://github.com/nymtech/nym/pull/5148): Apparently, exit gateways are also entry gateways so we need to start session stats for them as well

- [build(deps): bump mikefarah/yq from `4.44.3` to `4.44.5`](https://github.com/nymtech/nym/pull/5149): Bumps [mikefarah/yq](https://github.com/mikefarah/yq) from `4.44.3` to `4.44.5`.

- [build(deps): bump cross-spawn from `7.0.3` to `7.0.6` in /testnet-faucet](https://github.com/nymtech/nym/pull/5150): Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from `7.0.3` to `7.0.6`.

- [Add export_to_env to NymNetworkDetails](https://github.com/nymtech/nym/pull/5162): In `nym-vpn-core` we've started to read the network environment from a json file and then try to pass around `NymNetworkDetails` directly instead of relying on the exported environment. However we still need to bridge with old code so we need to export the network details instance to the environment.

- [Add strum::EnumIter for TicketType](https://github.com/nymtech/nym/pull/5164)

- [Fix env var name](https://github.com/nymtech/nym/pull/5165)

- [Add support for DELETE to nym-http-api-client](https://github.com/nymtech/nym/pull/5166): Add delete support to `http-api-client`

- [Add derive_extended_private_key to DirectSecp256k1HdWallet](https://github.com/nymtech/nym/pull/5167): Add `derive_extended_private_key` to `DirectSectp256k1HdWallet` to support seeding ecash keys

- [Move two minor jobs to free tier github hosted runners](https://github.com/nymtech/nym/pull/5169): In an attempt to easy the load on the self-hosted runners, move two minor workflows over to GH hosted free tier runners.

- [Remove peers with no allowed ip from storage](https://github.com/nymtech/nym/pull/5175)

- [Add indexes to monitor run and testing route](https://github.com/nymtech/nym/pull/5181)

- [Add `monitor_run` and testing_route indexes](https://github.com/nymtech/nym/pull/5182)

- [`explorer-api`: add nym node endpoints + UI to show nym-nodes and account balances](https://github.com/nymtech/nym/pull/5183): Explorer API:
    - Existing endpoints stay identical
    - Adds new endpoints to get:
    - `nym-nodes` (list + by id)
    - account balance + delegations + rewarding + vesting

  - Explorer UI (NextJS)
    - List of nym-nodes
    - Remove service providers routes (Harbour Master shows these)
    - Updates summary page to show nym-nodes
    - Adds legacy markers to old gateway and mixnode bond lists

- [Add `monitor_run` and testing_route indexes](https://github.com/nymtech/nym/pull/5182)

- [Bugfix/credential proxy sequencing](https://github.com/nymtech/nym/pull/5187)

- [improvement: make internal gateway clients use the same topology cache](https://github.com/nymtech/nym/pull/5191): This should result in 66% reduction in queries for topology within `nym-node` as all the clients should rely on the same cache

- [chore: apply 1.84 linter suggestions](https://github.com/nymtech/nym/pull/5192)

- [Guard storage access with cache](https://github.com/nymtech/nym/pull/5193)

- [Update Security disclosure email, public key and policy](https://github.com/nymtech/nym/pull/5195)

- [merge crunch into develop](https://github.com/nymtech/nym/pull/5199)

- [Fix backwards compat mac generation](https://github.com/nymtech/nym/pull/5202)

- [adjusted config score penalty calculation](https://github.com/nymtech/nym/pull/5206)

- [`nym-api` NMv1 adjustments](https://github.com/nymtech/nym/pull/5209)

- [Nmv2 add debug config](https://github.com/nymtech/nym/pull/5212): Adds debug config to disable poisson process, cover traffic and min performance filtering

- [introduce UNSTABLE endpoints for returning network monitor run details](https://github.com/nymtech/nym/pull/5214)

- [Don't consider legacy nodes for rewarded set selection](https://github.com/nymtech/nym/pull/5215)

- [Derive serialize for UserAgent (#5210)](https://github.com/nymtech/nym/pull/5217): Cherry-pick PR [\#5210](https://github.com/nymtech/nym/pull/5210)

- [Backport \#5218](https://github.com/nymtech/nym/pull/5220)

- [Remove any filtering on node semver](https://github.com/nymtech/nym/pull/5224): Removed any filtering on version of nodes. however, the parameters can still be passed to `nym-api` queries to not break existing clients, but they will happily ignore them

- [Further config score adjustments](https://github.com/nymtech/nym/pull/5225): I still want to add helper endpoints on `nym-api` to expose some of this data. but for now, I'll let this PR bake over the weekend.

### Bugfix

- [Correct IPv6 address generation](https://github.com/nymtech/nym/pull/5113)

- [bugfix: don't send empty BankMsg in ecash contract](https://github.com/nymtech/nym/pull/5121): If ticketbook prices were to be set so low the resultant redemption would have created `BankMsg` with value of 0, that message is no longer going to be sent

- [fix: validator-rewarder GH job](https://github.com/nymtech/nym/pull/5151)

- [bugfix: correctly expose ecash-related data on nym-api](https://github.com/nymtech/nym/pull/5155): This PR makes fixes to ecash-related endpoints on `nym-api`
    - global data (such as aggregated signatures and keys) are actually always available by all apis
    - global data (such as aggregated signatures and keys) are actually always available by all apis

- [bugfix: use default value for verloc config when deserialising missing values](https://github.com/nymtech/nym/pull/5177)

- [bugfix: fixed nym-node config migrations (again)](https://github.com/nymtech/nym/pull/5179)

- [bugfix: added explicit openapi servers to account for route prefixes](https://github.com/nymtech/nym/pull/5237)

### Operators Updates & Tools

**Nym Network will now only allow nodes which [migrated](nodes/nym-node/bonding#migrate-to-nym-node-in-mixnet-smart-contract) their node in Nym mixnet smart contract to Nym Node. All nodes which are still bonded as a legacy one (Mixnode or Gateway) in the wallet will have no chance to take part in the [Rewarded set selection](tokenomics/mixnet-rewards#rewarded-set-selection).**

**Operators taking part in Delegation program or Service Grant program must migrate their nodes latest by December 16th, 08:00 UTC.**

#### Updates

- [Version count as a part of config score](tokenomics/mixnet-rewards#config-score-calculation) has been introduced. To familiarize yourself with Nym Node operator rewards calculation, read [this page](tokenomics/mixnet-rewards).
- Nym nodes running as Exit Gateway in Service Grant program received delegation. Nym team is now delegating total of **64,800,000 NYM on top 241 Nym Nodes** (137 in Mixnode mode and 104 as Gateways). Our delegation aims to incentivise committed operators who support bootstrapping of Nym network before paying users come.

- 250k NYM - Upgrading to magura in time - 2 nodes
- 300k NYM - Upgrading to magura + bonus for a quick patch upgrade - 102 nodes
- No delegation - not upgrading in time - 2 nodes

- `nym-node` has now implemented [IPv6 support for wireguard](https://github.com/nymtech/nym/pull/5059)

- [`network_tunnel_manager.sh` updated](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh): run the commands below to make sure

<AccordionTemplate name={<TunnelManagerCommands/>}>
These commands can be run one by one or copy-pasted and run as a block.
```sh
mkdir $HOME/nym-binaries; \

curl -L https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh -o $HOME/nym-binaries/network_tunnel_manager.sh && \
chmod +x $HOME/nym-binaries/network_tunnel_manager.sh; \

$HOME/nym-binaries/network_tunnel_manager.sh check_nymtun_iptables  ; \
$HOME/nym-binaries/network_tunnel_manager.sh remove_duplicate_rules nymtun0 ;\
$HOME/nym-binaries/network_tunnel_manager.sh remove_duplicate_rules nymwg;\
$HOME/nym-binaries/network_tunnel_manager.sh check_nymtun_iptables ; \
$HOME/nym-binaries/network_tunnel_manager.sh adjust_ip_forwarding ; \
$HOME/nym-binaries/network_tunnel_manager.sh apply_iptables_rules ; \
$HOME/nym-binaries/network_tunnel_manager.sh check_nymtun_iptables ; \
$HOME/nym-binaries/network_tunnel_manager.sh apply_iptables_rules_wg ; \
$HOME/nym-binaries/network_tunnel_manager.sh configure_dns_and_icmp_wg ; \
$HOME/nym-binaries/network_tunnel_manager.sh adjust_ip_forwarding ; \
$HOME/nym-binaries/network_tunnel_manager.sh check_ipv6_ipv4_forwarding; \

systemctl daemon-reload && service nym-node restart && journalctl -u nym-node -f
```

Then run the jokes in a new window for control
```sh
$HOME/nym-binaries/network_tunnel_manager.sh joke_through_the_mixnet
$HOME/nym-binaries/network_tunnel_manager.sh joke_through_wg_tunnel
```

#### Tools

- **[New APIs documentation](../apis/introduction)** with interactive APIs generated from the OpenAPI specs of various API endpoints offered by bits of Nym infrastructure run both by Nym and community operators for both Mainnet and the Sandbox testnet.
- [Nym Harbourmaster](https://harbourmaster.nymtech.net/) has a new tab called `CONTRACT EXPLORER` querying data from Nym mixnet contract in real time.
- [Nym Explorer](https://explorer.nymtech.net) is updated to read migrated nodes correctly
- [New community explorer by SpectreDAO](https://explorer.nym.spectredao.net/dashboard) offers Nym Network dashboard, Node overview and Account stats view functions for operators and delegators.
- [`nym-vpnc`](../developers/nymvpncli) build and run documentation, for those who don't want to use the Nym VPN GUIs.

## `magura-drift`

Second patch to `v2024.13-magura` release version.

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.13-magura-drift)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.12`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-11-29T13:10:51.813092288Z
Build Version:      1.1.12
Commit SHA:         4a9a5579c40ad956163ea02e01d7b53aef2ac8ef
Commit Date:        2024-11-29T14:06:32.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.83.0
rustc Channel:      stable
cargo Profile:      release
```

-  This patch adds a peer storage manager to fix issues causing external clients to be blocked, ensuring they can successfully connect to different nodes.

## `v2024.13-magura-patched`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.13-magura-patched)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.11`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-11-22T14:30:48.067329245Z
Build Version:      1.1.11
Commit SHA:         01c7b2819ee3d328deccd303b4113ff415d7e276
Commit Date:        2024-11-22T10:50:59.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.82.0
rustc Channel:      stable
cargo Profile:      release
```

After changes coming along with `v2024.13-magura` (`nym-node v1.1.10`), Nym Explorer is no longer picking all values correctly. Instead of fixing this outdated explorer, we are working on a new one, coming out soon.

[Nym Harbourmaster](https://harbourmaster.nymtech.net) has cache of 90min, expect your values to be updated with delay. We are aware of some issues with Nym Harbourmaster and working hard to resolve them in the upcoming explorer v2. To check your routing values in real time, you can use [`nym-gateway-probe`](performance-and-testing/gateway-probe).

### Operators Updates & Tools

- Updated [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) (moved to our monorepo) helps operators to configure their IP tables rules for `nymtun` and `wireguard` routing.

- **Please re-run [routing configuration steps](nodes/nym-node/configuration#routing-configuration) to update your routing settings.**

- We found out that some operators have a wrong value for wireguard IP. Follow these steps to ensure your value is set to `10.1.0.1` (default on new nodes):

###### 1. Open your node config file:
```sh
nano $HOME/.nym/nym-nodes/<ID>/config/config.toml

# change <ID> for your local nym moniker for example:
# nano $HOME/.nym/nym-nodes/default-nym-node/config/config.toml
```
###### 2. Control or change the value of wireguard private IP
- Scroll down to section starting with `[wireguard]`
- Find line `private_ip` and ensure it's set to value `10.1.0.1`
- The section will look like this:
```toml
[wireguard]
# Specifies whether the wireguard service is enabled on this node.
enabled = true

# Socket address this node will use for binding its wireguard interface.
# default: `0.0.0.0:51822`
bind_address = '0.0.0.0:51822'

# Private IP address of the wireguard gateway.
# default: `10.1.0.1`
private_ip = '10.1.0.1'
```
###### 3. Save, exit and restart the service
- If you used `nano` editor - press `ctrl` + `x` and confirm the changes
- Run these commands to update the service with new values and restart your node process:
```sh
systemctl daemon-reload && service nym-node restart
```

- New manual how to [run `nym-node` as non-root](nodes/nym-node/configuration#running-nym-node-as-a-non-root)

- Since `v2024.13-magura`, operators do not update their node version in the wallet. [Manual upgrading steps](nodes/maintenance/manual-upgrade.mdx) has been updated accordingly.

- CLI tool `node_api_check.py`, helping operators to collect all API values about their nodes locally, is not up to date with the API changes introduced with `v2024.13-magura` release version. Please treat it as unstable before we fix it.

#### Error Log

In case you encounter this error:
```
[ERROR] nym-node/src/node/mod.rs:628: the exit gateway subtask has failed with the following message: failed to start authenticator: internal wireguard error no private IP set for peer..
```

You can follow these steps to make a workaround:

###### 1. Find the error

- In the node logs, locate the ERROR message which says `the exit gateway subtask has failed with the following message: failed to start authenticator: internal wireguard error no private IP set for peer KN5GPvkC+p6G/SM4PD2Z3ObAtRGiDjHPRnQOPpbdUQk=`

- Copy the end part of that peer, later denoted as `<WG_PEER_STRING_END>` (in our example `GiDjHPRnQOPpbdUQk=`) to use later in the sql commands

###### 2. Fix the issue in sqlite3 db

Be careful when running commands within sqlite database.

- Navigate to the data directory:
```sh
cd $HOME/.nym/nym-nodes/<ID>/data
```
- Enter the database:
```sh
sqlite3 clients.sqlite
```

- Run these commands:
```sh
# Change with your unique <PEER_STRING_END>
select * from wireguard_peer where public_key like "%<WG_PEER_STRING_END>%"
# Make sure that only ONE line is returned and it contains the key

delete from wireguard_peer where public_key like "%<WG_PEER_STRING_END>%";
```
- Confirm that peer has been removed by running this again:
```sh
select * from wireguard_peer where public_key like "%<WG_PEER_STRING_END>%";
```

###### 3. Exit and restart the service

Run `.quit` and:
```sh
systemctl restart nym-node.service
```

## `v2024.13-magura`

Magura release represents a bigger milestone in [project Smoosh](archive/faq/smoosh-faq.mdx) development where `nym-node` is one binary able to perform any function in Nym Mixnet. This release is especially crucial for operators, please pay attention to the section [*Operators Updates & Tooling*](#operators-updates--tooling) below.

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.13-magura)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.13-magura/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.10`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-11-18T17:02:50.947941194Z
Build Version:      1.1.10
Commit SHA:         b49ef643df86f0c670672429812c632fbbaf6cf1
Commit Date:        2024-11-18T17:56:57.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.82.0
rustc Channel:      stable
cargo Profile:      release
```

- [New smart contracts](https://github.com/nymtech/nym/releases/tag/nym-contracts-magura)

- **[New wallet version 1.2.15](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.15) is out!** - allowing operators to migrate to `nym-node` in Mixnet smart contract.

- [New wallet changelog](https://github.com/nymtech/nym/blob/nym-wallet-v1.2.15/nym-wallet/CHANGELOG.md)

- [New directory services v2.1: API & Mixnet contract changes](#directory-services-v21-api--mixnet-contract-changes)

### Features

- [Migrate Legacy Node (Frontend) ](https://github.com/nymtech/nym/pull/4826)

- [Directory Sevices v2.1](https://github.com/nymtech/nym/pull/4903): Read section [Directory Services v2.1: API & Mixnet Contract Changes ](#directory-services-v21-api--mixnet-contract-changes) below with detailed explanation or the [PR notes](https://github.com/nymtech/nym/pull/4903)

- [Switch over the last set of jobs to arc runners](https://github.com/nymtech/nym/pull/4938): Switch over the remaining GH jobs using 16-core runners to self-hosted arc runners. Since we can't currently use Docker on the ubuntu-20.04 runners, remove the matrix notification steps

<AccordionTemplate name={<TestingSteps/>}>
Confirm that the deployment workflows work through manual testing
- [x] cd-docs
- [x] publish-sdk-npm

- [V2 performance monitoring feature flag](https://github.com/nymtech/nym/pull/4943): Feature flag to use v2 network monitor results in rewarding

- [Add `utoipa` feature to nym-node](https://github.com/nymtech/nym/pull/4945): `cargo build -p nym-node` was failing, since its depending on `QueryParams` having `utoipa` traits derived

- [Ticket type storage](https://github.com/nymtech/nym/pull/4947)

- [`nym-api` container](https://github.com/nymtech/nym/pull/4948)

- [Extract packet processing from mixnode-common](https://github.com/nymtech/nym/pull/4949): First step on a journey of making a strong interface around packet processing, and packet processing portability. This one only moves stuff around, so it should be safe to just blindly merge.

- [expose authenticator address along other address in node-details](https://github.com/nymtech/nym/pull/4953): Expose authenticator address along ip packet router and network requester for easier parsing

- [Feature/contract state tools](https://github.com/nymtech/nym/pull/4954): Introduced/reimplemented old tools for importing cosmwasm contract states given a kv dump file. This makes it significantly easier to plan and test complex state migrations on actual chains where we risk timing out on expensive operations.

- [Add env feature to clap and make clap parameters available as env variables](https://github.com/nymtech/nym/pull/4957)

- [Bump sqlx to 0.7.4](https://github.com/nymtech/nym/pull/4959)

- [`Product Data` First step in gateway usage data collection](https://github.com/nymtech/nym/pull/4963): This PR is the first step towards collecting data on gateway usage. It builds up on an old code for what was then nym-connect. It exposes unique users count and connection time histogram on the `metrics/sessions` endpoint of the self-described API on entry-gateways. For the time being, data is collected by probing the `ActiveClientStore` every minute and extracting data from this. Data is stored internally and exposed on the next day, i.e. UTC day $d$ exposes data from day $d-1$. The [`statistics`](https://github.com/nymtech/nym/tree/simon/product_data/gateway/src/node/statistics) module will evolve as we add collection for product data and censorship resistance study. The collection will also eventually switch from probing to event-based for more accurate data.

- [`importer-cli` to correctly handle mixnet/vesting import](https://github.com/nymtech/nym/pull/4966)

- [Import `nym-vpn-api` crates](https://github.com/nymtech/nym/pull/4967): Keep these crates in a separate workspace for now. The idea is to add them to the main workspace in time, but this appears to might require some changes to how sqlite is used. Alternatively these issues might go away once we upgrade sqlite in the main workspace. Also we intend to rename some of these to something like `nym-credential-facade`, and the wasm lib should be incorporated in one of the existing crates in `common`.

- [chore: remove unused rocket code](https://github.com/nymtech/nym/pull/4968)

- [add Dockerfile for nym node](https://github.com/nymtech/nym/pull/4972)

- [`Product Data` Add session type based on ecash ticket received](https://github.com/nymtech/nym/pull/4974): Fire an `EcashTicket` event for the `GatewayStatisticsCollector`, when an Ecash ticket is being accepted. This allows to mark an active session as being a mixnet session or a vpn session. It also changes the format of the related self-described data, to accommodate that new session type.

- [Top up bandwidth](https://github.com/nymtech/nym/pull/4975)

- [feature: require reporting using nym-node binary for rewarded set selection](https://github.com/nymtech/nym/pull/4976)

- [Re-enable vested delegation migration](https://github.com/nymtech/nym/pull/4977): supersedes [\#4956](https://github.com/nymtech/nym/pull/4956) by removing the contract migration code as it's already been run on mainnet.

- [Resolve beta clippy issues in contracts](https://github.com/nymtech/nym/pull/4978)

- [Enable global ecash routes even if api is not a signer](https://github.com/nymtech/nym/pull/4980)

- [Rename `nym-vpn-api` to `nym-credential-proxy`](https://github.com/nymtech/nym/pull/4981)

- [Add topup req constructor](https://github.com/nymtech/nym/pull/4983)

- [Eliminate 0 bandwidth race check](https://github.com/nymtech/nym/pull/4988)

- [Make accepting t&c a hard requirement for rewarded set selection](https://github.com/nymtech/nym/pull/4993)

- [chore: update itertools in compact ecash](https://github.com/nymtech/nym/pull/4994): supersedes [\#4916](https://github.com/nymtech/nym/pull/4916)

- [Push private ip before inserting](https://github.com/nymtech/nym/pull/5008)

- [Adjusted ticket sizes to the agreed amounts](https://github.com/nymtech/nym/pull/5009)

- [Consume only positive bandwidth](https://github.com/nymtech/nym/pull/5013)

- [Reapply fixes to new branch](https://github.com/nymtech/nym/pull/5014)

- [Added `get_all_described_nodes` to NymApiClient and adjusted return](https://github.com/nymtech/nym/pull/5016)

- [feature: use axum_client_ip for attempting to extract source ip](https://github.com/nymtech/nym/pull/5031): improves source ip logging by extracting relevant header when nym-api is run behind a proxy

- [Pass poisson flag ](https://github.com/nymtech/nym/pull/5037)

- [Added hacky routes to return nymnodes alongside legacy nodes](https://github.com/nymtech/nym/pull/5051)

- [Use unstable explorer client](https://github.com/nymtech/nym/pull/5058): Clean up stale testruns & better logging:
    - use new `/unstable` endpoints on explorer for backwards compatibility
    - log gw identity key
    - better agent testrun logging
    - log responses on server side
    - change response code for agents
    - update sqlx data
    - fix agent - probe gw bug

- [Merge1/release/2024.13 magura](https://github.com/nymtech/nym/pull/5061)

- [Merge2/release/2024.13 magura](https://github.com/nymtech/nym/pull/5063)

- [Feature/wallet bonding fixes](https://github.com/nymtech/nym/pull/5064)

- [Allow nym node config updates](https://github.com/nymtech/nym/pull/5066)

- [NS API with directory v2 (#5058)](https://github.com/nymtech/nym/pull/5068)

- [chore: deprecated old nym-api client methods and replaced them when possible](https://github.com/nymtech/nym/pull/5069): this is to that the next time those methods are used outside the monorepo, the relevant calls flag up the CI via clippy

- [Allow custom http port to be reset](https://github.com/nymtech/nym/pull/5073)

- [Fix gateway decreasing bandwidth](https://github.com/nymtech/nym/pull/5075): Make sure to update the storage after each decrease with the new values. Also set the storage values to 0 on restart for existing peers, as kernel peers can't have those values set to 0

- [Fix expiration date as today + 7 days](https://github.com/nymtech/nym/pull/5076)

- [Don't increase bandwidth two times](https://github.com/nymtech/nym/pull/5081)

- [Make 250 GB/30 days for free ride mode](https://github.com/nymtech/nym/pull/5083)

- [Nym node - Fix claim delegator rewards](https://github.com/nymtech/nym/pull/5090)

- [Add more translations from v2 to v3 authenticator](https://github.com/nymtech/nym/pull/5091)

- [Graceful agent 1.1.5](https://github.com/nymtech/nym/pull/5093): API improvements:
    - agent exits gracefully when no testrun available
    - agent reads content of server's error message in case of 503
    - API doesn't log every error (to avoid log spam)
    - update network probe within NS agent image: [CI rebuild](https://github.com/nymtech/nym/blob/release/2024.13-magura/nym-node-status-agent/Dockerfile#L9) of NS agent will pick up updated network probe

- [Remove old use of 1GB constant](https://github.com/nymtech/nym/pull/5096)

- [Add NYM_VPN_API to env files](https://github.com/nymtech/nym/pull/5099)

- [Feature/force refresh node](https://github.com/nymtech/nym/pull/5101): currently if nodes update their role from say mixnode to entry-gateway, it might take quite a while for `nym-api` to pick up the change and thus they might be losing performance. With this change, the node will be force refreshed on its startup

- [`nym-credential-proxy-requests`: reqwest use rustls-tls](https://github.com/nymtech/nym/pull/5116)

- [change: dont select mixnodes bonded with vested tokens into the rewarded set](https://github.com/nymtech/nym/pull/5129)

- [Pain/polyfill deprecated endpoints](https://github.com/nymtech/nym/pull/5131)

- [Respond to auth messages with same version](https://github.com/nymtech/nym/pull/5140)

- [Limit race probability](https://github.com/nymtech/nym/pull/5145)

### Bugfix

- [Fix critical issues SI84 and SI85 from Cure53](https://github.com/nymtech/nym/pull/4758): This pull request fixes the following issues:
    - NYM-01-009 WP5: BLS12-381 EC signature bypasses in Coconut library (Critical)
    - NYM-01-014 WP5: Partial signature bypass in offline eCash (Critical)

- [bugfix: correctly paginate through 'search_tx' endpoint](https://github.com/nymtech/nym/pull/4936): when `results.append(&mut res.txs);` was called, `res.txs` was always empty thus it was impossible to return more than page size number of results

- [Fix broken build after merge](https://github.com/nymtech/nym/pull/4937)

- [Bugfix/rewarder post pruning adjustments](https://github.com/nymtech/nym/pull/4942): this PR introduces/fixes the following:
    - dedicated commands to request specific blocks for processing
    - decreased websocket failure timeout
    - ensuring we do actually have sufficient number of blocks to process rewarding for given epoch
    - additional error logging

- [bugfix: fix expected return type on /v1/gateways endpoint](https://github.com/nymtech/nym/pull/4965)

- [Bugfix/additional directory fixes](https://github.com/nymtech/nym/pull/4973): This branch introduces additional fixes to the new directory services

- [Fix critical issues SI86 and SI87 from Cure53](https://github.com/nymtech/nym/pull/4982): This pull request fixes the following issues:
    - Faulty aggregation to invalid offline eCash signatures
    - Signature forgery of Pointcheval-Sanders schema

- [bugfix: client memory leak](https://github.com/nymtech/nym/pull/4991): This fixes memory leaks in all the clients. however, they were most prominent in `nym-api` during network monitoring due to the sheer amount of packets being pushed

- [Fix rustfmt in nym-credential-proxy](https://github.com/nymtech/nym/pull/4992)

- [bugfix: directory v2.1 `get_all_avg_gateway_reliability_in_interval` query](https://github.com/nymtech/nym/pull/5023): fixes query for avg gateway performance (no idea why it makes a difference, but it does...)

- [bugfix: missing #[serde(default)] for announce port](https://github.com/nymtech/nym/pull/5024)

- [bugfix: introduce 'LegacyPendingMixNodeChanges' that does not contain 'cost_params_change'](https://github.com/nymtech/nym/pull/5028)

- [bugfix: verifying signed information of legacy nodes](https://github.com/nymtech/nym/pull/5029)

- [bugfix: fixed backwards incompatibility for /gateways/described endpoint](https://github.com/nymtech/nym/pull/5030)

- [bugfix: make sure to use correct highest node id when assigning role](https://github.com/nymtech/nym/pull/5032)

- [bugfix: use old name for 'epoch_role' in SkimmedNode](https://github.com/nymtech/nym/pull/5034)

- [bugfix: use human readable roles for annotations](https://github.com/nymtech/nym/pull/5036)

- [bugfix: make gateways insert themselves into [local] topology](https://github.com/nymtech/nym/pull/5038)

- [bugfix: use bonded nym-nodes for determining initial network monitor …](https://github.com/nymtech/nym/pull/5039)

- [bugfix: make sure nym-nodes are also tested by network monitor](https://github.com/nymtech/nym/pull/5040)

- [bugfix: don't assign exit gateways to standby set](https://github.com/nymtech/nym/pull/5041)

- [bugfix: fix ecash handlers routes](https://github.com/nymtech/nym/pull/5043)

- [bugfix: restore default http port for nym-api](https://github.com/nymtech/nym/pull/5045): when it was run under 'rocket' server the port used was 8000. let's restore that value

- [bugfix: supersede 'cb13be27f8f61d9ae74d924e85d2e6787895eb14' by using…](https://github.com/nymtech/nym/pull/5046)

- [bugfix: adjust runtime storage migration](https://github.com/nymtech/nym/pull/5047): remove the panic during migration as the gateway count can actually be different if some of them have already migrated to nym-nodes before the code has been run

- [bugfix: mark migrated gateways as rewarded in the previous epoch in case theyre in the rewarded set](https://github.com/nymtech/nym/pull/5049)

- [bugfix/feature: added NymApiClient method to get all skimmed nodes](https://github.com/nymtech/nym/pull/5062)

- [bugfix: use corrext axum extractors for ecash route arguments](https://github.com/nymtech/nym/pull/5065)

- [bugfix: credential-proxy obtain-async](https://github.com/nymtech/nym/pull/5067)

- [bugfix: wallet backend fixes](https://github.com/nymtech/nym/pull/5070)

- [bugfix: additional checks inside credential proxy](https://github.com/nymtech/nym/pull/5072)

- [bugfix: [wallet] displaying delegations for native nymnodes](https://github.com/nymtech/nym/pull/5087)

- [bugfix: preserve as much as possible of the rewarded set during migration](https://github.com/nymtech/nym/pull/5103)

- [bugfix: make sure to assign correct node_id and identity during 'gateway_details' table migration](https://github.com/nymtech/nym/pull/5142)

- [bugifx: assign 'node_id' when converting from 'GatewayDetails' to 'TestNode'](https://github.com/nymtech/nym/pull/5143)

### Operators Updates & Tooling

**Every operator has to make sure that their nodes self-described endpoint works, otherwise the node will be un-routable and thus won't get any rewards!**

- **New technical documentation:** All Nym documentation starts from a new entry page [nymtech.net/docs](https://nymtech.net/docs/operators/introduction). To run locally or propose collaboration, start in our [repository](https://github.com/nymtech/nym/tree/develop/documentation)

- **New [Tokenomics chapter](tokenomics.mdx) with [Mixnet Rewards page](tokenomics/mixnet-rewards.mdx)**

- **[Operators release & rewards roadmap](tokenomics/mixnet-rewards.mdx#roadmap)**

- **New [Operators landing page](https://nymtech.net/operators)**

- [Nym Harbourmaster](https://harbourmaster.nymtech.net) had a new tab `NODE SEARCH` where operators can easily search nodes by identity keys and owner accounts and get all public information listed.

- Simplified [bonding](nodes/nym-node/bonding.mdx) and [Mixnet smart contract migration](nodes/nym-node/bonding.mdx#migrate-to-nym-node-in-mixnet-smart-contract)

- Nodes bonded with vesting tokens are [not allowed to join rewarded set](https://github.com/nymtech/nym/pull/5129) - read more on [Nym operators forum](https://forum.nymtech.net/t/vesting-accounts-are-no-longer-supported/827)

#### Wallet changes

**[New wallet version 1.2.15](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.15) is out!**

- [New wallet changelog](https://github.com/nymtech/nym/blob/nym-wallet-v1.2.15/nym-wallet/CHANGELOG.md)

- This version of wallet allows and prompts operators to migrate their gateway or mixnode to a `nym-node` in the Mixnet smart contract - an important step in [project smoosh](archive/faq/smoosh-faq.mdx). To do so follow these steps:

###### 1. Download the wallet from [the release page](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.15)

###### 2. Verify the binary and extract it if needed

- Download [`hashes.json`](https://github.com/nymtech/nym/releases/download/nym-wallet-v1.2.15/hashes.json)
- Open it with your text editor or print it's content with `cat hashes.json`
- Run `sha256sum <WALLET_BINARY>` for example `sha256sum ./nym-wallet_1.2.15_amd64.AppImage`
- If your have to extract it (like `.tar.gz`) do it

###### 3. Open the wallet and sign in

###### 4. Migrate!

- Go to Bonding and you will be prompted with such message:

![](/images/operators/wallet-screenshots/migrate_nym-node.png)

- In case you for some reason didn't see the prompt or you closed it - you can click in the upper right corner of the same window on this button:

![](/images/operators/wallet-screenshots/migrate_nym-node2.png)

- Confirm the transaction

###### 5. Welcome to new episode of `nym-node`!

</ Steps>

- **Older versions will not allow bonding new nodes!**

#### Selection & Rewarding

- **Config score is introduced:** In the current version the nodes selection to the active set has a new parameter (which multiplies the existing formula) - `config_score`. Config score looks if the node binary is `nym-node` (not legacy `nym-mixnode` or `nym-gateway`) **AND** if [Terms & Conditions](nodes/nym-node/setup.mdx#terms--conditions) are accepted. Config score has binary values of either 0 or 1, with a following logic:

| **Run `nym-node` binary** | **T&C's accepted** | **`config_score`** |
| :--                       | :--                | ---:               |
| True                      | False              | 0                  |
| False                     | True               | 0                  |
| False                     | False              | 0                  |
| True                      | True               | 1                  |

- The active set selection formula is then:
> CONFIG_SCORE \* STAKE_SATURATION \* PERFORMANCE ^ 20

- Currently in *Native rewarding*, the rewards are split equally across the [rewarded set of nodes](https://validator.nymtech.net/api/v1/epoch/reward_params) (which now = active set and it's size is 240 nodes) for both Mixnet mode and dVPN mode. Every node being assigned 1 / 240 work factor (hence *naive rewarding*).

#### Directory Services v2.1: API & Mixnet Contract Changes

Magura release brings [breaking changes on API](https://github.com/nymtech/nym/pull/4903) logic of Nym. New APIs will only communicate with `nym-node` from this release and newer. Also old version of APIs won't be able to communicate with the new version of `nym-node`. We are also moving towards completely removing Nym Explorer API, which now has been only used to report nodes location.

Any new bonded node will provide only the bare minimum information: host, identity key and optionally custom port of its HTTP api - we highly recommend to set that one up to `8080`. Everything else will be discovered via the self-described API for maximum flexibility. This also includes the sphinx key, meaning if the API is not exposed, the node will be unable to route any traffic. Furthermore, this allows to arbitrary change of   `nym-node` from mixnode into a gateway modes (and vice versa) without losing any delegations.

The contract changes also mean any node functionality can get rewards. Rather than just with assigned mixing roles, gateways now also added into the pool. However, to be eligible for gateway rewarding, one must [migrate into a `nym-node`](#wallet-changes) on a smart contract level (or bond a new node).

##### API High Level Changes

###### New/Added

- All new routes that return multiple nodes/entries/etc now wrap their responses to expect pagination. Currently, however, full data is returned for each of the endpoints since the pagination hasn't been  implemented yet. But once we add it, it won't be a breaking API change.

###### Removed

- `rocket` support has been completely removed. All routes are now always served via `axum`

###### Changed

- Getting anything to do with all nodes (including gateways) requires knowing their `node_id`. For legacy gateway endpoints, we have a helper method that translates identity key to the `node_id`
- Rewarded set is no longer populated with just mixnodes. Instead `nym-node`s are assigned to eligible roles (based on stake and performance) in the following order:
    - entry gateways
    - exit gateways
    - mixnodes
    - standby
- A lot of legacy routes got deprecated. while technically they still "work" and return data, they only return data for legacy `nym-mixnode` and `nym-gateway`. What it means is that as operators are migrating their nodes (in the smart contract), those endpoints will start running dry.
- Since layers are only assigned during rewarded set assignment, for the purposes of network monitor (v1) and legacy mixnode routes, layerless nodes are put on random layers during annotation
- All legacy gateway queries now also include additional field in their respones: `node_id` that indicate the id pre-assigned during contract migration
- Nym Node performance is a bit odd. When network monitors (v1 and v2) were made, there was no concept of a Nym Node. The solution taken is checking whther there is any mixnode performance for node with a given id, if so - return it. Otherwise we grab the equivalent gateway performance. In the future it should probably be averaged or maybe split into explicit mixing or gateway routing performance metrics.

##### `nym-api` Changes

- Root route `/` now redirects to `/swagger`

###### `nym-node` Routes

- `/v1/nym-nodes/annotation/<NODE_ID>` - get annotation about particular `nym-node`, as gathered by this `nym-api`. Currently this just includes last 24h performance metric and the current node role
- `/v1/nym-nodes/bonded` - get bond information about Nym Nodes, as present in the mixnet contract
- `/v1/nym-nodes/described` - get described information about Nym Nodes, as present on their self-described API
- `/v1/nym-nodes/historical-performance/<NODE_ID>` - return historical performance of this `nym-node` on the provided date
- `/v1/nym-nodes/performance-history/<NODE_ID>` - return performance history of this `nym-node` (as a 0 - 1 float)
- `/v1/nym-nodes/uptime-history/<NODE_ID>` - return current uptime of this `nym-node` (as a 0 - 100 u8); added for compatibility with existing APIs using that data format
- `/v1/nym-nodes/performance/<NODE_ID>` - return current performance of this `nym-node`
</ AccordionTemplate>

- `/v1/unstable/nym-nodes/noise` - returns basic information needed for the noise protocol between nodes
- `/v1/unstable/nym-nodes/skimmed/active` - returns all: Nym Nodes and legacy mixnodes and legacy gateways, that are currently in the active set, unless `no-legacy` parameter is used
- `/v1/unstable/nym-nodes/skimmed/mixnodes/active` - returns all: Nym Nodes and legacy mixnodes, that are currently in the active set, unless `no-legacy` parameter is used
- `/v1/unstable/nym-nodes/skimmed/mixnodes/all` - returns all: Nym Nodes and legacy mixnodes, that are currently bonded and support mixing role, unless `no-legacy` parameter is used
- `/v1/unstable/nym-nodes/skimmed/entry-gateways/active` - returns all: Nym Nodes and legacy gateways, that are currently in the active set and are assigned the entry role, unless `no-legacy` parameter is used
- `/v1/unstable/nym-nodes/skimmed/exit-gateways/active` - returns all: Nym Nodes and legacy gateways, that are currently in the active set and are assigned the exit role, unless `no-legacy` parameter is used
- `/v1/unstable/nym-nodes/skimmed/entry-gateways/all` - returns all: Nym Nodes and legacy gateways, that are currently bonded and support entry gateway role, unless `no-legacy` parameter is used
- `/v1/unstable/nym-nodes/skimmed/exit-gateways/all` - returns all: Nym Nodes and legacy gateways, that are currently bonded and support exit gateway role, unless `no-legacy` parameter is used
</ AccordionTemplate>

###### Deprecated (will be removed eventually, so please migrate away from their usage)

Some endpoints got purposely deprecated without any equivalent reimplemented since they do not belong on `nym-api`. This includes for example `/stake-saturation` (which can be obtained directly from the contract instead) or `/inclusion-probability` (for this run your own Monte Carlo simulation).

- `contract-cache` routes - all of the below got deprecated as they will only return **legacy** `nym-mixnode` and `nym-gateway` data:
    - `/v1/gateways`
    - `/v1/gateways/blacklisted`
    - `/v1/mixnodes`
    - `/v1/mixnodes/active` - just to restate the obvious, it will only return a small **SUBSET** of the active set that since it will ignore active Nym Nodes
    - `/v1/mixnodes/active/detailed`
    - `/v1/mixnodes/blacklisted`
    - `/v1/mixnodes/detailed`
    - `/v1/mixnodes/rewarded`
    - `/v1/mixnodes/rewarded/detailed`
- `status` routes - all of the below got deprecated as they will only return **legacy** `nym-mixnode` and `nym-gateway` data:
    - `/v1/status/gateway/<ID_KEY>/report`
    - `/v1/status/gateway/<ID_KEY>/history`
    - `/v1/status/gateway/<ID_KEY>/core-status-count`
    - `/v1/status/gateway/<ID_KEY>/avg_uptime`
    - `/v1/status/gateways/detailed`
    - `/v1/status/gateways/detailed-unfiltered`
    - `/v1/status/mixnode/<MIX_ID>/report`
    - `/v1/status/mixnode/<MIX_ID>/history`
    - `/v1/status/mixnode/<MIX_ID>/core-status-count`
    - `/v1/status/mixnode/<MIX_ID>/avg_uptime`
    - `/v1/status/mixnodes/detailed`
    - `/v1/status/mixnodes/detailed-unfiltered`
    - `/v1/status/mixnode/<MIX_ID>/status`
    - `/v1/status/mixnode/<MIX_ID>/reward-estimation`
    - `/v1/status/mixnode/<MIX_ID>/compute-reward-estimation`
    - `/v1/status/mixnode/<MIX_ID>/stake-saturation`
    - `/v1/status/mixnode/<MIX_ID>/inclusion-probability`
    - `/v1/status/mixnodes/inclusion_probability`
    - `/v1/status/mixnodes/rewarded/detailed`
    - `/v1/status/mixnodes/active/detailed`
- `nym-node` routes - all of the below got deprecated as they will only return **legacy** `nym-mixnode` and `nym-gateway` data:
    - `/v1/gateways/described`
    - `/v1/mixnodes/described`

- `Unstable Nym Nodes Routes`:
    - `/v1/unstable/nym-nodes/mixnodes/skimmed` - due to inconsistency in behaviour (i.e. active vs all) it is now redirected to `/v1/unstable/nym-nodes/mixnodes/skimmed/active` and unwraps the pagination
    - `/v1/unstable/nym-nodes/gateways/skimmed` - due to inconsistency in behaviour (i.e. active vs all) it is now redirected to `/v1/unstable/nym-nodes/entry-gateways/skimmed/all` and unwraps the pagination
</ AccordionTemplate>

- `Unstable Nym Nodes Routes`:
    - `/v1/unstable/nym-nodes/skimmed` - now works with `exit` parameter
    - `/v1/unstable/nym-nodes/skimmed` - introduced `no-legacy` flag to ignore legacy `nym-mixnode` and `nym-gateway` (where applicable)
    - `/v1/unstable/nym-nodes/skimmed` - will now return all nodes if no query parameter is provided
</ AccordionTemplate>

##### Mixnet Contract

**Every operator has to make sure that their nodes self-described endpoint works, otherwise the node will be un-routable and thus won't get any rewards!**

###### High Level Changes

**New/Added**

- All new nodes are now bonded as Nym Nodes, even when using old `BondMixnode` or `BondGateway` messages (messages are getting translated)
- Operators only announce nodes identity key (`<ID_KEY>`), host and port to the directory. Everything else is discovered via self-described endpoint
- All Nym Nodes in the rewarded set are eligible for rewards and staking. Even if they serve one of the gateway roles. Legacy gateways can't be staked on nor get rewards.
- All nodes, including legacy mixnodes and legacy gateways, are now uniquely identified by a monotonically increasing `node_id`
- All legacy gateways are preassigned `node_id` during the contract migration

**Removed**

> 🔥 all concepts of node families got purged, removed, deleted, thrown into the abyss. they simply no longer exist and the world is all better for it.

**Changed**

- Bunch of types got changed/renamed with some fields being added/removed/deprecated. It's be quite a lot of work to list them all here, but whenever possible and feasible, they should be cross-compatible (but not always).
- Rewarded set is no longer just a "number". Instead it has an explicit number of all `nym-node` modes: mixnodes, entry and exit gateways as well as standby nodes
- Rewarding is now based on two parameters: performance and work factor as opposed to performance and "is active" flag. However, in practice, during this transitional period, it is assumed that the work factor will be equivalent to what would have been calculated using the old "is active" flag

###### Transaction Messages Changes

- `BondNymNode` - self-explanatory
- `UnbondNymNode` - self-explanatory
- `UpdateNodeConfig` - works as `UpdateMixnodeConfig`; it lets you change your announced host or http api port
- `MigrateMixnode` - migrate your existing legacy mixnode into a Nym Node
- `MigrateGateway` - migrate your exsting legacy gasteway into a Nym Node. enables staking and rewarding
- `AssignRoles` - an additional step for epoch transition transactions. think of it as a replacement for `AdvanceCurrentEpoch`. it assigns nodes to particular roles for the given epoch

- As mentioned, all family-related things got killed off, so the following no longer exist: `CreateFamily`, `JoinFamily`, `LeaveFamily`, `KickFamilyMember`, `CreateFamilyOnBehalf`, `JoinFamilyOnBehalf`, `LeaveFamilyOnBehalf`, `KickFamilyMemberOnBehalf`
- `UpdateActiveSetSize` - the rewarded/active set are now based on the role distribution
- `AssignNodeLayer` - we're no longer explicitly assigning roles to all mixnodes, instead they get assigned mixing roles
- `AdvanceCurrentEpoch` - the logic for advancing the epoch/assigning active set has changed so this message was removed

## `v2024.12.1-aero` - patch

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.12.1-aero)
- `nym-node` patch only, no other binaries

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-11-07T08:45:13.162565620Z
Build Version:      1.1.9-1
Commit SHA:         ccdee808303ffcfa8ed77176d3f629512045febb
Commit Date:        2024-11-06T16:31:30.000000000+01:00
Commit Branch:      HEAD
rustc Version:      1.82.0
rustc Channel:      stable
cargo Profile:      release
```

### Changes

- Fixed timeout connectivity issues with authenticator
- Amended network allowance cap

## `v2024.12-aero`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.12-aero)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.12-aero/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.9`

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2024-10-17T08:57:52.525093253Z
Build Version:      1.1.9
Commit SHA:         d75c7eaaaf3bb7350720cf9c7657ce3f7ee6ec2e
Commit Date:        2024-10-17T08:51:39.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.81.0
rustc Channel:      stable
cargo Profile:      release
```

### Features

- [Rust sdk stream abstraction](https://github.com/nymtech/nym/pull/4743): Starting to move this from being standalone binaries (as seen [here](https://github.com/nymtech/nym-zcash-grpc-demo)) into the sdk. EDIT this has sort of expanded a bit to include a few things:
  - [x] simple example
  - [x] example doc to `src/tcp_proxy.rs`
  - [x] simple echo server in `tools/`
  - [x] multithread example
  - [x] example to sdk for using different network
  - [x] go ffi for proxies

- [Build(deps): bump `toml` from `0.5.11` to `0.8.14`](https://github.com/nymtech/nym/pull/4805): [`toml`](https://github.com/toml-rs/toml) version update

<AccordionTemplate name={<TestingSteps/>}>
- Ensured that the `cargo.toml` is legible in various places; tested it on `nym-node`, `nym-api` and `nymvisor`.
- Ensured that updating the cargo.toml file and restarting the given binary continues to behave as normal.

- [Use `serde` from workspace](https://github.com/nymtech/nym/pull/4833): cargo autoinherit for `serde` - cargo autoinherit for `bs58` and `vergen` in `cosmwasm-smart-contracts`

- [Gateway database modifications for different modes](https://github.com/nymtech/nym/pull/4868): As gateway clients will not be solely from the mixnet, we need to split the table that handles shared keys from the client ids that are referenced from other tables. That way, the bandwidth table can be shared between different client types (entry mixnet, entry gateway, exit gateway), using the same `client_id` referencing.

- [Remove the push trigger for `ci-nym-wallet-rust`](https://github.com/nymtech/nym/pull/4869)

- [Chore: remove queued migration for adding explicit admin](https://github.com/nymtech/nym/pull/4871)

- [Allow clients to send stateless gateway requests without prior registration](https://github.com/nymtech/nym/pull/4873): in order to make changes to the registration/authentication procedure we needed a way of extracting protocol information before undergoing the handshake.

- [Fix sql `serde` with `enum`](https://github.com/nymtech/nym/pull/4875)

- [Few fixes to NNM pre deploy](https://github.com/nymtech/nym/pull/4883)

- [Feature/updated gateway registration](https://github.com/nymtech/nym/pull/4885): This PR introduces support for aes256-gcm-siv shared keys between clients and gateways.
    - Those changes should be fully backwards compatible. if they're not, there's a bug.

<AccordionTemplate name={<TestingSteps/>}>
- For the following combinations I inited the client, ran the client, stopped the client, and ran the client again:
- Fresh client on new binary && gateway on old binary
- Fresh client on old binary && gateway on new binary
- Fresh client on new binary && gateway new binary
- Existing old client on old binary & new gateway

- [Build and Push CI](https://github.com/nymtech/nym/pull/4887)

- [Entry wireguard tickets](https://github.com/nymtech/nym/pull/4888): Note: The behaviour of the nodes and vpn client (as a test) has not changed, it still works as it used to. Obtaining ticketbooks also is unchanged

- [Update `nym-vpn` metapackage and replace `nymvpn-x` with `nym-vpn-app`](https://github.com/nymtech/nym/pull/4889): Change dependency from `nymvpn-x` to `nym-vpn-app` to reflect the new package name of the tauri client

- [Update network monitor entry point](https://github.com/nymtech/nym/pull/4893)

- [Remove clippy github PR annotations](https://github.com/nymtech/nym/pull/4896): It eats up CI resources and time to run the clippy annotation checks that likely no one uses anyway. We keep the clippy checks of course.

- [Fix clippy for beta toolchain](https://github.com/nymtech/nym/pull/4897):

- [Update cargo deny](https://github.com/nymtech/nym/pull/4901): Update to use latest `cargo-deny`. Here are the steps done:
  - Regenerate `deny.toml`
  - Backport old settings to `deny.toml`
  - Explicitly allow GPL-3 only on our own specific crates
  - Update `deny.toml` for latest changes
  - Fix `cargo-deny` warnings for duplicate crates
  - Update `cargo-deny-action` to v2

- [Data Observatory stub](https://github.com/nymtech/nym/pull/4905): You need Postgres up for `sqlx` compile-time checked queries to work

<AccordionTemplate name={<TryYourself/>}>

- Get [`page_up.sh` script](https://github.com/nymtech/nym/blob/develop/nym-data-observatory/pg_up.sh)

```bash
./pg_up.sh
```

- Play with the database:
```bash
docker exec -it nym-data-observatory-pg /bin/bash
psql -U youruser -d yourdb
```

- [Proxy ffi](https://github.com/nymtech/nym/pull/4906): Updates Go & CPP FFI with the proxy code from  [\#4743](https://github.com/nymtech/nym/pull/4743)

- [Bump `http-api-client` default timeout to 30 sec](https://github.com/nymtech/nym/pull/4917)

- [Check both version and type in message header](https://github.com/nymtech/nym/pull/4918)

- [Fix argument to `cargo-deny` action](https://github.com/nymtech/nym/pull/4922)

- [Expose error type](https://github.com/nymtech/nym/pull/4924)

- [Make ip-packet-request VERSION pub](https://github.com/nymtech/nym/pull/4925)

- [Assume offline mode](https://github.com/nymtech/nym/pull/4926)

- [`nym-node`: don't use bloomfilters for double spending checks](https://github.com/nymtech/nym/pull/4960): this PR disables gateways polling for double spending bloomfilters and also `nym-apis` from providing this data.

### Bugfix

- [Fix `apt install` in `ci-build-upload-binaries.yml`](https://github.com/nymtech/nym/pull/4894)

- [Fix missing duplication of modified tables](https://github.com/nymtech/nym/pull/4904)

- [Fix nymvpn.com url in mainnet defaults](https://github.com/nymtech/nym/pull/4920): The old URL (nympvn.net) works since it is redirected to nymvpn.com, but the extra round-trip adds latency to all the API calls the vpn client does. So this PR should help speed things up, in particular when these API calls happen across the mixnet.

- [Fix handle drop](https://github.com/nymtech/nym/pull/4934)

- [Replace unreachable macro with an error return](https://github.com/nymtech/nym/pull/4958)

### Operators Guide, Tooling & Updates

#### Documentation Updates

- [Update FAQ sphinx size](https://github.com/nymtech/nym/pull/4946): This PR upgrades url to our code base sphinx creation from an outdated branch to develop.

#### Fast & Furious - WireGuard edition

Nym team started another round of load and speed testing. This time the tests are limited to Wireguard mode Gateways - to find out any weak spots for needed improvement. The load testing is happening directly on mainnet as it simulates a real user traffic which the network components must be able to handle in order.

Over past week we ran a total of three tests, with 450 clients at most. We've managed to push around 300 GB in total. Around 50% of requests failed. Over the course of those three tests, we did about 5000 requests, and bandwidth per client varies between 50Mb/s and 150Mb/s.

We already caught two bugs and [fixed](https://github.com/nymtech/nym/pull/4885) it in this release.

**The faster the operators upgrade to this [latest release](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.12-aero), the better**. A that will allow us to do more precise testing through the nodes without the registry bug, leading to more precise specs for `nym-node`.

Here are the aims of these tests:

1. Understanding of the wireguard network behavior under full load
    - How many client users can all entry gateways and exit gateways handle simultaneously?
    - How much sustained IP traffic can a subset of mainnet nodes sustain?
2. Needed improvements of Nym Node binaries to improve the throughput on mainnet
3. Measurement of required machine specs
    - Releasing a new spec requirements
4. Raw data record
5. Increase quality of Nym Nodes

Meanwhile we started to research pricing of stronger servers with unlimited bandwidth and higher (and stable) port speed, to arrive to a better understanding of needed rewards and grants to bootstrap the network before NymVPN launch.

More info about testing and tools for performance monitoring can be found in [this chapter](performance-and-testing).

> We would like to call out to operators to join the efforts and reach out to us if they know of solid ISPs who offer reliable dedicated services for good price or may even be interested in partnership.

#### Delegation Program

In October we again proceeded with our Delegation Program. 22 nodes didn't meet the program rules and got their delegation removed and 25 nodes from the que received delegation. Below is a complete list.

Delegated:
```
Ce6kcPckNfQsga2z645VFQYadtoTjqXrS1YXMTtNNv98
2XSCWy1vAoJRaYBJXx4KWwjU1cfoS2wNBXVQZvi8Jtdr
Bu4sUGjJqkje4vSncTH2KgrnojmfESdaYwamC6DbpJGZ
7TWEw9qQxsc8w4WhPAX6zjZ8vuNBdtP21zUVN8K26RkD
HejyqervmGTCEwi1JbRBXV5My463336huBn8ZgSpuhc3
CXcCVGiamYSwgVwaxW3mEkXkZh1sKY2TXnWjjTjxDxzA
FScLfnKUPv9wSef3R4N2pQ9ft7DiwdivLW1i65Dqfc9L
2vuZZJjyYN27fvDbhyqeGosewGWaRh6iVsFtqbJoYAR7
B9QiBsSAx7MRcTpYMs1fu9AFJurAZTPWMispHZXPbaVW
E3e2a9kXZjQXsKAfvmCf2WqwmVkiGR2LbjCwoadZgEJt
Dk4fCLM7idHPqfsUucLQtSMtYaYCLhi4T7vwvw88jG3P
9xZUp4sYWUNJesWy3MPVjh5kTorNqj3RxcFgBmYjV1xV
HK9QxPpdJfNtNpLJZHTN5M113jeBbFzTkMtPt9eouimx
ECkzyHfoiNGKyDTtbbH5HDCWa8KMGh92mtGbGHLZ3Y9n
9jQQV9vQ2mFFXywwVhACCKefjUFpyBoCU6KXNfjAEi45
6QguhCfnDPKJe8bQXg9myuPB89yYFk6R77vMhLTbipK7
4hAJJQhLTFve8FZGd28ksjavbch8STMax2rytzKmDPCV
EZLFq5HGXFKRpxu78nVjf7kuuUaKPLAbezR6mXbZrP6y
FtAAA5GMxY1Ge9wKYDrQgaSfJEUp4XvBLptBwy3GU8ap
tUiLPjz5nkPn5ZJT5ZXLPGDcZ3caQsfkMAp1epoAuSQ
4ScsM6AVowhKTMWaH98NLntKDwbu2ZMEycUk4mZiZppG
Hb34PTth6CeFziPAAEUMEjJFHWJg1dDex5QxUXKNqRBE
9ek1PMvLhpbwZe7kTMyCVY5VNqrdSPPoruFPQtbxnZyf
```

Undelegated due to the use of an outdated binary:
```
9UHXFYuMLhuugndt8xCFRydmDPFyEEUHYc72tNANEtHp
5Y86A7fUX3LYVDDeoujtAiZFudYcHJq6gw8nsp71wN7U
HYWjn6yL8y7TBPFL9bTgDm6tHgyoEQupgJuBhLLoA5EY
4JCpbdhiQFKWwhrbkNDbwcwBGZnvU4WQrF2vqQLfmZvW
2f7JaYmmrMQQMczLX32ogfP7PBHeyPKbAVNjjEsExZVd
9TW55JrsFhsMoe3Tf8LBR4bPSCX86VXyvioMmCw9tWB
AyN34XqUi5XxgjmivWG2z6TftkqAFjVV5C9zCbx8Fvp5
skNS4zNsKdbbUR9wFTJoPdmReW4NdrDEpp8512TNG4f
DztUnMKM545sdipgqhCsPNhK3YVmBbS2fp9HZgM5Jpw9
GnLmx1s7g9nH3uLRhGpaXTbQEhCSKB6YenBQWQhthSx9
GoJjAkH5hpcPYeW7JDUVfHdqgcufjwdhY2PLwBGJV3Ar
EdHVMTXpLiBbvCUnEoSPQ86pBNY1h9HtL34Q7cpNPWCy
```

Undelegated due to increased operation costs or profit margin:
```
Erw9AQ4UJCgCiAWisUWbFk9Yedm8qvW4YQqmJRrBrE5p
BVDVtmNbZRgPKU81uBkrgfj5TnhtZqQcPAwxD48jcfMd
36nmH3kawhAsNA6sxFva2HgTnQHQDbcrRefvWWbmhHvY
2831fyXRAJ88x1Pd5aW7utw7WH1XkHZEfoWhLk2foLxJ
AMDS4cib433iRstwP9mWnZ4zPqb6hm6uPF7PpvhSkpYC
DE9eEeVsuiKeVfwebg5HYsebqRUvxd7LWsT9hQUtVrTQ
FAKhiQ8nW5sAWAxks1WB8u1MAWsapToCSE3KmF9LuGRQ
```

Undelegated due to being blacklisted for extensive period
```
sjL9n9ymxfWWwkQJxXdsMkdwamXfh3AJ3vCe7rJ8RrT
E2HAJrHnk56QZDUCkcjc4i4pVEqtyuPYL5bNFYtweQuL
4PytR3tmodsvqGTKdY47yie8kmrkARQdb5Ht3Ro3ChH4
```

---

## `v2024.11-wedel`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.11-wedel)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.11-wedel/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.8`

```sh
Binary Name:        nym-node
Build Timestamp:    2024-09-27T11:02:37.073944654Z
Build Version:      1.1.8
Commit SHA:         c3ec970a377adb25d57be5428551fada2ec55128
Commit Date:        2024-09-26T08:24:53.000000000+02:00
Commit Branch:      master
rustc Version:      1.80.1
rustc Channel:      stable
cargo Profile:      release
```

### Features

- [New Network Monitor](https://github.com/nymtech/nym/pull/4610): Monitors the Nym network by sending itself packages across the mixnet. Network monitor is running two tokio tasks, one manages mixnet clients and another manages monitoring itself. Monitor is designed to be driven externally, via an `HTTP api`. This means that it does not do any monitoring unless driven by something like [`locust`](https://locust.io/). This allows us to tailor the load externally, potentially distributing it across multiple monitors. Includes a dockerised setup for automatically spinning up monitor and driving it with locust.
    - *Note: NNM is not deployed on mainnet yet!*

- [Add get_mixnodes_described to validator_client](https://github.com/nymtech/nym/pull/4725)

- [Remove deprecated mark_as_success and use new disarm](https://github.com/nymtech/nym/pull/4751): Update function name to keep terminology consistent with tokio `CancellationToken DropGuard`.

- [Update peer refresh value](https://github.com/nymtech/nym/pull/4754): `lso` expose the value by moving it to wireguard types, and separate the refresh time to the database sync time, so that more probable and needed actions happen faster (refresh) and more improbable ones don't overload the system (peer suspended or stale)
<AccordionTemplate name={<TestingSteps/>}>
- **Noted** that the constants `DEFAULT_PEER_TIMEOUT` and `DEFAULT_PEER_TIMEOUT_CHECK` have been moved to `common/wireguard-types/src/lib.rs` and are now being used across modules for consistency
- **Observed** that the `peer_controller.rs` now separates the in-memory updates from the storage sync operations to reduce system load
- **Identified** that in-memory updates of peer bandwidth usage happen every `DEFAULT_PEER_TIMEOUT_CHECK` (every 5 seconds), while storage updates occur every 5 * `DEFAULT_PEER_TIMEOUT_CHECK` (every 25 seconds)

**Checked System Load and Performance:**

- **Monitored** system resource usage (CPU, memory, I/O) during the test to assess the impact of the changes
- **Confirmed** that the separation of in-memory updates and storage syncs resulted in reduced system load, particularly I/O operations, compared to previous versions where storage updates occurred more frequently
- **Ensured** that the system remained responsive and no performance bottlenecks were introduced

- **Efficiency Improvement:** The separation of in-memory updates and storage syncs effectively reduced unnecessary database writes, improving system efficiency without compromising data accuracy

- [Remove duplicate stat count for retransmissions](https://github.com/nymtech/nym/pull/4756)

- [Make gateway latency check generic](https://github.com/nymtech/nym/pull/4759): Replace concrete gateway type with trait in latency check, so we can make use of it in the vpn client.
<AccordionTemplate name={<TestingSteps/>}>
- Initialised new `nym-client` with the `--latency-based-selection` flag and ensured it still works as normal.

- [chore: remove repetitive words](https://github.com/nymtech/nym/pull/4763)

- [Avoid race on ip and registration structures](https://github.com/nymtech/nym/pull/4766): To avoid a state where the ip is being cleared out before the registration is also cleared out, couple the two structures under the same lock, since they are anyway very inter-dependent.
<AccordionTemplate name={<TestingSteps/>}>
1.  - **Checked out** the release/2024.10-wedel branch containing the fix for the race condition on IP and registration structures
    - **Deployed** the on a controlled test environment to prevent interference

2. **Monitored Logs:**

    - **Enabled** debug logging to capture all events
    - **Monitored** logs in real-time to observe the handling of concurrent registration requests
    - **Checked** for any error messages, warnings, or indications of race conditions

3. **Verified Client Responses:**

    - Ensured that all clients received appropriate responses:
    - Successful registration with assigned IP and registration data
    - Appropriate error messages if no IPs were available or if other issues occurred
    - Confirmed that no clients were left in an inconsistent state (e.g., assigned an IP but not fully registered)

4. **Validated Normal Operation:**
    - **Conducted standard registration processes** with individual clients to confirm that regular functionality is unaffected via `nym-vpn-cli`
    - Ensured that authenticated clients could communicate over the network as expected

- [Persist used wireguard private IPs](https://github.com/nymtech/nym/pull/4771)

- [Enable dependabot version upgrades for root rust workspace](https://github.com/nymtech/nym/pull/4778)

- [Fix clippy for `unwrap_or_default`](https://github.com/nymtech/nym/pull/4783): Fix nightly build for [beta toolchain](https://github.com/nymtech/nym/actions/runs/10552082396/job/29230401668)

- [Update dependabot](https://github.com/nymtech/nym/pull/4796): Bump max number of dependabot rust PRs to 10. Add readme entry to workspace package.

- [Run `cargo-autoinherit` for a few new crates](https://github.com/nymtech/nym/pull/4801): Run cargo-autoinherit for a few new crates - Sort crates list.

- [Add `axum` server to `nym-api`](https://github.com/nymtech/nym/pull/4803): Summary PR to add axum functionality behind a feature flag `axum`, alongside rocket.

- [Remove unused wireguard flag from SDK](https://github.com/nymtech/nym/pull/4823)

- [Expose wireguard details on self described endpoint](https://github.com/nymtech/nym/pull/4825)

<AccordionTemplate name={<TestingSteps/>}>
Wireguard details are now visible at the nym-node endpoint `/api/v1/gateway/client-interfaces` as well as on the nym-api self-described endpoint `/api/v1/gateways/described`, above the existing data displaying mixnet_websocket information.

An example of what will be shown is:
```json
 "wireguard": {
 "port": 51822,
 "public_key": "<some public key here>"
 }
```

- [Revamped ticketbook serialisation and exposed additional cli methods](https://github.com/nymtech/nym/pull/4827): `wip` branch that includes changes needed for `vpn-api` alongside additional `ecash utils`
<AccordionTemplate name={<TestingSteps/>}>
Checked the following commands:
```sh
show-ticket-books # which displays the information about all ticketbooks associated to the client
import-ticket-book # which imports a normal ticketbook to the client alongside `--full` flag
```

On the cli, the following were added: `import-coin-index-signatures`, `import-expiration-date-signatures` and `import-master-verification-key`.

- [Run cargo autoinherit following last weeks dependabot updates](https://github.com/nymtech/nym/pull/4831)

- [Remove serde_crate named import](https://github.com/nymtech/nym/pull/4832)

- [Create nym-repo-setup debian package and nym-vpn meta package](https://github.com/nymtech/nym/pull/4837): Create nym-repo-setup debian package that sets up the nymtech debian repo on the system it's installed on. It does 2 things:

    1. Copy the keyring to `/usr/share/keyrings/nymtech.gpg`
    2. Copy the repo spec to `/etc/apt/sources.list.d/nymtech.list`
    - Also create a meta package `nym-vpn` which only purpose is to depend on the daemon and UI.

<AccordionTemplate name={<TryYourself/>}>
1. Install with
```sh
sudo dpkg -i ./nym-repo-setup.deb
```
2. Once it's installed, it should be possible to install the vpn client with
```sh
sudo apt install nym-vpnc
```
3. To remove the repo, use
```sh
sudo apt remove nym-repo-setup
```

NOTE: removing the repo will not remove any installed nym-vpn packages

<AccordionTemplate name={<TestingSteps/>}>
1. **Downloaded** the `nym-repo-setup.deb` package to a Debian-based test system

2. **Installed** the repository setup package using the command:
```bash
sudo dpkg -i ./nym-repo-setup.deb
```

3. **Verified** that the GPG keyring was copied to `/usr/share/keyrings/nymtech.gpg`:
```bash
ls -l /usr/share/keyrings/nymtech.gpg
```

4. **Checked** that the repository specification was added to `/etc/apt/sources.list.d/nymtech.list`:
```bash
cat /etc/apt/sources.list.d/nymtech.list
```

 5. **Updated** the package list:
```bash
sudo apt update
```

6. **Installed** the VPN client meta-package:
```bash
sudo apt install nym-vpnc
```

7. **Confirmed** that the `nym-vpnc` package and its dependencies (daemon and UI) were installed successfully

8. **Tested** the VPN client to ensure it operates as expected

9. **Removed** the repository setup package:
```bash
sudo apt remove nym-repo-setup
```

10. **Verified** that the repository specification file `/etc/apt/sources.list.d/nymtech.list` was removed

11. **Ensured** that the installed `nym-vpnc` packages remained installed and functional after removing the repo setup package

- [Use ecash credential type for bandwidth value](https://github.com/nymtech/nym/pull/4840)

- [Start switching over jobs to arc-ubuntu-20.04](https://github.com/nymtech/nym/pull/4843)

<AccordionTemplate name={<CiConfig/>}>
```
 - ci-build-upload-binaries
 - ci-build
 - ci-cargo-deny
 - ci-contracts-schema
 - ci-contracts-upload-binaries
 - ci-contracts
 - ci-docs
 - ci-nym-wallet-rust
 - ci-sdk-wasm
```

- [Move credential verification into common crate](https://github.com/nymtech/nym/pull/4853)

- [Revert runner for `ci-docs`](https://github.com/nymtech/nym/pull/4855)

- [Remove `golang` workaround in `ci-sdk-wasm`](https://github.com/nymtech/nym/pull/4858)

- [Fix linux conditional in `ci-build.yml`](https://github.com/nymtech/nym/pull/4863)

- [Disable push trigger and add missing paths in `ci-build`](https://github.com/nymtech/nym/pull/4864)

- [chore: removed completed queued mixnet migration](https://github.com/nymtech/nym/pull/4865)

- [Bump defguard to github latest version](https://github.com/nymtech/nym/pull/4872)

- [Backport #4894 to fix ci](https://github.com/nymtech/nym/pull/4899)

### Bugfix

- [Fix test failure in ipr request size](https://github.com/nymtech/nym/pull/4844): Nightly build started failing due to a unit test using `now()`, changing the serialized size. Fixed to use a fixed date.

- [Fix clippy for nym-wallet and latest rustc](https://github.com/nymtech/nym/pull/4845)

- [Allow updating globally stored signatures](https://github.com/nymtech/nym/pull/4891)

- [Bugfix/ticketbook false double spending](https://github.com/nymtech/nym/pull/4892)
<AccordionTemplate name={<TestingSteps/>}>
Tested running a client in mixnet mode, with a standard ticketbook, as well as a client using an imported ticketbook. The double spending bug is no longer an issue, bandwidth is consumed properly, and upon consumption of one ticket another ticket is properly obtained.

### Operators Guide, Tooling & Updates

- [WSS setup guide updates](https://github.com/nymtech/nym/commit/05d6652177fb77324f8c38b3d8a547d07e729fec): Operators setting up WSS and reverse proxy on Gateways have now cleaner and simpler guide to configure their VPS.

- [Updat hostname instruction for WSS](https://github.com/nymtech/nym/commit/7146c4c012ba7012dc74edc8510bbf377dc32fba): Adding a hostname instruction for clarity

## `nym-node` patch from `release/2024.10-caramello`

- [Patch release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.10-caramello-patch)

```sh
Binary Name:        nym-node
Build Timestamp:    2024-09-16T15:00:41.019107021Z
Build Version:      1.1.7
Commit SHA:         65c8982cab0ff3a1154966e7d61956cb42a065fc
Commit Date:        2024-09-16T15:59:34.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.81.0
rustc Channel:      stable
cargo Profile:      release
```

This patch fixes [`v202410-caramello`](#v202410-caramello) release [bug](#known-bugs--undone-features) where one of the used dependencies - [`DefGuard`](https://github.com/DefGuard/defguard/issues/619), was failing.

Updating to this patched version and running `nym-node --mode exit-gateway` with `--wireguard-enabled true` should result in a smooth node start without the `defguard_wireguard` error, occuring to some operators before:
```sh
/home/ubuntu/.cargo/registry/src/index.crates.io-6f17d22bba15001f/defguard_wireguard_rs-0.4.2/src/netlink.rs:155: Serialized netlink packet (23240 bytes) larger than maximum size 12288: NetlinkMessage.
```

This release is a patch only, there are no additional features, everything else stays the same like in the latest release [`v202410-caramello`](#v202410-caramello).

## `v2024.10-caramello`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.10-caramello)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.10-caramello/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.7`

- Backport 4844 and 4845 ([#4857])
- Bugfix/client registration vol2 ([#4856])
- Remove wireguard feature flag and pass runtime enabled flag ([#4839])
- Eliminate cancel unsafe sig awaiting ([#4834])
- added explicit updateable admin to the mixnet contract ([#4822])
- using legacy signing payload in CLI and verifying both variants in contract ([#4821])
- adding ecash contract address ([#4819])
- Check profit margin of node before defaulting to hardcoded value  ([#4802])
- Sync last_seen_bandwidth immediately ([#4774])
- Feature/additional ecash nym cli utils ([#4773])
- Better storage error logging ([#4772])
- bugfix: make sure DKG parses data out of events if logs are empty ([#4764])
- Fix clippy on rustc beta toolchain ([#4746])
- Fix clippy for beta toolchain ([#4742])
- Disable testnet-manager on non-unix ([#4741])
- Don't set NYM_VPN_API to default ([#4740])
- Update publish-nym-binaries.yml ([#4739])
- Update ci-build-upload-binaries.yml ([#4738])
- Add NYM_VPN_API to network config ([#4736])
- Re-export RecipientFormattingError in nym sdk ([#4735])
- Persist wireguard peers ([#4732])
- Fix tokio error in 1.39 ([#4730])
- Feature/vesting purge plus ranged cost params ([#4716])
- Fix (some) feature unification build failures ([#4681])
- Feature Compact Ecash : The One PR ([#4623])

[#4857]: https://github.com/nymtech/nym/pull/4857
[#4856]: https://github.com/nymtech/nym/pull/4856
[#4839]: https://github.com/nymtech/nym/pull/4839
[#4834]: https://github.com/nymtech/nym/pull/4834
[#4822]: https://github.com/nymtech/nym/pull/4822
[#4821]: https://github.com/nymtech/nym/pull/4821
[#4819]: https://github.com/nymtech/nym/pull/4819
[#4802]: https://github.com/nymtech/nym/pull/4802
[#4774]: https://github.com/nymtech/nym/pull/4774
[#4773]: https://github.com/nymtech/nym/pull/4773
[#4772]: https://github.com/nymtech/nym/pull/4772
[#4764]: https://github.com/nymtech/nym/pull/4764
[#4746]: https://github.com/nymtech/nym/pull/4746
[#4742]: https://github.com/nymtech/nym/pull/4742
[#4741]: https://github.com/nymtech/nym/pull/4741
[#4740]: https://github.com/nymtech/nym/pull/4740
[#4739]: https://github.com/nymtech/nym/pull/4739
[#4738]: https://github.com/nymtech/nym/pull/4738
[#4736]: https://github.com/nymtech/nym/pull/4736
[#4735]: https://github.com/nymtech/nym/pull/4735
[#4732]: https://github.com/nymtech/nym/pull/4732
[#4730]: https://github.com/nymtech/nym/pull/4730
[#4716]: https://github.com/nymtech/nym/pull/4716
[#4681]: https://github.com/nymtech/nym/pull/4681
[#4623]: https://github.com/nymtech/nym/pull/4623

### Features

- [Add 1GB/day/user bandwidth cap](https://github.com/nymtech/nym/pull/4717)

<AccordionTemplate name={<TestingSteps/>}>
**Scenario 1: Bandwidth Decreasing Continuously**

1. Started the client and noted the initial bandwidth (e.g., 1GB).
2. Used the client and tracked bandwidth usage over time (e.g., decrease by 100MB every hour).
3. Restarted the client after some usage.
4. Verified the bandwidth continued from the last recorded value, not reset.

The bandwidth continued decreasing without resetting upon restart. Logs and reports correctly reflected the decreasing bandwidth.

**Scenario 2: Bandwidth Reset Next Day**

1. Used the client normally until the end of the day.
2. Suspended some clients and kept others active.
3. Checked bandwidth at midnight.
4. Verified that bandwidth reset to 1GB for both suspended and active clients.

Bandwidth reset to 1GB for all clients at midnight. Logs and reports correctly showed the reset.

**Scenario 3: Bandwidth Reset at a Different Time (e.g., Midday)**

1. Configured the system to reset bandwidth at midday.
2. Used the client and monitored bandwidth until midday.
3. Kept the client connected during the reset time.
4. Verified that bandwidth reset to 1GB live at midday.

Bandwidth reset to 1GB at midday while the client was connected. Logs and reports correctly reflected the reset.

**Scenario 4: Stale Check for 3 Days**

1. Kept a client inactive for 3 days.
2. Verified removal from the peer list after 3 days.
3. Reconnected the client after 3 days and checked for a new private IP.
4. Restarted a client within 3 days and verified it retained the same private IP.

The client was removed from the peer list after 3 days of inactivity. Upon re-connection after 3 days, the client received a new private IP. The client retained the same private IP when restarted within 3 days.

- [Feature/merge back](https://github.com/nymtech/nym/pull/4710): Merge back from the release branch the changes that fix the `nym-node` upgrades

- [Removed mixnode/gateway config migration code and disabled cli without explicit flag](https://github.com/nymtech/nym/pull/4706): Commands for archived / legacy binaries `nym-gateway` and `nym-mixnode` won't do anything without explicit `--force-run` to bypass the deprecation. The next step, in say a month or so, is to completely remove all `cli` related things.

<AccordionTemplate name={<TestingSteps/>}>
- Verify that the `nym-gateway` binary and `nym-mixnode` binary commands return the _error message_ stating to update to nym-node
- Check that when adding the `--force-run` flag, it still allows the command to be run (aside from `init` which has been removed) and the message stating to update to nym-node is a _warning_ now
- Check `nym-node` is not affected
- Reviewed the changes in the PR

- [Handle clients with different versions in IPR](https://github.com/nymtech/nym/pull/4723): Allow the IPR to handle clients connecting both using `v6` and `v7`, independently. The motivation is that we want to be able to roll out a API version change gradually for VPN clients without breaking backwards compatibility. The main feature on the new `v7` format that is not yet used, is that it adds signatures for connect/disconnect.

<AccordionTemplate name={<TestingSteps/>}>
Run the same command (using same gateways deployed from this PR) on different versions of the `nym-vpn-cli`.

Example:
```sh
sudo -E ./nym-vpn-cli -c ../qa.env run --entry-gateway-id $entry_gateway --exit-gateway-id $exit_gateway --enable-two-hop

sudo -E ./nym-vpn-cli -c ../qa.env run --entry-gateway-id $entry_gateway --exit-gateway-id $exit_gateway --enable-two-hop
```

- [Backport `#4844` and `#4845`](https://github.com/nymtech/nym/pull/4857)

- [Remove wireguard feature flag and pass runtime enabled flag](https://github.com/nymtech/nym/pull/4839)

- [Eliminate cancel unsafe sig awaiting](https://github.com/nymtech/nym/pull/4834)

- [Added explicit updateable admin to the mixnet contract](https://github.com/nymtech/nym/pull/4822)

- [Using legacy signing payload in CLI and verifying both variants in contract](https://github.com/nymtech/nym/pull/4821)

- [Adding ecash contract address](https://github.com/nymtech/nym/pull/4819)

- [Check profit margin of node before defaulting to hardcoded value ](https://github.com/nymtech/nym/pull/4802)

- [Sync `last_seen_bandwidth` immediately](https://github.com/nymtech/nym/pull/4774)

- [Feature/additional ecash `nym-cli` utils](https://github.com/nymtech/nym/pull/4773)

- [Better storage error logging](https://github.com/nymtech/nym/pull/4772)

- [Disable testnet-manager on non-unix](https://github.com/nymtech/nym/pull/4741)

- [Don't set NYM_VPN_API to default](https://github.com/nymtech/nym/pull/4740)

- [Update publish-nym-binaries.yml](https://github.com/nymtech/nym/pull/4739): Adds wireguard to builds

- [Update ci-build-upload-binaries.yml](https://github.com/nymtech/nym/pull/4738): Adds wireguard for ci-builds

- [Add NYM_VPN_API to network config](https://github.com/nymtech/nym/pull/4736)

- [Re-export RecipientFormattingError in nym sdk](https://github.com/nymtech/nym/pull/4735)

- [Persist wireguard peers](https://github.com/nymtech/nym/pull/4732)

- [Feature/vesting purge plus ranged cost params](https://github.com/nymtech/nym/pull/4716): Combines [\#4715](https://github.com/nymtech/nym/pull/4715) and [\#4711](https://github.com/nymtech/nym/pull/4711) into one.
    - Disables all non-essential operations on the vesting contract \=\> you can no longer bond mixnodes/make delegations/etc. (you can still, however, withdraw your vested tokens and so on)
    - Introduces admin-controlled minimum (and maximum) profit margin and interval operating costs.
    - both contracts have to be migrated **at the same time**. ideally within the same transaction
    - mixnet contract migration is not allowed (and will fail) if there are any pending actions involving vesting tokens, like delegating, increasing pledge, etc

- [Bump braces from `3.0.2` to `3.0.3` in `/nym-wallet/webdriver`](https://github.com/nymtech/nym/pull/4709): Bumps [braces](https://github.com/micromatch/braces) from `3.0.2` to `3.0.3`.

### Bugfix

- [chore: fix 1.80 lint issues](https://github.com/nymtech/nym/pull/4731)

<AccordionTemplate name={<TestingSteps/>}>
- Building all binaries is ok
- Running `cargo fmt` returns no issues

- [Fix version 1 not having template correspondent initially](https://github.com/nymtech/nym/pull/4733)

<AccordionTemplate name={<TestingSteps/>}>
Tested updating an old `nym-node` version and ensuring it did not throw any errors.

- [Bugfix/client registration vol2](https://github.com/nymtech/nym/pull/4856)

- [Fix tokio error in `1.39`](https://github.com/nymtech/nym/pull/4730):
    - Bump tokio to `1.39.2`, skipping the issue with `1.39.1`

- [Fix (some) feature unification build failures](https://github.com/nymtech/nym/pull/4681): Running a script in the root workspace that builds each crate independently

```sh
#!/bin/bash

packages=$(cargo metadata --format-version 1 --no-deps | jq -r '.packages[].name')

# Loop through each package and build
for package in $packages; do
    echo "Building $package"
    cargo clean
    cargo check -p "$package"
    if [ $? -ne 0 ]; then
        echo "Build failed for $package. Stopping."
        exit 1
    fi
done
```

- [bugfix: make sure DKG parses data out of events if logs are empty](https://github.com/nymtech/nym/pull/4764): This will be the case on post `0.50` chains

- [Fix clippy on rustc beta toolchain](https://github.com/nymtech/nym/pull/4746): Fix clippy warnings for rust beta toolchain

- [Fix clippy for beta toolchain](https://github.com/nymtech/nym/pull/4742): Fix beta toolchain clippy by removing unused module
    - Add `nym-` prefix to `serde-common` crate
    - Remove ignored `default-features = false` attribute for workspace dependency

### Crypto

- [Feature Compact Ecash : The One PR](https://github.com/nymtech/nym/pull/4623)

### Operators Guide, Tooling & Updates

- More explicit [setup for `nym-node`](nodes/nym-node/setup#initialise--run) with a new [option explanation](nodes/nym-node/setup#essential-parameters--variables), including syntax examples

- New [VPS networking configuration steps for Wireguard](nodes/nym-node/configuration#routing-configuration)

- Wireguard [builds from source](binaries/building-nym) together with `nym-node`, no need to specify with a feature flag anymore

- Wireguard peers stay connected for longer time, re-connections are also faster

- Profit margin and operating cost values are set to the values agreed by operators off-chain vote, the values can be changed in the future through [Nym Operators governance process](https://forum.nymtech.net/t/poll-proposal-for-on-chain-minimum-profit-margin-for-all-nym-nodes/253)

*Minimum profit margin = 20%* <br />
*Maximum profit margin = 50%* <br />
*Minimum operating cost = 0 NYM* <br />
*Maximum operating cost = 1000 NYM*

- [Nym Harbourmater](https://harbourmaster.nymtech.net) has several new functionalities:
    - Version counting graph for Gateways and Mixnodes
    - Several new columns with larger nodes performance and settings overview.
    - Top routing score now includes:
        - Wireguard registration and complete handshake test, to configure see [tasklist below](#operators-tasks)
        - DNS resolution check, to configure see [tasklist below](#operators-tasks)
        - Wireguard performance bigger than 0.75, to configure see [tasklist below](#operators-tasks)

- New [Nym Wallet](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.14) is out!
    - Vesting contract functionalities have been purged, users can only remove tokens from vesting
    - Migrating from `mixnode` or `gateway` smart contracts to a new unifying `nym-node` smart contract will be available soon using Nym desktop wallet, just like you are used to for bonding and node settings. After this migration all `nym-nodes` will be able to receive delegation and rewards. We will share a step by step guide once this migration will be deployed. No action needed now.

- Nym API Check CLI is upgraded according to the latest API endpoints, output is cleaner and more concise.

#### Operators Tasks

**The steps below are highly recommended for all operators and mandatory for everyone who is a part of Nym Delegation or Grant program. Deadline is Friday, September 20th, 2024.**

Every `nym-node` should be upgraded to the latest version! Operators can test using [Sandbox env](sandbox.mdx) during the pre-release period, then upgrade on mainnet. During the upgrade, please follow the points below before you restart the node:

**`nym-node`**

- Make sure to fill in basic description info, into the file located at `.nym/nym-nodes/<ID>/data/description.toml` (all nodes)
- Configure wireguard routing with new [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) following [these steps](nodes/nym-node/configuration#routing-configuration) (Gateways only for the time being)
- Enable Wireguard with `--wireguard-enabled true` flag included in your run command (Gateways only for the time being)
    - Note: On some VPS this setup may not be enough to get the correct results as some ISPs  have their own security groups setup below the individual VPS. In that case a ticket to ISP will have to be issued to open the needed settings. We are working on a template for such ticket.
- Setup [reverse proxy and WSS](nodes/nym-node/configuration/proxy-configuration) on `nym-node` (Gateways only for the time being)
- Don't forget to restart your node - or (preferably using [systemd automation](nodes/nym-node/configuration.mdx#systemd)) reload daemon and restart the service
- Optional: Use [`nym-gateway-probe`](performance-and-testing/gateway-probe) and [NymVPN CLI](https://nymtech.net/developers/nymvpn/cli.html) to test your own Gateway
- Optional: Run the script below to measure ping speed of your Gateway and share your results in [Nym Operators channel](https://matrix.to/#/#operators:nymtech.chat)

We made a script for pinging nymtech.net from your GWs. Can you please install it and then share the result together with your Gateway ID:

1. Get the script onto your machine (soon on github for curl or wget):

```sh
# paste all this block as one command
cat <<'EOL' > ping_with_curl_average_for_wg_check.sh
#!/bin/bash

ping_with_curl_average_for_wg_check() {
    total_connect_time=0
    total_total_time=0
    iterations=5
    timeout=2

    for ((i=1; i<=iterations; i++)); do
        echo "ping attempt $i..."

        echo "curling nymtech.net to check ping response times"
        times=$(curl -I https://nymtech.net --max-time $timeout \
        -w "time_connect=%{time_connect}\ntime_total=%{time_total}" -o /dev/null -s)

        time_connect=$(echo "$times" | grep "time_connect" | cut -d"=" -f2)
        time_total=$(echo "$times" | grep "time_total" | cut -d"=" -f2)

        total_connect_time=$(echo "$total_connect_time + $time_connect" | bc)
        total_total_time=$(echo "$total_total_time + $time_total" | bc)

        echo "time to connect: $time_connect s"
        echo "total time: $time_total s"
    done

    average_connect_time=$(echo "scale=3; $total_connect_time / $iterations" | bc)
    average_total_time=$(echo "scale=3; $total_total_time / $iterations" | bc)

    echo "-----------------------------------"
    echo "average time to connect: $average_connect_time s"
    echo "average total time: $average_total_time s"
}

ping_with_curl_average_for_wg_check
EOL
```

2. Make executable:

```sh
chmod +x ping_with_curl_average_for_wg_check.sh
```

3. In case you don't have `bc`, install it:

```sh
sudo apt install bc
```

4. Run:

```sh
./ping_with_curl_average_for_wg_check.sh
```

5. Share results and ID key in [Nym Operators channel](https://matrix.to/#/#operators:nymtech.chat)

THANK YOU!

**validators**

- Validators need to update and prepare for ecash implementation.

### Known Bugs & Undone features

- New `nym-nodes` without a performance 24h history above 50% don't show routing properly on `nym-gateway-probe`, on Nym Harbourmaster the page may appear blank - we are working on a fix.
- Wireguard works on IPv4 only for the time being, we are working on IPv6 implementation.
- Harbourmaster *Role* column shows `nym-node --mode exit-gateway` as `EntryGateway`, we are working to fix it.
- In rare occassions Harbourmaster shows only *"panda"* without the *"smiley"* badge even for nodes, which have T&C's accepted. We are working to fix it.
- Sometimes `nym-node` running with `--wireguard-enabled true` gives this error on restart: `Serialized netlink packet .. larger than maximum size ..`
```sh
/home/ubuntu/.cargo/registry/src/index.crates.io-6f17d22bba15001f/defguard_wireguard_rs-0.4.2/src/netlink.rs:155: Serialized netlink packet (23240 bytes) larger than maximum size 12288: NetlinkMessage.
```

From what we found out it seems that one of our [dependencies - `DefGuard` - is failing](https://github.com/DefGuard/defguard/issues/619). Based on the reading on their fix, it seems that when node operators try to re-create a wireguard interface with too many previous peers (like on Gateway restart, with restoring from storage), there's an overflow. So their fix is to just add them one by one. To be sure that bumping the dependency version fixes the problem there's still two things we'd need to check - and your feedback would help us a lot:

1. Did operators only encounter this error after a `nym-node` (Gateway) restart?
2. Reprouce this error ourselves and see if it actually fixes our problem.

**Please share your experience with us to help faster fix of this issue.**

---

## `v2024.9-topdeck`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.9-topdeck)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.9-topdeck/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.6`

- chore: fix 1.80 lint issues ([#4731])
- Handle clients with different versions in IPR ([#4723])
- Add 1GB/day/user bandwidth cap ([#4717])
- Feature/merge back ([#4710])
- removed mixnode/gateway config migration code and disabled cli without explicit flag ([#4706])

[#4731]: https://github.com/nymtech/nym/pull/4731
[#4723]: https://github.com/nymtech/nym/pull/4723
[#4717]: https://github.com/nymtech/nym/pull/4717
[#4710]: https://github.com/nymtech/nym/pull/4710
[#4706]: https://github.com/nymtech/nym/pull/4706

### Features

* [Removed `nym-mixnode` and `nym-gateway` config migration code and disabled CLI without explicit flag](https://github.com/nymtech/nym/pull/4706): Gateway and Mixnode commands now won't do anything without explicit `--force-run` to bypass the deprecation, instead it will tell an operator to run a `nym-node`.  The next step, in say a month or so, is to completely remove all `cli` related things.
<AccordionTemplate name={<TestingSteps/>}>
- Verify that the `nym-gateway` binary and `nym-mixnode` binary commands return the `_error message_` stating to *update to `nym-node`*
- Check that when adding the `--force-run` flag, it still allows the command to be run (aside from `init` which has been removed) and the message stating to update to `nym-node` is a `_warning_` now
- Check `nym-node` is not affected
- Review the changes in the PR

* [Add 1GB/day/user bandwidth cap](https://github.com/nymtech/nym/pull/4717)

<AccordionTemplate name={<TestingSteps/>}>
**Scenario 1: Bandwidth Decreasing Continuously'**

1. Start the client and noted the initial bandwidth (e.g., 1GB).
2. Us the client and track bandwidth usage over time (e.g., decrease by 100MB every hour).
3. Restart the client after some usage.
4. Verify the bandwidth continued from the last recorded value, not reset.

**Notes:**
 The bandwidth continued decreasing without resetting upon restart. Logs and reports correctly reflected the decreasing bandwidth.

**Scenario 2: Bandwidth Reset Next Day'**

1. Use the client normally until the end of the day.
2. Suspend some clients and kept others active.
3. Check bandwidth at midnight.
4. Verify that bandwidth reset to 1GB for both suspended and active clients.

**Notes:**
Bandwidth reset to 1GB for all clients at midnight. Logs and reports correctly showed the reset.

**Scenario 3: Bandwidth Reset at a Different Time (e.g., Midday)'**

1. Configure the system to reset bandwidth at midday.
2. Use the client and monitored bandwidth until midday.
3. Keep the client connected during the reset time.
4. Verify that bandwidth reset to 1GB live at midday.

**Notes:**
Bandwidth reset to 1GB at midday while the client was connected. Logs and reports correctly reflected the reset.

* [Handle clients with different versions in IPR](https://github.com/nymtech/nym/pull/4723): Allow the IPR to handle clients connecting both using `v6` and `v7`, independently. The motivation is that we want to be able to roll out an API version change gradually for NymVPN clients without breaking backwards compatibility. The main feature on the new `v7` format that is not yet used, is that it adds signatures for connect/disconnect.
<AccordionTemplate name={<TestingSteps/>}>
Run the same command (using same gateways deployed from this PR) on different versions of the `nym-vpn-cli`.

Example:
```sh
sudo -E ./nym-vpn-cli -c ../qa.env run --entry-gateway-id $entry_gateway --exit-gateway-id $exit_gateway --enable-two-hop

sudo -E ./nym-vpn-cli -c ../qa.env run --entry-gateway-id $entry_gateway --exit-gateway-id $exit_gateway --enable-two-hop
```

### Bugfix

* [Feature/merge back](https://github.com/nymtech/nym/pull/4710): Merge back from the release branch the changes that fix the `nym-node` upgrades.

* [Fix version `1.x.x` not having template correspondent initially](https://github.com/nymtech/nym/pull/4733): This should fix the problem of config deserialisation when operators upgrade nodes and skip over multiple versions.
<AccordionTemplate name={<TestingSteps/>}>
- Tested updating an old nym-node version and ensuring it did not throw any errors.

* [chore: fix 1.80 lint issues](https://github.com/nymtech/nym/pull/4731):
<AccordionTemplate name={<TestingSteps/>}>
- Building all binaries is ok
- Running `cargo fmt` returns no issues

### Operators Guide updates

* [WireGuard tunnel configuration guide](nodes/nym-node/configuration#routing-configuration) for `nym-node` (currently Gateways functionalities). For simplicity we made a detailed step by step guide to upgrade an existing `nym-node` to the latest version and configure your VPS routing for WireGuard. Open by clicking on the example block below.

**Prerequisites**

- **Nym Node Version:** You must be running the `2024.9-topdeck` release branch, which operates as `nym-node` version `1.1.6`. You can find the release here: [Nym 2024.9-topdeck Release](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.9-topdeck).

- **Important:** Before proceeding, make sure to [back up](nodes/maintenance.md#backup-a-node) your current `nym-node` configuration to avoid any potential data loss or issues.

- **Download Nym Node:**
- You can download the `nym-node` binary directly using the following command:
```bash
curl -L https://github.com/nymtech/nym/releases/download/nym-binaries-v2024.9-topdeck/nym-node -o nym-node && chmod u+x nym-node
```

**Step 1: Update UFW Firewall Rules**

- **Warning:** Enabling the firewall with UFW without allowing SSH port 22 first will lead to losing access over SSH. Make sure port 22 is allowed before proceeding with any UFW configurations.

Run the following as root or with `sudo` prefix:

1. Check the current status of UFW (Uncomplicated Firewall):
```bash
ufw status
```

2. Ensure that the following ports are allowed on your machine before adding the WireGuard port:

```bash
ufw allow 22/tcp    # SSH - you're in control of these ports
ufw allow 80/tcp    # HTTP
ufw allow 443/tcp   # HTTPS
ufw allow 1789/tcp  # Nym specific
ufw allow 1790/tcp  # Nym specific
ufw allow 8080/tcp  # Nym specific - nym-node-api
ufw allow 9000/tcp  # Nym Specific - clients port
ufw allow 9001/tcp  # Nym specific - wss port
ufw allow 51822/udp # WireGuard
```

3. Confirm that the UFW rules have been updated:
```bash
ufw status
```

**Step 2: Download and Prepare the Network Tunnel Manager Script**

1. Download the [`network_tunnel_manager.sh`](https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh) script:
```bash
curl -L -o network_tunnel_manager.sh https://github.com/nymtech/nym/blob/develop/scripts/network_tunnel_manager.sh
```

2. Make the script executable:
```bash
chmod u+x network_tunnel_manager.sh
```

3. Apply the WireGuard IPTables rules:
```bash
./network_tunnel_manager.sh apply_iptables_rules_wg
```

**Step 3: Update the Nym Node Service File**

1. Modify your [`nym-node` service file](nodes/nym-node/configuration#systemd) to enable WireGuard. Open the file (usually located at `/etc/systemd/system/nym-node.service`) and update the `[Service]` section as follows:

```ini
[Service]
User=<YOUR_USER_NAME>
Type=simple
#Environment=RUST_LOG=debug
# CAHNGE PATH IF YOU DON'T RUN IT FROM ROOT HOME DIRECTORY
ExecStart=/root/nym-node run --mode exit-gateway --id <YOUR_NODE_LOCAL_ID> --accept-operator-terms-and-conditions --wireguard-enabled true
Restart=on-failure
RestartSec=30
StartLimitInterval=350
StartLimitBurst=10
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

# ADD OR TWEAK ANY CUSTOM SETTINGS
```

2. Reload the systemd daemon to apply the changes:
```bash
systemctl daemon-reload
```

3. Restart the `nym-node service`:
```bash
systemctl restart nym-node.service
```

4. Optionally, you can check if the node is running correctly by monitoring the service logs:
```bash
journalctl -u nym-node.service -f -n 100
```

**Step 4: Run the Network Tunnel Manager Script**

Finally, run the following command to initiate our favorite routing test - run the joke through the WireGuard tunnel:
```bash
./network_tunnel_manager.sh joke_through_wg_tunnel
```

- **Note:** Wireguard will return only IPv4 joke, not IPv6. WG IPv6 is under development. Running IPR joke through the mixnet with `./network_tunnel_manager.sh joke_through_the_mixnet` should work with both IPv4 and IPv6!

* [Change `--wireguard-enabled` flag to `true`](nodes/nym-node/setup#initialise--run): With a proper [routing configuration](nodes/nym-node/configuration#routing-configuration) `nym-nodes` running as Gateways can now enable WG. See the example below:

For Exit Gateway:
```sh
./nym-node run --id <ID> --mode exit-gateway --public-ips "$(curl -4 https://ifconfig.me)" --hostname <HOSTNAME> --http-bind-address 0.0.0.0:8080 --mixnet-bind-address 0.0.0.0:1789 --location <LOCATION> --accept-operator-terms-and-conditions --wireguard-enabled true

# wireguard can be enabled from version 1.1.6 onwards
```

For Entry Gateway:
```sh
./nym-node run --id <ID> --mode entry-gateway --public-ips "$(curl -4 https://ifconfig.me)" --hostname <HOSTNAME> --http-bind-address 0.0.0.0:8080 --mixnet-bind-address 0.0.0.0:1789 --accept-operator-terms-and-conditions --wireguard-enabled true

# wireguard can be enabled from version 1.1.6 onwards
```

* [Update Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt): Based on the survey, AMA and following discussions we added several ports to Nym exit policy. The ports voted upon in the [forum governance](https://forum.nymtech.net/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464) have not been added yet due to the concerns raised. These ports were unrestricted:

```
22 # SSH
123 # NTP
445 # SMB file share Windows
587 # SMTP
853 # DNS over TLS
1433 # databases
1521 # databases
2049 # NFS
3074 # Xbox Live
3306 # databases
5000-5005 # RTP / VoIP
5432 # databases
6543 # databases
8080 # HTTP Proxies
8767 # TeamSpeak
8883 # Secure MQ Telemetry Transport - MQTT over SSL
9053 # Tari
9339 # gaming
9443 # alternative HTTPS
9735 # Lightning
25565 # Minecraft
27000-27050 # Steam and game servers
60000-61000 # MOSH
```

* [Create a NymConnect archive page](https://nymtech.net/developers/archive/nym-connect.html), PR [\#4750](https://github.com/nymtech/nym/commit/5096c1e60e203dcf8be934823946e24fda16a9a3): Archive deprecated NymConnect for backward compatibility, show PEApps examples for both NC and maintained `nym-socks5-client`.

* Fix broken URLs and correct redirection. PRs: [\#4745](https://github.com/nymtech/nym/commit/7e36595d8fa7706876880b42df1c998a4b8c1478), [\#4752](https://github.com/nymtech/nym/commit/1db61f800c6884e284c5ab21e7abce3bc6d91d99) [\#4755](https://github.com/nymtech/nym/commit/aaf3dca5b999ad7f19d2ff170078b43c9c4476c2), [\#4737](https://github.com/nymtech/nym/commit/6f669866e92e637772726ad05caa5c5501a830f3)
<AccordionTemplate name={<TestingSteps/>}>
- Use [deadlinkchecker.com](https://www.deadlinkchecker.com/website-dead-link-checker.asp) to go over `nymtech.net` and correct all docs URLs
- Go over search engines and old medium articles and check that all dead URLs re-directing correctly

* [Clarify syntax on `nym-nodes` ports on VPS setup page](https://nymtech.net/operators/nodes/vps-setup.html#configure-your-firewall), PR [\#4734](https://github.com/nymtech/nym/commit/5e6417f83788f30b2a84e4dd73d6dd9619a2bb16): Make crystal clear that the addresses and ports in operators `config.toml` must be opened using [`ufw`](https://nymtech.net/operators/nodes/vps-setup.html#configure-your-firewall) and set up as in the example below:

```toml
[host]
public_ips = [
'<PUBLIC_IP>'
]

[mixnet]
bind_address = '0.0.0.0:1789'

[http]
bind_address = '0.0.0.0:8080'

[mixnode]
[mixnode.verloc]
bind_address = '0.0.0.0:1790'

[entry_gateway]
bind_address = '0.0.0.0:9000'
```

### Tooling

* [Nym Harbourmaster](https://harbourmaster.nymtech.net/) has now several new functionalities:
    - Tab for Mixnodes
    - Tab with Charts
    - New columns with: *Moniker (node description)*, *DP delegatee*, *Accepted T&Cs* - also part of a new category 🐼😀

* Nym has a new [Token page](https://nymtech.net/about/token)

---

## `v2024.8-wispa`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.8-wispa)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.8-wispa/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.5`

- add event parsing to support cosmos_sdk to 0.50 ([#4697])
- Fix NR config compatibility ([#4690])
- Remove UserAgent constructor since it's weakly typed ([#4689])
- [bugfix]: Node_api_check CLI looked over roles on blacklisted nodes ([#4687])
- Add mixnodes to self describing api cache ([#4684])
- Move and whole bump of crates to workspace and upgrade some ([#4680])
- Remove code that refers to removed nym-network-statistics ([#4679])
- Remove nym-network-statistics ([#4678])
- Create UserAgent that can be passed from the binary to the nym api client ([#4677])
- Add authenticator ([#4667])

[#4697]: https://github.com/nymtech/nym/pull/4697
[#4690]: https://github.com/nymtech/nym/pull/4690
[#4689]: https://github.com/nymtech/nym/pull/4689
[#4687]: https://github.com/nymtech/nym/pull/4687
[#4684]: https://github.com/nymtech/nym/pull/4684
[#4680]: https://github.com/nymtech/nym/pull/4680
[#4679]: https://github.com/nymtech/nym/pull/4679
[#4678]: https://github.com/nymtech/nym/pull/4678
[#4677]: https://github.com/nymtech/nym/pull/4677
[#4667]: https://github.com/nymtech/nym/pull/4667

### Features

* [Default construct NodeRole](https://github.com/nymtech/nym/pull/4721): To preserve compatibility with newer clients interacting with older `nym-api`
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes in the `nym-api-requests/src/models.rs` file.
2. Verified that the `NymNodeDescription` struct includes the new `role` field with a default value set by `default_node_role`.
3. Checked the implementation of the `default_node_role` function to ensure it returns `NodeRole::Inactive`.
4. Ran the updated code in the sandbox environment.
5. Monitored the sandbox environment for any issues or errors related to the changes.

**Notes (if any):**

The test was successful. No issues were flagged during the testing in the sandbox environment. The new default value for `NodeRole` ensures backward compatibility without causing disruptions.

* [Default construct NodeRole for backwards compatibility (apply [\#4721](https://github.com/nymtech/nym/pull/4721) on develop)](https://github.com/nymtech/nym/pull/4722)
* [Add upgrades to `nym-node` for `authenticator` changes](https://github.com/nymtech/nym/pull/4703)
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes in the `gateway/src/error.rs` and `gateway/src/node/mod.rs` files.
2. Verified the new error enum `AuthenticatorStartupFailure` was added to `GatewayError`.
3. Confirmed the implementation of the `StartedAuthenticator` struct and its usage in the `start_authenticator` function.
4. Ran the updated code in the canary environment.
5. Monitored the canary environment for any issues or errors related to the changes.

* [Add event parsing to support `cosmos_sdk` to `0.50`](https://github.com/nymtech/nym/pull/4697)
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes in `common/client-libs/validator-client/src/nyxd/cosmwasm_client/client_traits/signing_client.rs`, `logs.rs`, `types.rs`, and `nym-api/src/coconut/tests/mod.rs` files.
2. Verified the addition of event parsing in the relevant functions and structs.
3. Ensured that the `find_attribute` function correctly parses event attributes.
4. Ran the updated code in the sandbox environment.
5. Broadcasted transactions on the sandbox network to test the changes.
6. Monitored the sandbox network for any malformed responses or errors after the test chain upgrade.

* [Send bandwidth status messages when connecting](https://github.com/nymtech/nym/pull/4691): When connecting to the gateway we get received the available bandwidth left. Emit a status messages for this, for consumption by the application layer.
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes in `common/bandwidth-controller/src/event.rs`, `common/bandwidth-controller/src/lib.rs`, and `common/client-libs/gateway-client/src/client.rs` files.
2. Verified the implementation of `BandwidthStatusMessage` enum for emitting status messages.
3. Ensured `GatewayClient` is updated to send bandwidth status messages when connecting.
4. Deployed the updated code on the canary environment.
5. Connected to the gateway and checked for the emission of bandwidth status messages.
6. Verified that the messages were correctly parsed and consumed by the application layer.
7. Ran the VPN client to observe the parsed events.

* [Fix NR config compatibility](https://github.com/nymtech/nym/pull/4690): Recently we deleted the old statistics service provider. This fixes some issues where old configs didn't work with the latest changes.
    - Make NR able to read config with old keys in
    - Remove deleted config keys from NR template
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes in the `service-providers/network-requester/src/config/mod.rs` and `service-providers/network-requester/src/config/template.rs` files.
2. Ensured `NetworkRequester` config is able to read old keys for compatibility.
3. Removed old and deleted config keys from the `NetworkRequester` template.
4. Compiled the project to verify no issues or warnings appeared.
5. Ran all tests to ensure that the changes did not affect the functionality.
6. Validated that no leftover code from the old statistics service provider caused any issues.

* [Remove `UserAgent` constructor since it's weakly typed](https://github.com/nymtech/nym/pull/4689):
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes in `common/http-api-client/src/user_agent.rs` file.
2. Verified the removal of the `UserAgent` constructor and ensured that all instances of `UserAgent::new` are updated accordingly.
3. Checked the implementation of `UserAgent` struct using `BinaryBuildInformation` and `BinaryBuildInformationOwned`.
4. Deployed the updated code across different environments (QA, sandbox, and canary).
5. Ran tests to ensure that the `UserAgent` struct functions correctly without the constructor.

* [Add mixnodes to self describing api cache](https://github.com/nymtech/nym/pull/4684):
    - Abstracts getting the self describing info a bit
    - Adds mixnodes to the cache refresher as well
    - Adds `role` field to the `NodeDescription` struct, to be able to distinguish between mixnodes and gateways
    - Switched to using `NodeStatusCache` instead of `ContractCache`
<AccordionTemplate name={<TestingSteps/>}>
Called the new `/mixnodes/described` endpoint as well as the existing `/gateways/described` endpoint and verified that the data returned for each was correct based on the settings that different nodes have when they are setup.

For gateway endpoint, the “role” for now does not differentiate between entry and exit gateways, this will be implemented in the future.

* [Move and whole bump of crates to workspace and upgrade some](https://github.com/nymtech/nym/pull/4680):
    - Fix cargo warning for `default_features`
    - Move dirs 4.0 to workspace
    - Use workspace `base64` dep
    - Move `rand_chacha` and `x25519-dalek` to workspace
    - Use workspace `ed25519-dalek` dep
    - Move `itertools` to workspace deps and upgrade
    - Move a few partial deps to workspace  while preserving versions
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the changes to move and upgrade crates to the workspace.
2. Verified the updated dependencies:
   - Moved `dirs` to version 4.0 in the workspace.
   - Updated the `base64` dependency to use the workspace version.
   - Moved `rand_chacha` and `x25519-dalek` to the workspace.
   - Updated `ed25519-dalek` to use the workspace version.
   - Moved and upgraded `itertools` in the workspace.
   - Moved other partial dependencies to the workspace while preserving their versions.
3. Ensured the `Cargo.toml` files across the project reflect these changes correctly.
4. Compiled the entire project to check for any issues or warnings.
5. Verified that all tests pass successfully after the changes.

* [Remove `nym-network-statistics`](https://github.com/nymtech/nym/pull/4678): Remove `nym-network-statistics` service provider that is no longer used.
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the project to identify all references to `nym-network-statistics`.
2. Removed all code and dependencies associated with `nym-network-statistics`.
3. Ensured that no references to `nym-network-statistics` remain in the codebase, including comments, imports, and configuration files.
4. Compiled the project to check for any issues or warnings.
5. Ran all tests to ensure the removal did not affect the functionality of the project.

* [Remove code that refers to removed `nym-network-statistics`](https://github.com/nymtech/nym/pull/4679): Follow up to [\#4678](https://github.com/nymtech/nym/pull/4678) where all code interacting with it is removed.
<AccordionTemplate name={<TestingSteps/>}>
1. Reviewed the project to identify all references to `nym-network-statistics`.
2. Removed all code and dependencies associated with `nym-network-statistics`.
3. Ensured that no references to `nym-network-statistics` remain in the codebase, including comments, imports, and configuration files.
4. Compiled the project to check for any issues or warnings.
5. Ran all tests to ensure the removal did not affect the functionality of the project.

* [Create `UserAgent` that can be passed from the binary to the `nym-api` client](https://github.com/nymtech/nym/pull/4677):
    - Support setting `UserAgent` for the validator client
    - Support setting `UserAgent` in the SDK `MixnetClient`
    - Set `UserAgent` when getting the list of gateways and topology in
         - `nym-client`
         - `nym-socks5-client`
         - Standalone `ip-packet-router`

<AccordionTemplate name={<TestingSteps/>}>
Used the nym-vpn-cli to test this, and we can visibly see the `UserAgent`, no issues with the comments mentioned above.

Example of the user agent sent:
`nym-client/1.1.36/x86_64-unknown-linux-gnu/e18bb70`

Connected with no problems

* [Add `authenticator`](https://github.com/nymtech/nym/pull/4667)

### Bugfix

* [`Node_api_check.py` CLI looked over roles on blacklisted nodes](https://github.com/nymtech/nym/pull/4687): Removing/correcting this redundant function which results in unwanted error print, will resolve in the program not looking up the `roles` endpoint for blacklisted GWs, instead just ignores the role description and still return all other endpoints.

### Operators Guide updates

* [Create a guide to backup and restore `nym-node`](https://nymtech.net/operators/nodes/maintenance.html#backup-a-node), PR [\#4720](https://github.com/nymtech/nym/pull/4720)
* [Add manual IPv6 ifup/down network configuration](https://nymtech.net/operators/troubleshooting/vps-isp.html#network-configuration), PR [\#4651](https://github.com/nymtech/nym/pull/4651)
* [Extend ISP list](https://nymtech.net/operators/legal/isp-list.html)
* [Add SSL cert bot block to WSS setup](https://nymtech.net/operators/nodes/proxy-configuration.html#web-secure-socket-setup), [PR here](https://github.com/nymtech/nym/commits/develop/): WSS setup fully works!
* [Correct `HTTP API port` in bonding page](https://nymtech.net/operators/nodes/bonding.html#bond-via-the-desktop-wallet-recommended) , [PR \#4707](https://github.com/nymtech/nym/pull/4707): Change `HTTP API port` to `8080` on every `nym-node` by opening `config.toml` and making sure that your binding addresses and ports are as in the block below. Then go to desktop wallet and open the box called `Show advanced options` and make sure all your ports are set correctly (usually this means to change `HTTP api port` to `8080` for `mixnode` mode).

```toml
[host]
public_ips = [
'<PUBLIC_IP>'
]

[mixnet]
bind_address = '0.0.0.0:1789'

[http]
bind_address = '0.0.0.0:8080'

[mixnode]
[mixnode.verloc]
bind_address = '0.0.0.0:1790'

[entry_gateway]
bind_address = '0.0.0.0:9000'
```

* [Comment our deprecated node pages in `/docs`](https://github.com/nymtech/nym/pull/4727)
    - Fixes [issue \#4632](https://github.com/nymtech/nym/issues/4632)
* [Remove redundant syntax from the setup guide](https://github.com/nymtech/nym/pull/4682)

---

## `v2024.7-doubledecker`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.7-doubledecker)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.7-doubledecker/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.4`

- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
- Bump braces from 3.0.2 to 3.0.3 in /wasm/mix-fetch/internal-dev ([#4672])
- add expiry returned on import ([#4670])
- [bugfix] missing rustls feature ([#4666])
- Bump ws from 8.13.0 to 8.17.1 in /wasm/client/internal-dev-node ([#4665])
- Bump braces from 3.0.2 to 3.0.3 in /clients/native/examples/js-examples/websocket ([#4663])
- Bump ws from 8.14.2 to 8.17.1 in /sdk/typescript/packages/nodejs-client ([#4662])
- Update setup.md ([#4661])
- New clippy lints ([#4660])
- Bump braces from 3.0.2 to 3.0.3 in /nym-api/tests ([#4659])
- Bump braces from 3.0.2 to 3.0.3 in /docker/typescript_client/upload_contract ([#4658])
- Update vps-setup.md ([#4656])
- Update configuration.md ([#4655])
- Remove old PR template ([#4639])

[#4686]: https://github.com/nymtech/nym/pull/4686
[#4672]: https://github.com/nymtech/nym/pull/4672
[#4670]: https://github.com/nymtech/nym/pull/4670
[#4666]: https://github.com/nymtech/nym/pull/4666
[#4665]: https://github.com/nymtech/nym/pull/4665
[#4663]: https://github.com/nymtech/nym/pull/4663
[#4662]: https://github.com/nymtech/nym/pull/4662
[#4661]: https://github.com/nymtech/nym/pull/4661
[#4660]: https://github.com/nymtech/nym/pull/4660
[#4659]: https://github.com/nymtech/nym/pull/4659
[#4658]: https://github.com/nymtech/nym/pull/4658
[#4656]: https://github.com/nymtech/nym/pull/4656
[#4655]: https://github.com/nymtech/nym/pull/4655
[#4639]: https://github.com/nymtech/nym/pull/4639

### Features

- [Remove the `nym-mixnode` and `nym-gateway` binaries from the CI upload builds action](https://github.com/nymtech/nym/pull/4693)
- [Add an early return in `parse_raw_str_logs` for empty raw log strings.](https://github.com/nymtech/nym/pull/4686): This accommodates for the v50 + chain upgrade.
- [Bump braces from `3.0.2` to `3.0.3` in `/wasm/mix-fetch/internal-dev`](https://github.com/nymtech/nym/pull/4672): Version update of [braces](https://github.com/micromatch/braces)
- [Bump braces from `3.0.2` to `3.0.3` in `/clients/native/examples/js-examples/websocket`](https://github.com/nymtech/nym/pull/4663): Version update of [braces](https://github.com/micromatch/braces).
- [Bump braces from `3.0.2` to `3.0.3` in `/nym-api/tests`](https://github.com/nymtech/nym/pull/4659): Version update of [braces](https://github.com/micromatch/braces).
- [Bump braces from `3.0.2` to `3.0.3` in `/docker/typescript_client/upload_contract`](https://github.com/nymtech/nym/pull/4658): Version update of  [braces](https://github.com/micromatch/braces).
- [Bump `ws` from `8.13.0` to `8.17.1` in `/wasm/client/internal-dev-node`](https://github.com/nymtech/nym/pull/4665): Version update of [`ws`](https://github.com/websockets/ws).
- [Bump `ws` from `8.14.2` to `8.17.1` in `/sdk/typescript/packages/nodejs-client`](https://github.com/nymtech/nym/pull/4662): Version update of [`ws`](https://github.com/websockets/ws).
- [Add expiry returned on import](https://github.com/nymtech/nym/pull/4670): We need to return the expiry on import for desktop daemon `nym-vpnd`.
- [New clippy lints](https://github.com/nymtech/nym/pull/4660)
- [Remove `nym-connect` directory](https://github.com/nymtech/nym/pull/4643): Since the `nym-vpn` has superseded `nym-connect`, remove `nym-connect` from the repo.
- [Remove old PR template](https://github.com/nymtech/nym/pull/4639)

### Bugfix

- [missing rustls feature](https://github.com/nymtech/nym/pull/4666): It just happens to work due to `feature-unification`. It should probably have this feature inbuild.

### Operators Guide updates

- [Node description guide](nodes/nym-node/configuration#node-description): Steps to add self-description to `nym-node` and query this information from any node.
- [Web Secure Socket (WSS) guide and reverse proxy update](nodes/nym-node/configuration/proxy-configuration), PR [here](https://github.com/nymtech/nym/pull/4694): A guide to setup `nym-node` in a secure fashion, using WSS via Nginx and Certbot. Landing page (reversed proxy) is updated and simplified.

---

## `v2024.6-chomp`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.6-chomp)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.6-chomp/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.3`
- Standalone `nym-gateway` and `nym-mixnode` binaries are no longer released

- Remove additional code as part of Ephemera Purge and SP and contracts ([#4650])
- bugfix: make sure nym-api can handle non-cw2 (or without detailed build info) compliant contracts ([#4648])
- introduced a flag to accept toc and exposed it via self-described API ([#4647])
- bugfix: make sure to return an error on invalid public ip ([#4646])
- Add ci check for PR having an assigned milestone ([#4644])
- Removed ephemera code ([#4642])
- Remove stale peers ([#4640])
- Add generic wg private network routing ([#4636])
- Feature/new node endpoints ([#4635])
- standarised ContractBuildInformation and added it to all contracts ([#4631])
- validate nym-node public ips on startup ([#4630])
- Bump defguard wg ([#4625])
- Fix cargo warnings ([#4624])
- Update kernel peers on peer modification ([#4622])
- Handle v6 and v7 requests in the IPR, but reply with v6 ([#4620])
- fix typo ([#4619])
- Update crypto and rand crates ([#4607])
- Purge name service and service provider directory contracts ([#4603])

[#4650]: https://github.com/nymtech/nym/pull/4650
[#4648]: https://github.com/nymtech/nym/pull/4648
[#4647]: https://github.com/nymtech/nym/pull/4647
[#4646]: https://github.com/nymtech/nym/pull/4646
[#4644]: https://github.com/nymtech/nym/pull/4644
[#4642]: https://github.com/nymtech/nym/pull/4642
[#4640]: https://github.com/nymtech/nym/pull/4640
[#4636]: https://github.com/nymtech/nym/pull/4636
[#4635]: https://github.com/nymtech/nym/pull/4635
[#4631]: https://github.com/nymtech/nym/pull/4631
[#4630]: https://github.com/nymtech/nym/pull/4630
[#4625]: https://github.com/nymtech/nym/pull/4625
[#4624]: https://github.com/nymtech/nym/pull/4624
[#4622]: https://github.com/nymtech/nym/pull/4622
[#4620]: https://github.com/nymtech/nym/pull/4620
[#4619]: https://github.com/nymtech/nym/pull/4619
[#4607]: https://github.com/nymtech/nym/pull/4607
[#4603]: https://github.com/nymtech/nym/pull/4603

### Features

- [Make embedded NR/IPR ignore performance of the Gateway](https://github.com/nymtech/nym/pull/4671): fixes bug in relation to scoring issue on nym-nodes operating as exit gateways failing to come online.
- [Introduce a flag to accept Operators Terms and Conditions and exposed it via self-described API](https://github.com/nymtech/nym/pull/4647)
<AccordionTemplate name={<TestingSteps/>}>
- Verify that the `execute` function correctly checks if the `accept_operator_terms` flag is set.
- Test that a warning is displayed when the `accept_operator_terms` flag is not set.
- Confirm that the `NymNode` instance is initialized with `with_accepted_toc(accepted_toc)` when the flag is set.
- Apply the `--accept-toc` flag in the service and confirmed the change by running:
```sh
curl -s -X 'GET' 'http://18.171.251.41:8080/api/v1/auxiliary-details?output=json' -H 'accept: application/json' | jq .accepted_toc
```
- Verify that the output is `true`.

- [Rename 'accept-toc' flag and fields into explicit 'accept-operator-terms-and-conditions'](https://github.com/nymtech/nym/pull/4654): makes the `accept-toc` flag more explicit.
- [Validate nym-node public ips on startup](https://github.com/nymtech/nym/pull/4630): makes sure `nym-node` is not run with an empty `public_ips` and that they do not correspond to common misconfigurations like `127.0.0.1` or `0.0.0.0` unless run with `--local` flag.
<AccordionTemplate name={<TestingSteps/>}>
- Use the latest release/chomp binary with nym-node and input a dodgy ip

- Validation:

When restarting the node it complains within the service launch file

- [New node endpoints](https://github.com/nymtech/nym/pull/4635): introduces new endpoints on nym-api (and creates scaffolding for additional ones) for providing **unfiltered** network topology alongside performance score of all nodes.
    - `NymApiTopologyProvider` got modified to use those endpoints alongside (configurable) filtering of nodes with score \< 50% (like our current blacklist)
    - Old clients should work as before as no existing endpoint got removed
<AccordionTemplate name={<TestingSteps/>}>
- Validate that the `skimmed` endpoints are working, keeping in mind that they are unstable. The *full-fat* and *semi-skimmed* have not yet been implemented.

- [Remove stale peers](https://github.com/nymtech/nym/pull/4640)
- [Removed ephemera code](https://github.com/nymtech/nym/pull/4642)
<AccordionTemplate name={<TestingSteps/>}>
- Check references to everything named SP and Ephemera and removed any additional references

- [Remove additional code as part of Ephemera Purge and SP and contracts](https://github.com/nymtech/nym/pull/4650): in line with [#4642](https://github.com/nymtech/nym/pull/4642) and [#4603](https://github.com/nymtech/nym/pull/4603)
<AccordionTemplate name={<TestingSteps/>}>
- Check references to everything named SP and Ephemera and removed any additional references

- [Add ci check for PR having an assigned milestone](https://github.com/nymtech/nym/pull/4644): add a CI check for checking that a PR is assigned to a milestone. Can bypassed the check by adding a `no-milestone` label to a PR
<AccordionTemplate name={<TestingSteps/>}>
- CI complains if no milestone is associated with the an issue.

- [Bump defguard wireguard](https://github.com/nymtech/nym/pull/4625)
- [Add generic wireguard private network routing](https://github.com/nymtech/nym/pull/4636): as defguard wireguard only allows for peer routing modifications, we will configure the entire wireguard private network to be routed to the wg device. Configuring per peer is also not desirable, as the interface doesn't allow removing routes, so unused ip routing won't be cleaned until gateway restart (and it would also pollute to routing table with a lot of rules when many peers are added).
<AccordionTemplate name={<TestingSteps/>}>
- This is a part of a bigger ticket, but initial testing has proven to shown that launching nym-nodes (entry and exit gateways) in WG enable mode to be working

*QA will use this template for the other related WG tickets in this release milestone.*

- [Standarise `ContractBuildInformation` and add it to all contracts](https://github.com/nymtech/nym/pull/4631): Similarly to `cw2`, we're now saving `ContractBuildInformation` under a constant storage key, i.e. `b"contract_build_info"` that standarises the retrieval by nym-api.
    - Also each of our contracts now saves and updates that information upon init and migration.
<AccordionTemplate name={<TestingSteps/>}>
- Use the latest release/chomp contracts and deploy these to QA
- Use the `nym-api` to query for the results of these new contracts

```sh
 curl -X 'GET' \
   'https://qa-nym-api.qa.nymte.ch/api/v1/network/nym-contracts-detailed' \
   -H 'accept: application/json'
```

- It returns a detailed view of the contracts and which branch they were built from, alongside rust versions and so forth.

- [Update kernel peers on peer modification](https://github.com/nymtech/nym/pull/4622):
<AccordionTemplate name={<TestingSteps/>}>
- This is a part of a bigger ticket, but initial testing has proven to shown that launching nym-nodes (entry and exit gateways) in WG enable mode to be working.
*QA will use this template for the other related WG tickets in this release milestone.*

- [Handle v6 and v7 requests in the IPR, but reply with v6](https://github.com/nymtech/nym/pull/4620): teach the IPR to read both v6 and v7 requests, but always reply with v6. This is to prepare for bumping to v7 and signed connect/disconnect messages. Follow up PRs will add
    - Verify signature
    - Send v7 in client with signatures included
- [Purge name service and service provider directory contracts](https://github.com/nymtech/nym/pull/4603): this is a compiler assisted purge of the `nym-name-service` and `nym-service-provider-directory` contracts that were never deployed on mainnet, and will anyhow be superseded by the new mixnode directory that is being worked on.
<AccordionTemplate name={<TestingSteps/>}>
It works insofar that it compiles, we need to deploy and test this on non-mainnet before merging in

- Purge `nym-name-service` contract
- Purge `nym-name-service-common`
- Purge `nym-service-provider-directory` contract
- Purge `nym-service-provider-directory-common`
- Remove everywhere name-service contract is used
- Remove everywhere sp contract is used

Performed:
- Check references to everything named SP and Ephemera and removed any additional references

### Crypto

- [Update crypto and rand crates](https://github.com/nymtech/nym/pull/4607): Update sphinx crate to `0.1.1` along with 25519 crates and `rand` crates
<AccordionTemplate name={<TestingSteps/>}>
This PR contains a test failure due to the update [here](https://github.com/nymtech/nym/blob/b4a0487a41375167b2f481c00917b957b9f89789/common/crypto/src/asymmetric/encryption/mod.rs#L353-L358)

- This is due a change in `x25519-dalek` from `1.1.1` to `2`.
- Crypto operations should be identical, but the byte representation has changed (sphinx clamps at creation, x25519 clamps at use). This cannot be changed in the sphinx crate without breaking changes.
- There is a good chance that this failure doesn't impact anything else, but it has to be tested to see.
- A mix of old and new clients with a mix of old and new mixnodes should do

### Bugfix
- [Make sure nym-api can handle non-cw2 (or without detailed build info) compliant contracts](https://github.com/nymtech/nym/pull/4648): fixes the issue (even if some contracts aren't uploaded on chain it doesn't prohibit the api from working - caveat, the essential vesting and mixnet contract are required)
<AccordionTemplate name={<TestingSteps/>}>
- Use the latest release/chomp contracts and deploy these to QA
- If the contract was not found, the API would complain of invalid contracts, thus not starting the rest of the operations of the API (network monitor / rewarding etc)

 `Jun 11 16:27:34 qa-v2-nym-api bash[1352642]:  2024-06-11T16:27:34.551Z ERROR nym_api::nym_contract_cache::cache::refresher - Failed to refresh validator cache - Abci query failed with code 6 - address n14y2x8a60knc5jjfeztt84kw8x8l5pwdgnqg256v0p9v4p7t2q6eswxyusw: no such contract: unknown request`

- [Make sure to return an error on `nym-node` invalid public ip](https://github.com/nymtech/nym/pull/4646): bugfix for [#4630](https://github.com/nymtech/nym/pull/4630) that interestingly hasn't been detected by clippy.
<AccordionTemplate name={<TestingSteps/>}>
- Use the latest release/chomp binary with nym-node and input a dodgy ip

- Validation:

- [Extend the return error when connecting to gateway fails](https://github.com/nymtech/nym/pull/4626)
<AccordionTemplate name={<TestingSteps/>}>
- Verify that the `establish_connection` function correctly attempts to establish a connection to the gateway.
- Test error handling for `NetworkConnectionFailed` by simulating a failed connection.
- Ensure that the `NetworkConnectionFailed` error includes the `address` and `source` details as expected.
- Checked that `SocketState::Available` is set correctly when a connection is successfully established.

- [Fix Cargo warnings](https://github.com/nymtech/nym/pull/4624): On every cargo command we have the set warnings:

warning: /home/alice/src/nym/nym/common/dkg/Cargo.toml: `default-features` is ignored for bls12_381, since `default-features` was not specified for `workspace.dependencies.bls12_381`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/dkg/Cargo.toml: `default-features` is ignored for ff, since `default-features` was not specified for `workspace.dependencies.ff`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/dkg/Cargo.toml: `default-features` is ignored for group, since `default-features` was not specified for `workspace.dependencies.group`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/client-libs/validator-client/Cargo.toml: `default-features` is ignored for bip32, since `default-features` was not specified for `workspace.dependencies.bip32`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/client-libs/validator-client/Cargo.toml: `default-features` is ignored for prost, since `default-features` was not specified for `workspace.dependencies.prost`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/credentials-interface/Cargo.toml: `default-features` is ignored for bls12_381, since `default-features` was not specified for `workspace.dependencies.bls12_381`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/credentials/Cargo.toml: `default-features` is ignored for bls12_381, since `default-features` was not specified for `workspace.dependencies.bls12_381`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/nymcoconut/Cargo.toml: `default-features` is ignored for bls12_381, since `default-features` was not specified for `workspace.dependencies.bls12_381`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/nymcoconut/Cargo.toml: `default-features` is ignored for ff, since `default-features` was not specified for `workspace.dependencies.ff`, this could become a hard error in the future warning: /home/alice/src/nym/nym/common/nymcoconut/Cargo.toml: `default-features` is ignored for group, since `default-features` was not specified for `workspace.dependencies.group`, this could become a hard error in the future.

    - This PR adds `default-features = false` to the workspace dependencies to fix these. An alternative way would be to remove `default-features = false` in the crates, but we assume these were put there for a good reason. Also we might have other crates outside of the main workspace that depends on these crates having default features disabled.
    - We also have the warning `warning: profile package spec nym-wasm-sdk in profile release did not match any packages`  which we fix by commenting out the profile settings, since the crate is currently commented out in the workspace crate list.
<AccordionTemplate name={<TestingSteps/>}>
- All binaries have been built and deployed from this branch and no issues have surfaced.

### Operators Guide updates

- [New Release Cycle](release-cycle) introduced: a transparent release flow, including:
    - New environments
    - Stable testnet
    - [Testnet token faucet](https://nymtech.net/operators/sandbox.html#sandbox-token-faucet)
    - Flow [chart](release-cycle#release-flow)
- [Sandbox testnet](sandbox) guide: teaching Nym node operators how to run their nodes in Nym Sandbox testnet environment.
- [Terms & Conditions flag](nodes/nym-node/setup#terms--conditions)
- Node API Check CLI
- [Pruning VPS `syslog` scripts](troubleshooting/vps-isp#pruning-logs)
- [Black-xit: Exiting the blacklist](troubleshooting/nodes#my-gateway-is-blacklisted)

---

## `v2024.5-ragusa`

- [Release binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.5-ragusa)
- [Release CHANGELOG.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.5-ragusa/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.2`

- Feature/nym node api location ([#4605])
- Add optional signature to IPR request/response ([#4604])
- Feature/unstable tested nodes endpoint ([#4601])
- nym-api: make report/avg_uptime endpoints ignore blacklist ([#4599])
- removed blocking for coconut in the final epoch state ([#4598])
- allow using explicit admin address for issuing freepasses ([#4595])
- Use rfc3339 for last_polled in described nym-api endpoint ([#4591])
- Explicitly handle constraint unique violation when importing credential ([#4588])
- [bugfix] noop flag for nym-api for nymvisor compatibility ([#4586])
- Chore/additional helpers ([#4585])
- Feature/wasm coconut ([#4584])
- upgraded axum and related deps to the most recent version ([#4573])
- Feature/nyxd scraper pruning ([#4564])
- Run cargo autoinherit on the main workspace ([#4553])
- Add rustls-tls to reqwest in validator-client ([#4552])
- Feature/rewarder voucher issuance ([#4548])

[#4605]: https://github.com/nymtech/nym/pull/4605
[#4604]: https://github.com/nymtech/nym/pull/4604
[#4601]: https://github.com/nymtech/nym/pull/4601
[#4599]: https://github.com/nymtech/nym/pull/4599
[#4598]: https://github.com/nymtech/nym/pull/4598
[#4595]: https://github.com/nymtech/nym/pull/4595
[#4591]: https://github.com/nymtech/nym/pull/4591
[#4588]: https://github.com/nymtech/nym/pull/4588
[#4586]: https://github.com/nymtech/nym/pull/4586
[#4585]: https://github.com/nymtech/nym/pull/4585
[#4584]: https://github.com/nymtech/nym/pull/4584
[#4573]: https://github.com/nymtech/nym/pull/4573
[#4564]: https://github.com/nymtech/nym/pull/4564
[#4553]: https://github.com/nymtech/nym/pull/4553
[#4552]: https://github.com/nymtech/nym/pull/4552
[#4548]: https://github.com/nymtech/nym/pull/4548

### Features

- New `nym-node` API endpoint `/api/v1/auxiliary-details`: to expose any additional information. Currently it's just the location. `nym-api` will then query all nodes for that information and put it in the `self-described` endpoint.
- New `nym-node` location available - use one of the three options to add this to your node config:
    1. Update the `location` field under `[host]` section of `config.toml`
    2. For new nodes: Initialise the node with `--location` flag, where they have to provide the country info. Either full country name (e.g. 'Jamaica'), two-letter alpha2 (e.g. 'JM'), three-letter alpha3 (e.g. 'JAM') or three-digit numeric-3 (e.g. '388') can be provided.
    3. For existing nodes: It's also possible to use exactly the same `--location` argument as above, but make sure to also provide `--write-changes` (or `-w`) flag to persist those changes!
- [Feature/unstable tested nodes endpoint](https://github.com/nymtech/nym/pull/4601): Adds new data structures (`TestNode`, `TestRoute`, `PartialTestResult`) to handle test results for Mixnodes and Gateways. With the inclusion of pagination to handle large API responses efficiently. Lastly, introducing a new route with the tag `unstable` thus meaning not to be consumed without a user risk, prefixes in endpoints with unstable, are what it says on the tin.
<AccordionTemplate name={<TestingSteps/>}>
- Deploy new api changes to sandbox environment
- Ensure current operations are transactional and standed operations are working
- Run a script to ensure that the new endpoints are working as expected with pagination

- [`nym-api`: make report/avg_uptime endpoints ignore blacklist](https://github.com/nymtech/nym/pull/4599): When querying for node specific data, it's no longer going to go through the entire list of all cached (and filtered nodes) to find it; instead it will attempt to retrieve a single unfiltered entry.
<AccordionTemplate name={<TestingSteps/>}>
- Build the project and deployed it in a test environment.
- Manually test API endpoints for mixnode and gateway data.
- Verify that the endpoints return the expected data and handle blacklists correctly.
- API performance improved due to the efficient `HashMap` lookups
- Data in mainnet will differ from test nets due to the increased amount of gateways and mixnodes in that environment
- Test standard uptime routes:
```sh
curl -X 'GET' 'https://validator.nymtech.net/api/v1/status/gateway/Fo4f4SQLdoyoGkFae5TpVhRVoXCF8UiypLVGtGjujVPf/avg_uptime' -H 'accept: application/json'
```

- [Use rfc3339 for last_polled in described nym-api endpoint](https://github.com/nymtech/nym/pull/4591): Fix issue where the validator-client can't parse the nym-api response for the described endpoint, in particular the `latest_polled` field that was recently added, by making the field use `rfc3339`
    - **Note:** This will require upgrading `nym-api` and everything that depends on the described endpoint.
<AccordionTemplate name={<TestingSteps/>}>
- Update a `nym-api` to the binary built from this branch, then restart the api
- Check the `journalctl` for error messages
- Connected via client and could not see the error messages, this is backwards compatible
- Local testing using sdk examples:
```sh
cd <PATH_TO>/nym/sdk/rust/nym-sdk
cargo run --example simple

# outcome
thread 'main' panicked at sdk/rust/nym-sdk/examples/simple.rs:9:64:
called Result::unwrap() on an Err value: ClientCoreError(ValidatorClientError(NymAPIError { source: ReqwestClientError { source: reqwest::Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None,
```

- [Upgrade `axum` and related dependencies to the most recent version](https://github.com/nymtech/nym/pull/4573)
- [Run cargo autoinherit on the main workspace](https://github.com/nymtech/nym/pull/4553): Move several dependencies to the workspace level using cargo autoinherit, to make it easier to keep our dependencies up to date.
    - Run cargo autoinherit in the root
    - Merge in the new workspace deps in the main list
    - We made sure to not mix in other changes as well - all features flags for all crates should be the same as before
<AccordionTemplate name={<TestingSteps/>}>
- Run `cargo autoinherit` in the root directory to move dependencies to the workspace level
- Merge the new workspace dependencies into the main list
- Ensure no other changes were mixed in during the process
- Verify that all feature flags for all crates remained the same as before
- Build all the binaries from this branch to confirm successful compilation
- Deploy the built binaries across different environments to ensure there were no issues

- [Add rustls-tls to reqwest in validator-client](https://github.com/nymtech/nym/pull/4552): An attempt to make possible to end up in a situation where use use the validator-client but without functioning TLS support. For the monorepo this is masked by cargo feature unification, but becomes a problem for outside consumers, as as been noticed in many of the vpn client implementations.
    - In `validator-client`: `reqwest`, enable `rustls-tls` for `non-wasm32`
    - In `client-core`: Use default features enabled for `non-wasm32` and switch to `webpki` roots, since that's what we're using with `reqwest` anyway
    - In `gateway-client`: Switch to `webpki` roots, since that's what we're using with `reqwest` anyway

#### Crypto

- [Remove blocking for coconut in the final epoch state](https://github.com/nymtech/nym/pull/4598)
<AccordionTemplate name={<TestingSteps/>}>
- Build the project to ensure no compilation errors
- Run tests to verify the functionality of the `issue_credential` function
- Execute integration tests to check the behaviour during an epoch transition.

- [Allow using explicit admin address for issuing freepasses](https://github.com/nymtech/nym/pull/4595)
- [Explicitly handle constraint unique violation when importing credential](https://github.com/nymtech/nym/pull/4588): Add a strong type for when a duplicate credential is imported so the vpn lib can handle this.
- [Feature/wasm coconut](https://github.com/nymtech/nym/pull/4584): This pull request requires [\#4585](https://github.com/nymtech/nym/pull/4585) to be merged first
- [Feature/nyxd scraper pruning](https://github.com/nymtech/nym/pull/4564): This PR introduces storage pruning to `nyxd` scraper which is then used by the validators rewarder.
<AccordionTemplate name={<TestingSteps/>}>
- Add a `main.rs` file in the `nyxd` scraper dir, underneath `lib.rs`, amend `config.pruning_options.validate()?;` to be `let _ = config.pruning_options.validate();` in the mod.rs file
- Test the different variations of `pruning_options`:
    - Check the *default* option: `pruning_options: PruningOptions::default()`
    - Check the *nothing* option: `pruning_options: PruningOptions::nothing()`
    - Check the *custom* option, example: `pruning_options: PruningOptions { keep_recent: (500), interval: (10), strategy: (PruningStrategy::Custom) }`
    - Check the pruning *in real life* for the validator rewarder
- Validate that the database table `blocks` was being updated accordingly

- [Feature/rewarder voucher issuance](https://github.com/nymtech/nym/pull/4548)
    - Introduces signature checks on issued credential data
    - Stores evidence of any failures/malicious behaviour in the internal db

### Bugfix

- [`noop` flag for `nym-api` for `nymvisor` compatibility](https://github.com/nymtech/nym/pull/4586)
    - The application starts correctly and logs the starting message
    - The `--no_banner` flag works as intended, providing compatibility with `nymvisor`
<AccordionTemplate name={<TestingSteps/>}>
- Build the project to ensure no compilation errors
- Run the binary with different command-line arguments to verify the CLI functionality
- Test with and without the `--no_banner` flag to ensure compatibility and expected behavior
- Verify logging setup and configuration file parsing

### Operators Guide updates

- [`nym-gateway-probe`](performance-and-testing/gateway-probe): A CLI tool to check in-real-time networking status of any Gateway locally.
- [Where to host your `nym-node`?](community-counsel/isp-list): A list of Internet Service Providers (ISPs) by Nym Operators community. We invite all operators to add their experiences with different ISPs to strengthen the community knowledge and Nym mixnet performance.
- Make sure you run `nym-node` with `--wireguard-enabled false` and add a location description to your `config.toml`, both documented in [`nym-node` setup manual](nodes/nym-node/setup#mode-exit-gateway).

---

## `v2024.4-nutella`

- [Merged PRs](https://github.com/nymtech/nym/milestone/59?closed=1)
- [`nym-node`](nodes/nym-node.mdx) version `1.1.1`
- This release also contains: `nym-gateway` and `nym-network-requester` binaries
- core improvements on nym-node configuration
- Nym wallet changes:
    - Adding `nym-node` command to bonding screens
    - Fixed the delegation issues with fixing RPC
- [Network configuration](nodes/nym-node/configuration#connectivity-test-and-configuration) section updates, in particular for `--mode mixnode` operators
- [VPS IPv6 troubleshooting](troubleshooting/vps-isp#ipv6-troubleshooting) updates

---

## `v2024.3-eclipse`

- Release [Changelog.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md)
- [`nym-node`](nodes/nym-node.mdx) initial release
- New tool for monitoring Gateways performance [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net)
- New versioning `1.1.0+nymnode` mainly for internal migration testing, not essential for operational use. We aim to correct this in a future release to ensure mixnodes feature correctly in the main API
- New [VPS specs & configuration](nodes/preliminary-steps/vps-setup) page
- New [configuration page](nodes/nym-node/configuration) with [connectivity setup guide](nodes/nym-node/configuration#connectivity-test-and-configuration) - a new requirement for `exit-gateway`
- API endpoints redirection: Nym-mixnode and nym-gateway endpoints will eventually be deprecated; due to this, their endpoints will be redirected to new routes once the `nym-node` has been migrated and is running

**API endpoints redirection**

| Previous endpoint              | New endpoint                             |
| ---                            | ---                                      |
| `http://<IP>:8000/stats`       | `http://<IP>:8000/api/v1/metrics/mixing` |
| `http://<IP>:8000/hardware`    | `http://<IP>:8000/api/v1/system-info`    |
| `http://<IP>:8000/description` | `http://<IP>:8000/api/v1/description`    |

</ AccordionTemplate>

---
title: Release Cycle
url: https://nym.com/docs/operators/release-cycle
---

# Release Cycle

Nym operator community is growing in quality and quantity. With node operators and developers joining the effort to make the Mixnet more robust and scalable, testing new features, sharing integration pull requests and generally taking an active part in Nym development, more transparency on the release cycle is required.

The core team therefore established a flow with different environments:

- ***local***: Developers use their local environments for feature building
- ***canary***: Nym internal testing environment managed by Qualtiy Assurance team (QA)
- [***sandbox***](sandbox.mdx): Public testnet, including testnet NYM token available in the [faucet](sandbox.mdx#sandbox-token-faucet)
- ***mainnet***: Nym Mixnet - the production version of Nym network

## Release Flow

Frequency of releases to mainnet is aimed to be every ~14 days. This time window is an optimal compromise between periodicity and quality assurance/testing, key factors playing an essential role in development.

| **Stage**                                 | **Environment** | **Branch**                 | **Ownership** |
| :--                                       | :--             | :--                        | :--           |
| development work                          | local/canary    | feature branches           | devs          |
| cut and test release                      | canary          | release branch             | QA            |
| bug fixing                                | canary          | directly on release branch | QA & devs     |
| put release on sandbox                    | sandbox         | release -> master/develop  | QA            |
| promote release to mainnet after 3-5 days | mainnet         | master                     | QA            |

```ascii
                   ▲                          ▲
                   │                          │
                   │  merge back into develop │
      MAINNET      ├─────────────────────────►│
      easy         │                          │
      autopromotion│                          │
      ▲            │                          │
      │            │                          │
      │            │                          │◄───────────────────────────────┐
      │            │                          │                                │
      └───release  │                          │                                │
          to       x◄───────────────┐         │                                │
          sandbox  ▲                │         │◄────────────────────────┐      │
                   │   ┌────────────►         │                         │      │
                   │   │            │         │                         │      │
                   │   │ bug        │         │                         │      │
                   │   │ fix        │         │◄─────────────────┐      │      │
                   │   │            │         │                  │      │      │
                   │   │            │         │ M                │      │      │
                   │   └────────────┤         │ I                │      │      │
                   │                │         │ L                │      │      │
                   │                └─────────x E                │      │      │
                   │                  release ▲ S                │      │      │
       ^           │                  cut     │ T                │      │      │
       :           │                  ---     │ O                │      │      │
       :           │                  fixed   │ N                │      │      │
       :           │                  release │ E                │      │      │
       :           │                  every   │     feature-bob3 │      │      │
       :           │                  14 days ├──────────────────┘      │      │
       :           │                          │                         │      │
       :           │                          │                         │      │
       :           │                          │     feature-bob2        │      │
       :           │                          ├─────────────────────────┘      │
       :           │                          │                                │
       :           │                          │                                │
       :           │                          │     feature-bob1               │
       :           │                          ├────────────────────────────────┘
       :           │                          │
       :           │                          │
       :t          │                          │
       :i          │                          │
       :m          │                          │
       :e          │                          │

                master                     develop             feature branches

ENVs
┌─────────┬────────┬──────────────────────────┬─────────────────────────────────┐
│mainnet  │sandbox │ QA / canary              │ development                     │
│         │        │                          │                                 │
└─────────┴────────┴──────────────────────────┴─────────────────────────────────┘
```

### Changes & Collaboration

To track changes easily, builders and operators can visit one of the following:

- [*CHANGELOG.md*](https://github.com/nymtech/nym/blob/master/CHANGELOG.md): Raw changelog of merged feauters in Nym's monorepo, managed by devs and QA.
- [*Changelog page*](changelog.mdx): A detailed explanation, testing steps and updated summary of documentation changes, managed by devrels.

In case you want to propose changes or resolve some of the existing [issues](https://github.com/nymtech/nym/issues), start [here](https://github.com/nymtech/nym/issues/new/choose). If you want to add content to the Operators Guide, visit [this page](community-counsel/add-content.mdx).

Feature tickets need explicit (while concise) wording because that title is eventually added to the changelog. Keep in mind that bad ticket naming results in bad changelog.

If you want to run in the testing environment, follow our [Sandbox testnet](sandbox.mdx) guide.

---
title: Essential Parameters & Variables
url: https://nym.com/docs/operators/variables
---

# Essential Parameters & Variables

Our documentation often refer to syntax annotated in `<>` brackets. We use this expression for variables that are unique to each user (like path, local moniker, versions etcetra). Any syntax in `<>` brackets needs to be substituted with your correct name or version, without the `<>` brackets.

Below is a table listing the most essential variables and parameters which they may come along with, together with description and syntax example.  It should help operators and developers to familiarise themselves with the convention of parameters and variables we use across the documentation.

To prevent over-flooding of our documentation we cannot provide with every single command syntax as there is a large combination of possibilities. Remember that you can always print the options using a `--help` flag together with any binary command.

---
title: Nym Sandbox Testnet for Node Operators
description: Run your Nym node in the Sandbox testnet environment. Test configurations, try new features, and experiment safely before deploying to mainnet.
url: https://nym.com/docs/operators/sandbox
---

# Sandbox Testnet

Nym node operators can run their nodes in Nym Sandbox testnet environment. Whether it's testing new configuration, hot features from Nym developers or just trying to setup a node for the first time, this environment is for you.

Below are steps to [setup your environment](#sandbox-environment-setup) and an introduction to [Sandbox token faucet](#sandbox-token-faucet).

This page is for Nym node operators. If you want to run NymVPN CLI over Sandbox testnet, visit [NymVPN CLI Testnet guide](https://nym-vpn-cli.sandbox.nymtech.net/).

## Sandbox Environment Setup

<VarInfo/ >

To run Nym binaries in Sandbox testnet, you need to get `sandbox.env` configuration file and point your binary to it. Follow the steps below:

###### 1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your binaries:
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
- In case you want to save the file elsewhere, change the path in '-o' flag

###### 2. Run your `nym-node` with an additional flag `-c` or `--config-env-file`
- Specify a path to `sandbox.env`
- Add all needed commands and options - for example:

<Tabs items={[<code>mixnode</code>, <code>exit-gateway</code>]}>

  This example is for `nym-node --mode mixnode`.
  ```sh
  ./nym-node --config-env-file <PATH>/sandbox.env run --mode mixnode
  ```

  This example is for `nym-node --mode exit-gateway`.
  ```sh
  ./nym-node --config-file-env <PATH>/sandbox.env run --mode exit-gateway --id <ID> --public-ips "$(curl -4 https://ifconfig.me)" --hostname "<HOSTNAME>" --http-bind-address 0.0.0.0:8080 --mixnet-bind-address 0.0.0.0:1789 true --location <CLOCATION>
  ```

- In case you downloaded `sandbox.env` to same directory, `<PATH>` is not needed

###### 3. Bond your node to Nym Sandbox environment
- Open [Nym Wallet](https://nym.com/wallet) and switch to testnet
- Go to [faucet.nymtech.net](https://faucet.nymtech.net) and aquire 101 testnet NYM tokens
- Follow the steps on the [bonding page](nodes/nym-node/bonding.mdx)

![](/images/operators/sandbox.png)

1. If you [built Nym from source](binaries/building-nym), you already have `sandbox.env` as a part of the monorepo (`nym/envs/sandbox.env`). Giving that you are likely to run `nym-node` from `nym/target/release`, the flag will look like this `--config-env-file ../../envs/sandbox.env`

2. You can export the path to `sandbox.env` to your environmental variables:
```sh
export NYMNODE_CONFIG_ENV_FILE_ARG=<PATH>/sandbox.env
```

## Sandbox Token Faucet

To run your nodes in Sandbox environment, you need testnet version of NYM token, that can be aquired from [faucet.nymtech.net](https://faucet.nymtech.net).

To prevent abuse, the faucet is rate-limited - your request will fail if the requesting wallet already has 101 NYM tokens.

---
title: Pre-built Binaries
url: https://nym.com/docs/operators/binaries/pre-built-binaries
---

# Pre-built Binaries

This page is for operators who prefer to download ready made binaries. The [Github releases page](https://github.com/nymtech/nym/releases) has pre-built binaries which should work on Ubuntu 22.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

If the pre-built binaries don't work or are unavailable for your system, you will need to build the platform yourself.

**[Nym release binaries](https://github.com/nymtech/nym/releases) no longer work on distributions based on Debian bullseye/sid (11) like Ubuntu 20.04 LTS and older! Please upgrade your sever to Debian bookworm (Debian 12) or Ubuntu 22.04 (and newer)!** Alternatively [compile the binaries from source](building-nym.mdx).

## Setup Binaries

1. ###### Download binary
- Go to [Nym release page](https://github.com/nymtech/nym/releases/), choose binary to download, click with a right button and `Copy Link...`
- Download from your terminal using `curl` or `wget` tool:
```sh
# using curl
curl -L <LINK> -o <PATH>

# using wget
wget <LINK>
```
In case you want to download binary to your current working directory, drop `<PATH>` from the command

###### 2. Verify the binary `sha256sum` hash

  <Tabs items={[
    <strong>Manual check</strong>,
    <strong>One-liner</strong>,
    ]} defaultIndex="0">

To see your binary `sha256sum` hash, run:
```sh
sha256sum <BINARY>
```
```sh
# for example
# sha256sum ./nym-wallet_1.2.15_amd64.AppImage
# or
# sha256sum ./nym-node
```
- Download [`hashes.json`](https://github.com/nymtech/nym/releases) file from the same same *Assets* drop down like your binary
- Open it with your text editor or print its content with `cat hashes.json`
- Check it if your binary `sha256sum` output is in `hashes.json` by using the `sha256sum` and searching for it or using `grep` command:
```
grep -i <SHA_HASH>
```

- Download [`hashes.json`](https://github.com/nymtech/nym/releases) file from the same same *Assets* drop down like your binary
- Run this command, substituting `<BINARY>` with your the one you want to check:
```sh
sha256sum <BINARY> | awk '{print $1}' | grep -qF "$(jq -r '.assets | to_entries | .[].value.sha256' hashes.json)" && echo "Hash matches an asset in the JSON file." || echo "Hash does not match any asset in the JSON file."
```
```sh
# for example
# sha256sum ./nym-node | awk '{print $1}' | grep -qF "$(jq -r '.assets | to_entries | .[].value.sha256' hashes.json)" && echo "Hash matches an asset in the JSON file." || echo "Hash does not match any asset in the JSON file."
```

- If your have to extract the binary (it would look like like `<BINARY>.tar.gz`) do it:
```sh
tar -xvzf <BINARY>.tar.gz
```

###### 3. Make the binary executable
- Open terminal in the same directory and run:
```sh
chmod u+x <BINARY>
# for example: chmod u+x nym-node
```

Now you can use your binary. Follow the guide according to the type of your binary.

* [Nym Nodes](../nodes/nym-node.mdx)
* [Validators](../nodes/validator-setup.mdx)

You can reconfigure your binaries at any time by editing the config file located at `~/.nym/<BINARY_TYPE>/<ID>/config/config.toml` and restarting the binary process.

`<ID>` represents a local moniker that is **never** transmitted over the network. It's used to select which local config and key files (stored in `./nym`) to use for startup.

---
title: Building Nym from Source: Linux, macOS & Windows
description: How to build Nym platform binaries from source code. Covers dependencies for Debian, Arch, macOS, and Windows. Requires Rust toolchain and Git.
url: https://nym.com/docs/operators/binaries/building-nym
---

# Building from Source

> Nym runs on Mac OS X, Linux, and Windows. All nodes **except the Desktop Wallet and NymConnect** on Windows should be considered experimental - it works fine if you're an app developer but isn't recommended for running nodes.

## Building Nym

Nym has two main codebases:

- the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code _except_ for the validators.
- the [Nym validators](https://github.com/nymtech/nyxd), written in Go.

> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator-setup) instead.**

## Prerequisites

- Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git`

```sh
apt install pkg-config build-essential libssl-dev curl jq git
```

- Arch/Manjaro: `base-devel`

```sh
pacman -S base-devel
```

- Mac OS X: `pkg-config` , `brew`, `openss1`, `protobuf`, `curl`, `git`
Running the following the script installs Homebrew and the above dependencies:

```sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

- `Rust & cargo >= 1.80`

We recommend using the [Rust shell script installer](https://www.rust-lang.org/tools/install). Installing cargo from your package manager (e.g. `apt`) is not recommended as the packaged versions are usually too old.

If you really don't want to use the shell script installer, the [Rust installation docs](https://forge.rust-lang.org/infra/other-installation-methods.html) contain instructions for many platforms.

## Download and Build Nym Binaries

You cannot build from GitHub's .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn't a Git repository). Check the code out from github using `git clone` instead.

The following commands will compile binaries into the `nym/target/release` directory:

```sh
rustup update
git clone https://github.com/nymtech/nym.git
cd nym

git reset --hard # in case you made any changes on your branch
git pull # in case you've checked it out before

git checkout master # master branch has the latest release version: `develop` will most likely be incompatible with deployed public networks

cargo build --release # build your binaries with **mainnet** configuration
```

Quite a bit of stuff gets built. The key working parts are:

* [Nym Node](../nodes/nym-node): `nym-node`
* [Validator](../nodes/validator-setup.mdx)
* [websocket client](../../developers/clients/websocket): `nym-client`
* [socks5 client](../../developers/clients/socks5): `nym-socks5-client`
* [webassembly client](../../developers/clients/webassembly-client): `webassembly-client`
* [nym-cli tool](../../developers/tools/nym-cli): `nym-cli`
* [nym-api](../nodes/validator-setup/nym-api.mdx): `nym-api`
* [nymvisor](../nodes/maintenance/nymvisor-upgrade.mdx): `nymvisor`

{/*
The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages.
* [Nym Wallet](https://nym.com/docs/wallet/desktop-wallet.html)
* [Network Explorer UI](https://nymtech.net/docs/explorers/mixnet-explorer.html)
*/}

---
title: How to Set Up & Run a Nym Node on the Mixnet
description: Step-by-step guide to installing, configuring, and running a nym-node on the Nym mixnet. Covers prerequisites, staking requirements, and CLI setup.
url: https://nym.com/docs/operators/nodes
---

# Nym Nodes Operator Guides

Welcome to the section containing setup guides for operators of Nym Nodes and Nym Validators. To setup, configure, run, bond and maintain a `nym-node` is not a difficult process, but it takes dedication. Before you start, please check out [minimum requirements](#minimum-requirements) and then follow the [Steps for Nym Node Operators](#steps-for-nym-node-operators) below.

## Minimum Requirements

Operating a `nym-node` is not a set-and-forget endeavor. To prevent operators committing their time and money into a sub-optimal server, resulting in frustration of never seeing their node active, we composed this list of prerequisites. Please read below about expectations regarding operators [skill set](#knowledge-base), [time dedication](#time), [minimum hardware specs](#vps-hardware-specs) and [Nym Wallet](nodes/preliminary-steps/wallet-preparation) with at least 101 NYM tokens.

### Knowledge base

**All nodes are run remotely from operators shell, using [SSH](https://www.ssh.com/academy/ssh) and [Bash](https://www.gnu.org/software/bash/) commands. Node operators need to be experienced super users or sys-admins.** If you never used terminal before, maybe start with some tutorial of [basic Linux administration](https://www.linode.com/docs/guides/linux-system-administration-basics/) before committing to run a node.

### Nym Wallet

To [register (bond)](nodes/nym-node/bonding) `nym-node` to the network, you need a Nyx blockchain account and at least 101 NYM tokens. Follow the steps on [this page](nodes/preliminary-steps/wallet-preparation).

### Time

Last but not least, managing a Nym Node is work. More skilled an operator is, less time it takes to run and maintain a node (and search extra details), but just like any other work, it takes effort.

Reserve 45-120 minutes for the initial setup and configuration (depends on your skills). Then count on a few minutes once in 2-4 weeks to upgrade node version binaries. Patches don't always come out [regularly](release-cycle.mdx), operators need to keep their eyes on [Matrix announcement channel](https://matrix.to/#/#node-ops-announcements:nymtech.chat).

Outdated nodes are never selected for routing/mixing packets, resulting in not receiving any rewards. You can read more on our [Tokenomics page](tokenomics/mixnet-rewards.mdx) to understand the selection and rewards logic.

Accepting T&Cs is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. Detailed info and proper syntax is provided on the [setup page](nodes/nym-node/setup#terms--conditions).

## Steps for Nym Node Operators

This is a summary of all needed steps for node operators to setup and configure a `nym-node` and register it to Nym Network:

1. **Start with [Preliminary Steps](nodes/preliminary-steps.mdx), preparing [VPS](nodes/preliminary-steps/vps-setup.mdx) and [Nym wallet](nodes/preliminary-steps/wallet-preparation)**

2. **[Setup](nodes/nym-node/setup.mdx) the node**

3. **[Configure](nodes/nym-node/configuration.mdx) the node and (optionally) automation, Wireguard, WSS, reverse proxy ...**

4. **[Run](nodes/nym-node/setup.mdx#initialise--run) the node or [the service](nodes/nym-node/configuration.md#systemd)**

5. **[Bond](nodes/nym-node/bonding.mdx) the node to the Nym API, using Nym wallet**

Make sure to follow the steps thoroughly, in case you find any point difficult don't hesitate to ask in our [Operators channel](https://matrix.to/#/#operators:nymtech.chat).

---
title: Preliminary Steps
url: https://nym.com/docs/operators/nodes/preliminary-steps
---

# Preliminary Steps

> The `nym-node` binary was built in the [building nym](../binaries/building-nym) section. If you haven't yet built Nym and want to run the code, go there first.

There are a couple of steps that need completing before starting to set up your `nym-node`:

1. **[Prepare your wallet](preliminary-steps/wallet-preparation.mdx):** [desktop](https://nym.com/wallet) or [CLI](../../developers/tools/nym-cli/commands.mdx).
2. **[Requisition and setup a VPS](preliminary-steps/vps-setup.mdx)** (Virtual Private Server)

Make sure to follow these steps carefully as it prevents a lot of troubleshooting later on.

---
title: Nym Wallet Preparation
url: https://nym.com/docs/operators/nodes/preliminary-steps/wallet-preparation
---

# Nym Wallet Preparation

## Mainnet

Head to our [website](https://nym.com/wallet) and download Nym wallet for your operating system.

{/*

If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nym.com/docs/wallet/desktop-wallet.html).
*/}

If you don't already have one, please create a Nym address using the wallet, and fund it with NYM tokens. The minimum amount required to bond a node is 100 `NYM`, but make sure you have a bit more to account for gas costs.

`NYM` can be swapped in these places:

- [SpectreDAO Swap](https://explorer.nym.spectredao.net/swap) (1000+ tokens supported)
- [Binance bridge](https://bridge.nym.com/)
- [ERC20 bridge](https://swapper.nym.com/swap) - follow [this guide](https://nym.com/blog/nym-for-nym-swapper-app-bridges-native-and-erc20-token)

`NYM` can be also bought on several [exchanges](https://www.coingecko.com/en/coins/nym#markets).

> Remember that you can **only** use Cosmos `NYM` tokens to bond your node. You **cannot** use ERC20 representations of `NYM` to run a node.

## Sandbox testnet

Make sure to download a wallet and create an account as outlined above. Then head to our [Sandbox Testnet page](../../sandbox.mdx#sandbox-token-faucet) and request testnet NYM tokens.

---
title: VPS Setup & Configuration
url: https://nym.com/docs/operators/nodes/preliminary-steps/vps-setup
---

# VPS Setup & Configuration

We aim for Nym Network to be reliable and quality base layer of privacy accross the globe, while growing as distributed as possible. It's essential to have a fine tuned machine as a foundation for the nodes to meet the requirements and be rewarded for their work.

A sub-optimally configured VPS often results in a non-functional node. To follow these steps carefully will save you time and money later on.

## Full node configuration (validator)

To install a full node from scratch, refer to the [validator setup guide](../validator-setup.mdx) and follow the steps outlined there.

## VPS Configuration

Before node or validator setup, the VPS needs to be configured and tested, to verify your connectivity and make sure that your provider wasn't dishonest with the offered services.

The commands listed in this chapter must be executed with a prefix `sudo` or from a root shell.

### Install Dependencies & Configure Firewall

SSH to your server as `root` or become one running `sudo -i` or `su`. If you prefer to administrate your VPS from a user environment, supply the commands with prefix `sudo`.

###### 1. Start with setting up the essential tools on your server.

- Get your system up to date
```sh
apt update -y && apt --fix-broken install
```
- Install dependencies
```sh
apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git ntp ntpdate
```
- Double check ufw is installed correctly
```sh
apt install ufw --fix-missing
```

###### 2. Synchronize time of your server

###### 3. Configure your firewall

For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on the server.

  <Tabs items={[
    <code>nym-node</code>,
    <code>validator</code>,
    ]} defaultIndex="0">
    <MyTab><TabsPortsNymNode/></MyTab>
    <MyTab><PortsValidator/></MyTab>

For more information about your node's port configuration, check the [port reference table](#ports-reference-table) below.

## Setting `ulimit`

Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`.

`ulimit` is 1024 by default on most systems. It needs to be set higher, because Nym Nodes make and receive a lot of connections with each others.

If you see errors such as:

```sh
Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" }
```

This means that the operating system is preventing network connections from being made.

### Set the `ulimit` via `systemd` service file

The ulimit setup is relevant for maintenance of Nym Node only.

###### 1. Query the `ulimit` with:

- For 'nym-node`:
```sh
grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-node | grep -v grep |head -n 1 | awk '{print $1}')/limits
```
- For nyx validator
```sh
grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nymd | grep -v grep |head -n 1 | awk '{print $1}')/limits
```

You'll get back the hard and soft limits, which looks something like this:

```sh
Max open files            65536                65536                files
```

If your output is **the same as above**, your node will *not* encounter any `ulimit` related issues.

###### 2. If either value is `1024`, you must raise the limit

- We recommend doing it via the `systemd` service file. Following the steps in [this guide](../nym-node/configuration.mdx#systemd).
- You will see there a line setting new `ulimit` threshold.
```sh
LimitNOFILE=65536
```

###### 3. Alternatively you can execute this command for system-wide setting of `ulimit`:

```sh
echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf
```
- Then reboot your server, and restart your node. When it comes back, use:
```sh
# for nym-node
cat /proc/$(pidof nym-node)/limits | grep "Max open files"

# for validator
cat /proc/$(pidof nym-validator)/limits | grep "Max open files"
```

- Make sure the limit has changed to `65535`.

### Set `ulimit` on non `systemd` based distributions

In case you choose tmux option for Nym Node automation, see your `ulimit` list by running:

```sh
ulimit -a
```

Watch for the output line `-n`:
```sh
-n: file descriptors          1024
```

You can change it either by running a command:
```sh
ulimit -u -n 4096
```

or editing `etc/security/conf` and add the following lines:

```sh
# Example hard limit for max opened files
username        hard nofile 4096

# Example soft limit for max opened files
username        soft nofile 4096
```

Then reboot your server and restart your node.

## Running `nym-node` as a non-root

Some operators prefer to run `nym-node` without root privileges. It's possible but still `nym-node` binary needs higher privileges for network-level operations demanding these permissions. If you are starting a new `nym-node` and want to run it as a non-root, follow [this guide](../nym-node/configuration#running-nym-node-as-a-non-root) before you proceed with the node setup sections.

## Ports reference tables

All node-specific port configuration can be found in `$HOME/.nym/<BINARY_TYPE>/<ID>/config/config.toml`. If you do edit any port configs, remember to restart your client node processes and change the configuration in the wallet settings.

### Nym node port reference

#### Mix Node functionality ports

| Default port | Use                       |
| ------------ | ------------------------- |
| `1789`       | Listen for Mixnet traffic |
| `1790`       | Listen for VerLoc traffic |
| `8080`       | Metrics http API endpoint |

#### Gateway functionality ports

| Default port    | Use                           |
|-----------------|-------------------------------|
| `1789`          | Listen for Mixnet traffic     |
| `9000`          | Listen for Client traffic     |
| `9001`          | WSS                           |
| `8080, 80, 443` | Reversed Proxy & Swagger page |
| `51822/udp`     | WireGuard                     |

#### Embedded Network Requester functionality ports

| Default port | Use                       |
|--------------|---------------------------|
| `9000`       | Listen for Client traffic |

### Validator port reference

All validator-specific port configuration can be found in `$HOME/.nymd/config/config.toml`. If you do edit any port configs, remember to restart your validator.

| Default port | Use                                  |
|--------------|--------------------------------------|
| `1317`         | REST API server endpoint             |
| `26656`        | Listen for incoming peer connections |
| `26660`        | Listen for Prometheus connections    |

---
title: Advanced Server Administration
url: https://nym.com/docs/operators/nodes/preliminary-steps/vps-setup/advanced
---

# Advanced Server Administration

This page is for experienced operators and aspiring sys-admins who seek for higher optimisation and better efficiency of their work managing Nym infrastructure. The steps shared on this page cannot be simply copy-pasted, they ask you for more attention and consideration all the way from choosing server and OS to specs per VM allocation.

## Virtualising a Dedicated Server

Some operators or squads of operators orchestrate multiple Nym nodes. Among other benefits (which are out of scope of this page), these operators can decide to acquire one larger dedicated (or bare-metal) server with enough specs (CPU, RAM, storage, bandwidth and port speed) to meet [minimum requirements](../../../nodes#minimum-requirements) for multiple nodes run in parallel.

This guide explains how to prepare your server in order to be able to host multiple nodes running on separated VMs.

This guide is based on Ubuntu 22.04, in case you prefer another OS, you may have to do a bit of your own research to troubleshoot networking configuration and other parameters.

## Installing KVM on a Server with Ubuntu 22.04

**KVM** stands for **Kernel-based Virtual Machine**. It is a virtualization technology for Linux that allows a user to run multiple virtual machines (VMs) on a single physical machine. KVM turns the Linux kernel into a hypervisor, enabling it to manage multiple virtualised systems.

Follow the steps below to install KVM on Ubuntu 22.04 LTS.

### Prerequisites

Operators aiming to run Nym node as mixnet [Exit Gateway](../../../community-counsel/exit-gateway) or with wireguard enabled should familiarize themselves with the challenges possibly coming along `nym-node` operation, described in our [community counsel](../../../community-counsel) and follow up with [legal suggestions](../../../community-counsel/legal). Particularly important is to [introduce yourself](../../../community-counsel/legal#introduce-nym-node-to-your-provider) and your intentions to run a Nym node to your provider.

This step is essential part of legal self defense because it may prevent your provider immediately shutting down your entire service (with all the VMs on it) when receiving first abuse report.

Additionally, before purchasing a large server, **contact the provider and ask if the offered CPU supports Virtualization Technology (VT)**, without this feature you will not be able to proceed.

Start with obtaining a server with Ubuntu 22.04 LTS:
- Make sure that your server meets [minimum requirements](../vps-setup#nym-node---dedicated-server) multiplied by number of `nym-node` instance you aim to run on it.
- Most people rent a server from a provider and it comes with a pre-installed OS (in this guide we use Ubuntu 22.04). In case your choice is a bare-metal machine, you probably know what you are doing, there are some useful guides to install a new OS, like [this one on ostechnix.com](https://ostechnix.com/install-ubuntu-server/).

Make sure thay your system actually supports hardware virtualisation:
- Check out the methods documented in [this guide by ostechnix.com](https://ostechnix.com/how-to-find-if-a-cpu-supports-virtualization-technology-vt/).

Order enough IPv4 and IPv6 (static and public) addresses to have one of each for each planned VM plus one extra for the main machine.

When you have your OS installed, validated CPU virtualisation support and obtained IP addresses, you can start configuring your VMs, following the steps below.

> Note that the commands below require root permission. You can either go through the setup as `root` or use `sudo` prefix with the commands used in the guide. You can switch to `root` shell by entering one of these commands `sudo su` or `sudo -i`.

##### 1. Install KVM

- Install KVM and required components:
```sh
apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst
```

- `qemu-kvm`: Provides the core **KVM virtualization** support using QEMU.
- `libvirt-daemon-system`: Manages virtual machines via the **libvirt daemon**.
- `libvirt-clients` Provides command-line tools like `virsh` to manage VMs.
- `bridge-utils`: Enables **network bridging**, allowing VMs to communicate over the network.
- `virtinst`: Includes `virt-install` for **creating virtual machines** via CLI.

- Start the `libvertd` service:
```sh
systemctl enable libvirtd
systemctl start libvirtd
```
- Validate by checking status of `libvirt` service:
```sh
systemctl status libvirtd
```

The command output should look similar to this one:
```
root@nym-exit:~# systemctl status libvirtd
● libvirtd.service - Virtualization daemon
     Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2025-02-27 14:25:28 MSK; 2min 1s ago
TriggeredBy: ● libvirtd-ro.socket
             ● libvirtd.socket
             ● libvirtd-admin.socket
       Docs: man:libvirtd(8)
             https://libvirt.org
   Main PID: 6232 (libvirtd)
      Tasks: 21 (limit: 32768)
     Memory: 11.8M
        CPU: 852ms
     CGroup: /system.slice/libvirtd.service
             ├─6232 /usr/sbin/libvirtd
             ├─6460 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
             └─6461 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper

Feb 27 14:25:28 nym-exit.example.com systemd[1]: Started Virtualization daemon.
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: started, version 2.90 cachesize 150
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset no-nftset auth cryptohash DNSSEC loop-detect inotify dump>
Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: DHCP, IP range 192.168.122.2 -- 192.168.122.254, lease time 1h
Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: DHCP, sockets bound exclusively to interface virbr0
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: reading /etc/resolv.conf
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: using nameserver 127.0.0.53#53
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: read /etc/hosts - 8 names
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 names
Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: read /var/lib/libvirt/dnsmasq/default.hostsfile
```

- In case you don't configure KVM as `root`, add your current user to the `kvm` and `libvirt` groups to enable VM creation and management using the `virsh` command-line tool or the `virt-manager` GUI:
```bash
usermod -aG kvm $USER
usermod -aG libvirt $USER
```

##### 2. Setup Bridge Networking with KVM

A **bridged network** lets VMs share the host’s network interface, allowing direct IPv4/IPv6 access like a physical machine.

By default, KVM sets up a **private virtual bridge**, enabling VM-to-VM communication within the host. It provides its own subnet, DHCP, and NAT for external access.

Check the IP of KVM’s default virtual interfaces with:

```bash
ip a
```

The command output should look similar to this one:
```
root@nym-exit:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f0
3: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f0
    inet 31.222.238.222/24 brd 31.222.238.255 scope global eno49
       valid_lft forever preferred_lft forever
    inet6 fe80::3a63:bbff:fe2e:9d20/64 scope link
       valid_lft forever preferred_lft forever
4: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f1
5: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f2
6: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f1
7: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f3
8: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:ac:d3:ba brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
```

By default, KVM uses the `virbr0` network with `<IPv4_ADDRESS>.1/24`, assigning guest VMs IPs in the `<IPv4_ADDRESS>.0/24` range. The host OS is reachable at `<IPv4_ADDRESS>.1`, allowing SSH and file transfers (`scp`) between the host and guests.

This setup works if you only access VMs from the host. However, remote systems on a different subnet (e.g., `<IPv4_ADDRESS_ALT>.0/24`) **cannot** reach the VMs.

To enable external access, we need a *public bridge* that connects VMs to the host’s main network, using its DHCP. This ensures VMs get IPs in the same range as the host.

Before configuring a public bridge, **disable Netfilter** on bridges for better performance and security, as it is enabled by default.

- Create a file located at `/etc/sysctl.d/bridge.conf`:
```bash
nano /etc/sysctl.d/bridge.conf

# in case of using custom editor, replace nano in the syntax
```

- Paste inside the following block, save and exit:
```ini
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
```

- Create a file `/etc/udev/rules.d/99-bridge.rules`:
```bash
nano /etc/udev/rules.d/99-bridge.rules
```

- Paste this line, save and exit:
```bash
ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"
```

This disables Netfilter on bridges at startup. Save, exit, and reboot to apply changes.

- Disable KVM’s default networking. Find the default network interface with:
```bash
ip link
```

The command output should look similar to this one:
```
root@nym-exit:~# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f0
3: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f1
4: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f0
5: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f2
6: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f1
7: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f3
8: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:ac:d3:ba brd ff:ff:ff:ff:ff:ff
```

The `virbr0` interface is KVM’s default network. Note your physical interface’s MAC address (e.g., `eno49`). It's the only interface that is currently `UP` and running (`LOWER_UP` state). Other interfaces are `DOWN` and not in use.

- Remove the default KVM network:
```bash
virsh net-destroy default
```

- Remove the default network configuration:
```bash
virsh net-undefine default
```

- In case last two commands didn't work, try this:
```bash
ip link delete virbr0 type bridge
```
-  Verify that the `virbr0` and `virbr0-nic` interfaces are deleted:
```bash
ip link
```

The command output should look similar to this one:
```
root@nym-exit:~# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f0
3: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f1
4: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f0
5: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f2
6: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f1
7: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
    altname enp2s0f3
```
KVM network is gone.

##### 3. Setup KVM public bridge for new VMs

To create a KVM network bridge on Ubuntu, edit a config file located in `/etc/netplan/` either called `00-installer.yaml` or `00-installer-config.yaml` and add the bridge details.

- Before you edit the file, make a backup to stay on the save side:
```bash
cp /etc/netplan/00-installer-config.yaml /etc/netplan/00-installer-config.yaml.bak
# or
cp /etc/netplan/00-installer.yaml /etc/netplan/00-installer.yaml.bak
```

- Open `00-installer-config.yaml` or `00-installer.yaml.`config in a text editor:
```bash
nano /etc/netplan/00-installer.yaml
# or
nano /etc/netplan/00-installer-config.yaml
```

- Edit the block below and paste it to the config file, save and exit:
```yaml
#####################################################
######## CHANGE ALL VARIABLES IN <> BRACKETS ########
#####################################################

# <INTERFACE> is your own one, you can get with command ip link show
# <HOSTv4> is your server main IPv4 address
# <HOSTv6> is your server main IPv6 address
# <GATEWAYv4> value can be found by running: ip -4 route | grep default
# <GATEWAYv6> value can be found by running: ip -6 route | grep default

---------------------------------------------
 host-bridge   active   yes         yes
```

KVM bridge networking is successfully set up and active!

Your KVM installation is now ready to deploy and manage VMs.

## Setting Up Virtual Machines

**After finishing the [installation of KVM](#installing-kvm-on-a-server-with-ubuntu-2204), we can move to the virtualisation configuration.**

> **This tutorial will guide you through a setup of one VM, therefore you will have to repeat this process for each VM**.

A good practice before initialising any VMs, is to calculate space and memory allocation for each of them and your host machine.

You can choose in between using [bash scripts](#setting-up-vm-using-scripts) or [manual steps](#setting-up-vm-step-by-step) approach. While scripts may be faster, they give you much less flexibility. Therefore if you prefer to have room for customisation coming along installing software, do it step by step.

Remember, that anytime you execute a script on your computer, make sure to read and understand the script first.

### Seting up VM Using Scripts

In case you want to initialise and configure your VMs manually - skip this chapter and go directly to the [*step-by-step* part](#setting-up-vm-step-by-step).

Using the scripts is a two-step process. First, initialisation part is done from the host root using [`initialise-vm.sh`](https://github.com/nymtech/nym/blob/develop/scripts/kvm-setup/initialise-vm.sh) and second, configuration part is done from the VM itself using [`configure-vm.sh`](https://github.com/nymtech/nym/blob/develop/scripts/kvm-setup/configure-vm.sh).

##### 1. Initialise VM from the host machine
- Log in to your host as `root`
- Run this block and follow the prompts carefully:
```bash
wget "https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/kvm-setup/initialise-vm.sh"
chmod +x ./initialise-vm.sh
./initialise-vm.sh
```

##### 2. Configure VM from within
- After logging into your VM run this block and follow the prompts carefully:
```bash
wget "https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/kvm-setup/configure-vm.sh"
chmod +x ./configure-vm.sh
./configure-vm.sh
```
</ Steps>

### Setting up VM Step-by-step

In case you did't use the scripts and prefer manual approach, follow the steps below carefully.

##### 1. Install OS for VMs

This is the OS on which the nodes themselves will run. You can chose any GNU/Linux of your preference. For this guide we are going to be using Ubuntu 24.04 LTS (Noble Numbat) cloud image from [cloud-images.ubuntu.com](https://cloud-images.ubuntu.com/noble/current/).

- Download Ubuntu Cloud image:
```bash
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
```
- Copy the image to to `/var/lib/libvirt/images/` asigning to it a name your VM
```bash
cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/<VM_NAME>.img

# for example:
# cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/ubuntu-1.img
```

##### 2. Create and resize a virtual machine

- Get `guestfs-tools` to be able to customize your login credentials:
```bash
apt install guestfs-tools
```

- Define login credentials:
```bash
virt-customize -a /var/lib/libvirt/images/<VM_NAME>.img --root-password password:<PASSWORD>
# for example
# virt-customize -a /var/lib/libvirt/images/ubuntu-1.img --root-password password:makesuretosaveyourpasswordslocallytoapasswordmanager
```

- Use `qemu-img` tool with a command `resize` to create a VM according your needs. You can see `qemu` [documentation page`](https://www.qemu.org/docs/master/tools/qemu-img.html) for more info on how to use it correctly.
```bash
qemu-img resize /var/lib/libvirt/images/<VM_NAME>.img +<SIZE_IN_GB>G
# for example
# qemu-img resize /var/lib/libvirt/images/ubuntu-1.img +100G
```

- Resize it from within it after `virt-install` command:
```bash
virt-install \
--name <VM_NAME> \
--ram=<SIZE_IN_MB> \
--vcpus=<NUMBER_OF_VIRTUAL_CPUS> \
--cpu host \
--hvm \
--disk bus=virtio,path=/var/lib/libvirt/images/<VM_NAME>.img \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--osinfo <YOUR_CHOSEN_OS_NAME> \
--import
```

- In our example we go with 4 GB RAM on the same machine as before:

```bash
virt-install \
--name ubuntu-1 \
--ram=4096 \
--vcpus=4 \
--cpu host \
--hvm \
--disk bus=virtio,path=/var/lib/libvirt/images/ubuntu-1.img \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--osinfo ubuntunoble \
--import
```

- After loading you should see a login console, you can also initiate it by:
```bash
virsh console <VM_NAME>
# for example
# virsh console ubuntu-1
```

- Log in to your new VM using your credentials.

##### 3. Validate your setup

- Make sure the `root` disk has the expected space by running:
```bash
df -h
```

- If not, run:
```bash
growpart /dev/vda 1
resize2fs /dev/vda1
```

##### 4. Configure networking for the VM

As this guide is based on a newer Ubuntu, we use `netplan`, this may be different on different OS.

- Open `/etc/netplan/01-network-config.yaml` in your favourite text editor:
```bash
nano /etc/netplan/01-network-config.yaml
```

- Insert this config, using your correct IP configuration, save and exit:
```yaml
#####################################################
######## CHANGE ALL VARIABLES IN <> BRACKETS ########
#####################################################

# <INTERFACE> is your own one, you can get with command ip link show
# <VM_IPv4> is your VM IPv4 address
# <VM_IPv6> is your VM Pv6 address
# <GATEWAYv4> value can be found by running: ip -4 route | grep default
# <GATEWAYv6> value can be found by running: ip -6 route | grep default

network:
  version: 2
  renderer: networkd
  ethernets:
    <INTERFACE>:
      dhcp4: false
      dhcp6: false  # Set to true if you want automatic IPv6 assignment
      addresses:
        - <VM_IPv4>/24  # Assign IPv4 address to the VM
        - <VM_IPv6>/64  # Assign IPv6 address to the VM
      routes:
        - to: default
          via: <GATEWAYv4>  # IPv4 gateway
        - to: default
          via: <GATEWAYv6>  # IPv6 gateway
      nameservers:
        addresses:
          - 1.1.1.1  # Cloudflare IPv4 DNS
          - 8.8.8.8  # Google IPv4 DNS
          - 8.8.4.4  # Secondary Google IPv4 DNS
          - 2606:4700:4700::1111  # Cloudflare IPv6 DNS
          - 2001:4860:4860::8888  # Google IPv6 DNS
```
- Fix wide permissions on the config file:
```bash
chmod 600 /etc/netplan/01-network-config.yaml
```

- Check if the config has any errors:
```bash
netplan generate
```

- Apply the configuration:
```bash
netplan --debug  apply
```

- Verify by checking if IPv4 and IPv6 are assigned correctly and if they route:
```bash
ip -4 a
ip -6 a
```
```bash
ip -4 r
ip -6 r
```
```bash
# to ping through IPv6, use:
ping6 nym.com
```
- You should be able to ping your new VM from a local machine:
```bash
ping <IPv4_VM>
ping6 <IPv6_VM>
```

Your VM should be working and fully routable. To be able to use it properly, we will create a direct SSH access to the VM.

#### Configure VM SSH access

##### 1. Log in to your VM, update and upgrade your OS:
- Log in to your server using as `root` or as a non-root user with `sudo` privileges
```bash
apt update; apt upgrade
```

##### 2. Generate new host SSH keys

Since we used a `cloud-init` image without an SSH server, we need to generate SSH host keys for client authentication and server identity verification. All of them will be saved to this location: `/etc/ssh/<KEY>`.

- Generate a new RSA host key:
```bash
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
```
- Generate a new DSA host key:
```bash
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
```
- Generate a new ECDSA host key:
```bash
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
```
- Finally, generate a new ED25519 host key:
```bash
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
```
##### 3. Restart the SSH service on the server
- Run:
```bash
systemctl restart ssh.service
```

##### 4. Check if the SSH serice is active
- Run:
```bash
systemctl status ssh.service
```

##### 5. Create file `~/.ssh/authorized_keys` and add you public key:
- Create `.ssh` directory:
```bash
mkdir ~/.ssh
```

- Open with your favourite text editor:
```bash
nano ~/.ssh/authorized_keys
```
- Paste your SSH public key, save and exit

- In case of non-root, setup a correct ownership and permissions:
```bash
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chown : ~/.ssh
```

##### 5. Test by connecting via SSH

- Now you should be able to connect to the VM directly from your local terminal
```bash
ssh root@<IPv4> -i ~/.ssh/your_ssh_key
```

Now your VM is almost ready for `nym-node` [setup](../../nym-node/setup). Before you proceed, ssh in and [configure all prerequisities](../vps-setup#vps-configuration) needed for `nym-node` installation and operation.

## Removing Virtual Machines

If you setup your VM in a wrong way, or you simply don't use it anymore, you can remove it.

**These commands will erase everything on the VM, make sure to backup everything you may need in the future bewfore executing this!**

###### 1. SSH to the host server

###### 2. List all VMs
```sh
virsh list --all
```

###### 3. Shut down and remove VM
- To remove a VM run this sequence
```sh
# shutdown
virsh shutdown <VM_NAME>
sleep 10

# destroy
virsh destroy <VM_NAME>

# undefine and purge storage
virsh undefine <VM_NAME> --remove-all-storage

# ensure the storage is deleted
rm /var/lib/libvirt/images/<VM_NAME>.img
```

###### 4. List all VMs again

- The list should not contain the VM that you just deleted:
```sh
virsh list --all
```
</ Steps>

---
title: Nym Node
url: https://nym.com/docs/operators/nodes/nym-node
---

# Nym Node

NYM NODE is a tool for running a node within the Nym network. Nym Nodes containing functionality such as `mixnode`, `entry-gateway` and `exit-gateway` are fundamental components of Nym Mixnet architecture. Nym Nodes are ran by decentralised node operators.

To setup any type of Nym Node, start with either building [Nym's platform](../binaries/building-nym.mdx) from source or download [pre-compiled binaries](../binaries/pre-built-binaries.mdx) on the [configured server (VPS)](preliminary-steps/vps-setup.mdx) where you want to run the node. Your Nym Node will need to be bonded before it can be run. We recommend most users use the [Nym desktop wallet](preliminary-steps/wallet-preparation.mdx) for this.

**Read thoroughly [Minimum Requirement page](../nodes.mdx) before you configure and run a `nym-node`!**

---
title: Nym Node Setup & Run
url: https://nym.com/docs/operators/nodes/nym-node/setup
---

# Nym Node Setup & Run

This documentation page provides a guide on how to set up and run a [NYM NODE](../nym-node.mdx), along with explanations of available flags, commands, and examples.

<VarInfo/ >

## Current version

```sh
nym-node
Binary Name:        nym-node
Build Timestamp:    2026-05-06T05:19:51.973494120Z
Build Version:      1.31.0
Commit SHA:         f84de25302e886d4bd97a898885c569724c002a7
Commit Date:        2026-05-06T07:16:42.000000000+02:00
Commit Branch:      HEAD
rustc Version:      1.91.1
rustc Channel:      stable
cargo Profile:      release
```

Detailed version archive and release notes is documented [here](../../changelog.mdx).

{/* COMMENTING THIS OUT ASS WE HAVE TO FIGURE OUT HOW TO SHOW THE LATEST VERSION FROM MASTER BRANCH

*/}

## Functionality (mode)

From `nym-node v1.3.0` operators can choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).

**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes and therefore we ask operators to assign only one functionality to `--mode` option at a time. Please chose out of: `mixnode` or `entry-gateway` or `exit-gateway`. Chosing multiple at once will make your node non-routable!**

### Mixnet Routing

***Mixnet mode (5-hop) is the full anonymising option of NymVPN. Read more about the Mixnet architecture [here](/network/overview)***

Nym Node has three functionalities in the Mixnet: `entry-gateway`, `mixnode` and `exit-gateway`. These are selected with a flag `--mode <MODE>` alongside `nym-node` command `run` .

- **Entry Gateway (`--mode entry-gateway`)**: A node to which clients connect. It checks the bandwidth allowance, using [zk-nyms](../../../network/cryptography/zk-nym) and either sends [Sphinx packets](../../../network/cryptography/sphinx) through the mixnet or directly to Exit Gateway in case of dVPN (2-hop) routing. This node also receives replies and sends them back to users local client.

- **Mixnode (`--mode mixnode`)**: Nodes organized in three layers, randomly selected every epoch (60 minutes), mixing Sphinx packets, adding a slight latency to defend users agains time correlation attacks and sending them further to the next layer or to the Exit Gateway

- **Exit Gateway (`--mode exit-gateway`)**: The final node in the mixnet. It puts all packets together and using inbuilt Network requester and IP packet router, it sends traffic to the open internet. This node also recieves replies and sends them back to the user client.

Exit Gateway is the only mode routing data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run an Exit Gateway, please read our [Community Counsel pages](../../community-counsel/exit-gateway) containing more information and some legal content.

### dVPN Routing

***dVPN routing (2-hop) is the Fast option of NymVPN. It runs a wireguard tunnel inside another wireguard tunnel. dVPN uses 2 Gateway layers (entry and exit) and no Mixnode layers. If an operator announces and [correctly configure](configuration#connectivity-test-and-configuration) their node to route wireguard, the node can be chosen as entry or exit by any client at any time.***

To activate wireguard routing, operators need to add `--wireguard-enabled true` alongside `nym-node` command `run`.

Wireguard nodes route data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run a node with active wireguard routing, please read our [Community Counsel pages](../../community-counsel/exit-gateway) containing more information and some legal content.

**Wireguard mode has no exit policy right now - we are working on the implementation.**

Everything essential for each mode exists on `nym-node` by default. For instance, if you run a Mixnode, you'll find that a NR (Network Requester) and IPR (IP Packet Router) addresses exist, but they will be ignored in `mixnode` mode.

Note that every `exit-gateway` mode is basically an `entry-gateway` with NR (Network Requester) and IPR (IP Packet Router) enabled. This means that every `exit-gateway` can work as an `entry-gateway` but not the opposite.

## Command & Examples

**`nym-node` introduces a default human readible ID (local only) `default-nym-node`, which is used if there is not an explicit custom `--id <ID>` specified. All configuration is stored in `~/.nym/nym-nodes/default-nym-node/config/config.toml` or `~/.nym/nym-nodes/<ID>/config/config.toml` respectively.**

### Help Command

There are a few changes from the individual binaries used in the past. For example by default `run` command does initialisation function as well, local node `--id` will be set by default (1default-nym-node`) unless specified otherwise.

You can always use `--help` flag to see the commands or arguments associated with a given command.

Run `./nym-node --help` to see all available commands:

To list all available flags for each command, run `./nym-node <COMMAND> --help` for example `./nym-node run --help`:

The Wireguard flags currently have limited functionality. From version `1.1.6` ([`v2024.9-topdeck`](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.9-topdeck)) wireguard is available and recommended to be switched on for nodes running as Gateways. Keep in mind that this option needs a bit of a special [configuration](configuration.md#wireguard-setup).

Accepting T&Cs is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. If you use [systemd](configuration.md#systemd) automation, add the flag to your service file's `ExecStart` line.

To check whether any node has T&Cs accepted or not can be done by querying Swagger API endpoint `/auxiliary_details` via one of these ports (depending on node setup):
```sh
# sustitude <NODE_IP_ADDRESS> or <NODE_DOMAIN> with a real one
http://<NODE_IP_ADDRESS>:8080/api/v1/auxiliary_details
https://<NODE_DOMAIN>/api/v1/auxiliary_details
http://<NODE_IP_ADDRESS>/api/v1/auxiliary_details
```

```sh
# substitude <PUBLIC_IP> with a real one
curl -X 'GET' \
  'http://<NODE_IP_ADDRESS>:8080/api/v1/auxiliary-details' \
  -H 'accept: application/json'

{
  "location": "Kurdistan",
  "accepted_operator_terms_and_conditions": true
}
```

#### Essential Parameters & Variables

Running a `nym-node` in a `mixnode` mode requires less configuration than a full `exit-gateway` setup, we recommend operators to still follow through with all documented [configuration](configuration). Before you scroll down to syntax examples for the mode of your choice please familiarise yourself with the essential [paramters and variables](../../variables) convention we use in the guide.

To prevent over-flooding of our documentation we cannot provide with every single command syntax as there is a large combination of possibilities. Please read the [variables and parameters page](../../variables.mdx), use the explanation in `--help` option and common sence.

## Setup & Run

When we use `run` command for the first time the node will initialise all essential configuration and data files (unless specified with a flag `--deny-init`) stored at `$HOME/.nym/nym-nodes/<ID>` where the most important is the `config.toml` file stored at `$HOME/.nym/nym-nodes/<ID>/config/`. Below are some examples of initialising and running `nym-node` with different modes (`--mode`) like `mixnode`, `entry-gateway`, `exit-gateway`.

Please keep in mind that currently we ask operators to run only one functionality (`--mode`) at a time.

There is a simple default command to initialise and run your node: `./nym-node  run  --mode <MODE>`, however there quite a few parameters to be configured.

If an operator specifies any paramteres with optional flags alongside `run` command, these parameters passed in the option will take place over the ones in `config.toml` but they will not overwrite them by default. To overwrite them with the values passed with `run` command, a flag `-w` (`--write-changes`)  must be added.

Alternatively operators can just open a text editor and change these values manually. After saving the file,don't forget to restart the node or reload and restart the service. If all values are setup correctly in `config.toml`, then operator can use as simple command as `nym-node run --mode <MODE> --accept-operators-terms-and-conditions`, or alternatively paste this command with a correct path to your binary to your `ExecStart` line into a [systemd `nym-node.service`](configuration.md#systemd) config file.

**Below is a step by step guide how to initialise and run `nym-node`. Each tab represents one functionality.**

**We recommend operators to setup an [automation](configuration.md#systemd) flow for their nodes, using systemd!**

In such case, you can `run` a node to initalise it or try if everything works, but then stop the proces and paste your entire `run` command syntax (below) to the `ExecStart` line of your `/etc/systemd/system/nym-node.service` and start the node as a [service](configuration.md#following-steps-for-nym-nodes-running-as-systemd-service).

## Migrate

**Legacy binaries `nym-mixnode` and `nym-gateway` had been deprecated, [`nym-node`](../nym-node.mdx) is the only binary to use for `gateway` or `mixnode` functionalities!**

From `2024.14-crunch` release (`nym-node v1.2.0`) onward, `nym-node` binary does *not* have `migrate` command included. In case you are still running a legacy node and want to migrate, [download](https://github.com/nymtech/nym/releases) an older `nym-node` binary and upgrade to the latest after migrating.

Furthermore, giving that legacy nodes had been deprecated for several months, Nym cannot promise 100% serialisation for operators migrating from long outdated versions. If you are about to migrate, start with  [`nym-node v1.1.0`](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.3-eclipse) and keep upgrading version by version all the way to the latest one.

Operators who are about to migrate their nodes need to configure their [VPS](../preliminary-steps/vps-setup) and setup `nym-node` which can be downloaded as a [pre-built binary](../../binaries/pre-built-binaries) or compiled from [source](../../binaries/building-nym).

To migrate a `nym-mixnode` or a `nym-gateway` to `nym-node` use, the `migrate` command with `--config-file` flag pointing to the original `config.toml` file, with a conditional argument defining which type of node this configuration belongs to. The exact steps are below.

Make sure to use `--deny-init` flag to prevent initialisation of a new node.

**After you upgraded your node to the latest release of `nym-node`, make sure that you also follow [the steps to migrate your node in the Mixnet smart contract](bonding#migrate-to-nym-node-in-mixnet-smart-contract), othewise your node will never receive any rewards.**

## Functionality & Performance Check

We have a chapter called [Performance Monitoring & Testing](/operators/performance-and-testing) including much more information and tooling. If you want to just quickly check your nodes performance, connectivity and much more, visit [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).

For more information about available endpoints and their status, you can refer to:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
# or
http://<IPv4_ADDRESS>/api/v1/swagger/#/

# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/swagger/#/
```

For example to determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/roles
# or
http://<IPv4_ADDRESS>/api/v1/roles

# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/roles
```

## Next steps

If there are any problems checkout the troubleshooting section or report an issue.

Follow up with [configuration](configuration.mdx) page for automation, reversed proxy setup and other tweaks, then head straight to [bonding](bonding.mdx) page to finalise your setup.

---
title: Nym Node Configuration & Systemd Setup
description: Configure your nym-node with systemd automation, reverse proxy, IPv6, and custom settings. Includes service file templates and maintenance tips.
url: https://nym.com/docs/operators/nodes/nym-node/configuration
---

# Nym Node Configuration

## Basic Changes

Nym Node can be configured directly by editing the config file (`config.toml`) located at `~/.nym/nym-nodes/<ID>/config/config.toml` (by default `~/.nym/nym-nodes/default-nym-node/config/config.toml`) or through commands on the binary.

### Node Description

Operators can add a description themselves to share more information about their `nym-node` publicly.

To add or change `nym-node` description is done by editing `description.toml` file located in `~/.nym/nym-nodes/<ID>/data/description.toml`. After saving, don't forget to reload and restart your node [service](#systemd) or simply restart your `nym-node` if you run it without a service (not recommended).

**Query description**

Nodes description can be queried from API endpoint `/api/v1/description` or via Swagger API UI page `/api/v1/swagger/#/Node/description`.

```bash
curl -X 'GET' \
  'http://<PUBLIC_IP>:8080/api/v1/description' \
  -H 'accept: application/json'

# or for https reversed proxy or WSS setup
curl -X 'GET' \
  'https://<HOSTNAME>/api/v1/description' \
  -H 'accept: application/json'
```

## Commands & Examples

Disable sharing of system hardware info with the network:

```sh
./nym-node run --id <ID> --deny-init --mode entry-gateway -w --expose-system-hardware false --expose-system-info false
```

Alternatively these values can be changed in `config.toml` of your node. After saving, don't forget to reload and restart your node [service](#systemd) or simply restart your `nym-node` if you run it without a service (not recommended).

> Note: `--expose-system-info false` supersedes `--expose-system-hardware false`. If both are present with conflicting values, the system hardware will not be shown.

## VPS Setup and Automation

> Replace `<NODE>` variable with type of node you run, in majority of cases this will be `nym-node` (depreciated `nym-mixnode`, `nym-gateway` or `nym-network-requester` are no longer supported).

Although it’s not totally necessary, it's useful to have `nym-node` automatically start at system boot time. We recommend to run your remote operation via [`tmux`](#tmux) for easier management and a handy return to your previous session. For full automation, including a failed node auto-restart and `ulimit` setup, [`systemd`](#systemd) is a recommended choice for all operators, as it allows much more automation leading to better uptime and performance.

> Do any of these steps and run your automated node before you start bonding process!

### nohup

`nohup` is a command with which your terminal is told to ignore the `HUP` or 'hangup' signal. This will stop the node process ending if you kill your session.

```sh
nohup ./<NODE> run <ARGUMENTS> # use all the flags you use to run your node
```

### tmux

One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated.

Use the following command to get `tmux`.

| Platform | Install Command |
| :---      | :---             |
| Arch Linux|`pacman -S tmux`             |
| Debian or Ubuntu|`apt install tmux`      |
| Fedora|`dnf install tmux`                 |
| RHEL or CentOS|`yum install tmux`          |
|  macOS (using Homebrew | `brew install tmux`    |
| macOS (using MacPorts) | `port install tmux`    |
|               openSUSE | `zypper install tmux`  |

In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control).

**Running tmux**

Now you have installed tmux on your VPS, let's run a Mix Node on tmux, which allows you to detach your terminal and let your `<NODE>` run on its own on the VPS.

* Pause your `<NODE>`
* Start tmux with the command
```sh
tmux
```
* tmux terminal should open in the same working directory, just the layout changed into tmux default layout.
* Start the `<NODE>` again with a command:
```sh
./<NODE> run <ARGUMENTS> # use all the flags you use to run your node
```
* Now, without closing the tmux window, you can close the whole terminal and the `<NODE>` (and any other process running in tmux) will stay active.
* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session:
```sh
tmux attach-session
```
* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?`

### systemd

###### 1. Create a service file

To automate with `systemd` use this init service file by saving it as `/etc/systemd/system/nym-node.service` and follow the [next steps](#2-following-steps-for-nym-node-running-as-systemd-service).

- Open service file in a text editor
```sh
nano /etc/systemd/system/nym-node.service
```

- Paste this config file, substitute `<USER>` and `<PATH>` with your correct values and add all flags to run your `nym-node` to `ExecStart` line instead of `<ARGUMENTS>`:
```ini
[Unit]
Description=Nym Node
StartLimitInterval=350
StartLimitBurst=10

[Service]
User=<USER>
LimitNOFILE=65536
ExecStart=<PATH>/nym-node run <ARGUMENTS> # add all the flags you use to run your node
KillSignal=SIGINT
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
```

[Accepting T&Cs](setup.md#terms--conditions) is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. If you use systemd automation, add the flag to your service file's `ExecStart` line.

- Save config and exit

Make sure your `ExecStart <PATH>` and `run` command `<ARGUMENTS>` are correct!

Example: If you have built nym in the `$HOME` directory on your server, your username is `jetpanther`, and node `<ID>` is `puma`, then the `ExecStart` line (command) in the script located in `/etc/systemd/system/nym-node.service` for might look like this:
`ExecStart=/home/jetpanther/nym/target/release/nym-node run --id puma`.

Basically, you want the full path to `nym-node`. If you are unsure about your `<PATH>`, then `cd` to your directory where you run your `<NODE>` from and run `pwd` command which returns the full path for you.

###### 2. Following steps for `nym-node` running as `systemd` service

Once your service file is saved follow these steps.

- Reload systemctl to pickup the new unit file:
```sh
systemctl daemon-reload
```

- Enable the newly created service:
```sh
systemctl enable nym-node.service
```

- Start your `<NODE>` as a `systemd` service:
```sh
service nym-node start
```

This will cause your `<NODE>` to start at system boot time. If you restart your machine, your `<NODE>` will come back up automatically.

###### 3. Useful `systemd` commands for easier management

- You can monitor system logs of your node by running:
```sh
journalctl -u nym-node -f
```

- Or check service status by running:
```sh
systemctl status nym-node.service
# for example systemctl status nym-node.service
```

- You can also do `service <NODE> stop` or `service <NODE> restart`.

Anytime you make any changes to your `systemd` script after you've enabled it, you will need to run:
```sh
systemctl daemon-reload
service nym-node restart
```

This lets your operating system know it's ok to reload the service configuration and restarts the node in a graceful way.

## Routing Configuration

### Quick IPv6 Check

IPv6 routing is not only a case for gateways. Imagine a rare occasion when you run a `mixnode` without IPv6 enabled and a client will sent IPv6 packets through the Mixnet through such route:
```ascii
[client] -> [entry-gateway] -> [mixnode layer 1] -> [your mixnode] -> [IPv6 mixnode layer3] -> [exit-gateway]
```
In this (unusual) case your `mixnode` will not be able to route the packets. The node will drop the packets and its performance would go down. For that reason it's beneficial to have IPv6 enabled when running a `mixnode` functionality.

You can always check IPv6 address and connectivity by using some of these methods:

```sh
# locally listed IPv6 addresses
ip -6 addr

# globally reachable IPv6 addresses
ip -6 addr show scope global

# with DNS
dig -6 TXT +short o-o.myaddr.l.google.com @ns1.google.com
dig -t aaaa +short myip.opendns.com @resolver1.opendns.com

# https check
curl -6 https://ifconfig.co
curl -6 https://ipv6.icanhazip.com

# using telnet
telnet -6 ipv6.telnetmyip.com
```

Make sure to keep your IPv4 address enabled while setting up IPv6, as the majority of routing goes through that one!

## Wireguard Exit Policy Configuration

### Testing Wireguard Exit Policy

## QUIC Transport Bridge Deployment

## Running `nym-node` as a non-root

Some operators prefer to run `nym-node` without root privileges. It's possible but still `nym-node` binary needs higher privileges for network-level operations demanding these permissions. Below is a guide how to go about such setup:

Copying nodes database and the `.nym/` directories from `/root/.nym` to `/home/<USER>/.nym/` should be treated as experimental, therefore we would advise this section for operators starting new nodes, rather than tweaking an existing one. We will publish a detailed guide for changing permissions of an existing node soon.

###### 1. Setup a new user

- Define a variable `user_name` using your desired user name:
```sh
user_name="<USER>"
```

- Run:
```sh
user_home="/home/$user_name"

if ! id "$user_name" &>/dev/null; then
    sudo adduser --home "$user_home" --disabled-login --gecos "" "$user_name"
else
    echo "user $user_name already exists"
fi
```

- And follow by:

```sh
sudo usermod -aG sudo "$user_name"
```

- Optional: Add to sudoers group:
```sh
echo "$user_name ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/$user_name
```

###### 2. Grant needed permissions for network-level operations

While `nym-node` will be set as a user process, it requires higher privileges for network-level operations, set them up with this command:

```sh
sudo setcap 'cap_net_bind_service=+ep cap_net_admin=+ep' nym-node
```

**After replacing or upgrading the binary, you must reapply these permissions each time!**

###### 3. Edit service config file

- Add these new lines to your `/etc/systemd/system/nym-node.service` [service config file](#systemd)
    - `After=network.target`
    - `Group=<USER>`
    - `Type=simple`

- Your service file will then look like this:

```ini
[Unit]
Description=Nym Node
After=network.target
StartLimitInterval=350
StartLimitBurst=10

[Service]
User=<USER>
Group=<USER>
Type=simple
LimitNOFILE=65536
ExecStart=<PATH>/nym-node run <ARGUMENTS> # add all the flags you use to run your node
KillSignal=SIGINT
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
```

###### 4. Reload and restart the service

```sh
systemctl daemon-reload && service nym-node restart
```

- If you want to follow the logs, run:
```sh
journalctl -u nym-node -f
```

## Next Steps

There are a few more good suggestions for `nym-node` configuration, like Web Secure Socket or Reversed Proxy setup. These are optional and you can skip them if you want. Visit [Proxy configuration](configuration/proxy-configuration.mdx) page to see the guides.

---
title: Reverse Proxy & Web Secure Socket
url: https://nym.com/docs/operators/nodes/nym-node/configuration/proxy-configuration
---

export const IndexPage = () => (
<>
  An example template for <code>index.html</code> page
</>
);

# Reverse Proxy & Web Secure Socket

This section will guide you in setting up a reverse proxy for serving `nym-node` HTTP requests and to set up a custom [landing page](../../../community-counsel/landing-pages.mdx) for your node.

In later sections, you will be setting up secure websocket (wss) to add additional security and encrypt connections coming to your node. Follow [this guide](#web-secure-socket-setup) for installation.

Since SSL certificates can only be issued for a domain name and not an IP address, it is essential for you to register a new domain name and configure a domain record pointing to your node's IP address

The commands in this setup need to be run with root permission. Either add a prefix `sudo` or execute them from a root shell.

## Reverse Proxy Setup

Operators running nodes facing open internet may benefit from having a landing page. This page serves as a source of useful information about Nym network and the node when they try to search node IP or hostname.

### HTML File Customization

File for html configuration are by convention located at `/var/www/<HOSTNAME>` directory and it's sub-directories. We refer to this directory as `<LANDING_PAGE_ASSETS_PATH>`.

###### 1. Start by creating your directory landing page directory:
```sh
mkdir -p /var/www/<HOSTNAME>
```

###### 2. Create html landing page

- Use your own html code (check this [markdown to html tool](https://markdowntohtml.com/)) or use [this template](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/landing-page.html)

- Copy the [template](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/landing-page.html) a new file called `index.html` located in `/var/www/<HOSTNAME>` directory.

###### 3. If you used the template above - before you save and close the file, make sure to edit the email address:

- Change the email address you're willing to use for being contacted.
```
<a href="mailto:><YOUR_EMAIL_ADDRESS>">maintainer</a>
```

- Additionally you can add your own favicon logo on the line:
```html

```

###### 4. Save and exit

Now your html page is configured.

### `nym-node` Configuration

When done with the customization, you'll need to make sure your `nym-node` uploads the file and reference to it. This is done by opening your node configuration file located at `~/.nym/nym-nodes/<ID>/config/config.toml` and changing the value of the line `landing_page_assets_path` on the `[http]` section:
```toml
landing_page_assets_path = '<LANDING_PAGE_ASSETS_PATH>'
```

### Reverse Proxy Configuration

You may set up a [reverse proxy](https://www.nginx.com/resources/glossary/reverse-proxy-server) in order to serve this landing page with proper SSL and DNS management, i.e. to resolve it to `https://<HOSTNAME>`.

###### 1. Configure Nginx and firewall

- Install `nginx`:
```sh
sudo apt install nginx
```

- Setup firewall with `ufw`. `ufw` has three profile pre-configured for `nginx`, we will need the first one for `nym-node`:

  - `Nginx Full`: This profile opens both port 80 (normal, unencrypted web traffic) and port 443 (TLS/SSL encrypted traffic)
  - `Nginx HTTP`: This profile opens only port 80 (normal, unencrypted web traffic)
  - `Nginx HTTPS`: This profile opens only port 443 (TLS/SSL encrypted traffic)

```sh
ufw allow 'Nginx Full'

# you can verify by
ufw status

# possibly reload ufw by
ufw reload
```

- Disable the default Nginx landing page

```
systemctl status nginx
unlink /etc/nginx/sites-enabled/default
systemctl restart nginx
```

###### 2. Add your endpoint configuration to Nginx by creating a config file

- Open file in a text editor
```sh
nano /etc/nginx/sites-available/<HOSTNAME>
```
- Paste the text below to the editor and change `<HOSTNAME>` occurrences to your domain name:

```ini
server {
    listen 80;
    listen [::]:80;

    # Replace <HOSTNAME> with your domain name
    server_name <HOSTNAME>;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```
- Note: This guide assumes that the HTTP port used by you is `8080` (recommended default) . Adjust the configuration accordingly if you have defined
a custom port for your `nym-node` HTTP connections

###### 3. Activate and test Nginx configuration

- Create a symlink to `/etc/nginx/sites-enabled`:

```sh
ln -s /etc/nginx/sites-available/<HOSTNAME> /etc/nginx/sites-enabled
```

- Test your configuration syntax:

```sh
nginx -t
```

Nginx must report that the config is "ok" and the test was successful.

- Restart `nginx`:

```sh
systemctl restart nginx
```

###### 4. Get an `SSL` certificate using certbot and restart `nym-node`

```sh
apt install certbot python3-certbot-nginx
certbot --nginx --non-interactive --agree-tos --redirect -m <YOUR_EMAIL_ADDRESS> -d <HOSTNAME>
```

- Restart your `nym-node` or if you're running your `nym-node` as a [`systemd` service](../configuration.mdx#systemd), restart your service:
```sh
systemctl daemon-reload && service nym-node restart
```

###### 5. Verify that your page is working

- Check for the page being served reading the service logs
```sh
journalctl -u  nym-node.service | grep 8080
```
```sh
# where you should see
... Started NymNodeHTTPServer on 0.0.0.0:8080
```

Now your `nginx` should be configured, up and running. Test it by inserting your `<HOSTNAME>` as a URL in a browser.

## Web Secure Socket Setup

This section assumes that you have already configured a reverse proxy and have set it up to work over https. If not, head over to [the reverse proxy section](#reverse-proxy-configuration) to configure it.

We strongly recommend node operators to configure secure web sockets on their nodes. This will provide clients a more secure way to connect to your node.

You can read more about *Secure Socket Layer* (SSL) in [here](https://www.geeksforgeeks.org/secure-socket-layer-ssl/).

Remember that there may be some unique variables and customization depending on the way your reverse proxy is setup which you may have to adjust when configuring WSS to ensure correct functionality.

To see description of used variables (noted in `<>` brackets), visit [Variables & Paramteres](https://nymtech.net/docs/operators/variables.html) page.

#### Firewall configuration

Make sure to open all [needed ports](../../preliminary-steps/vps-setup.mdx#configure-your-firewall), adding your `<ANNOUNCE_WSS_PORT>`:

```sh
ufw allow <WSS_PORT>/tcp

# for example
# ufw allow 9001/tcp
```

#### WSS configuration

This section assumes that you have already configured a reverse proxy and have set it up to work over https. If not, head over to [the reverse proxy section](#reverse-proxy) to configure it.

###### 1. Create a new Nginx configuration file called `/etc/nginx/sites-available/wss-config-nym`

- Open text editor
```sh
nano /etc/nginx/sites-available/wss-config-nym
```
- Paste the block below. Don't forget to insert your correct values.

```ini
#############################################################
# EXCHANGE ALL <HOSTNAME> & <ANNOUNCE_WSS_PORT> VARIABLES ! #
#############################################################

server {
    listen <ANNOUNCE_WSS_PORT> ssl http2;
    listen [::]:<ANNOUNCE_WSS_PORT> ssl http2;

    server_name <HOSTNAME>;

    ssl_certificate /etc/letsencrypt/live/<HOSTNAME>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<HOSTNAME>/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # Ignore favicon requests
    location /favicon.ico {
        return 204;
        access_log     off;
        log_not_found  off;
    }

    location / {

        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD';
        add_header 'Access-Control-Allow-Headers' '*';

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Forwarded-For $remote_addr;

        proxy_pass http://localhost:9000;
        proxy_intercept_errors on;
    }
}
```

###### 2. Activate and test Nginx WSS configuration

- Create a symlink to `/etc/nginx/sites-enabled`:
```sh
ln -s /etc/nginx/sites-available/wss-config-nym /etc/nginx/sites-enabled
```

- Test your configuration syntax:
```sh
nginx -t
```

###### 3. Restart `nginx`
```sh
systemctl restart nginx
```

###### 4. Finally, configure your `nym-node` to announce the port and hostname of your WSS and restart the node

- Open your node configuration file located at `~/.nym/nym-nodes/<ID>/config/config.toml`
```sh
nano ~/.nym/nym-nodes/<ID>/config/config.toml
```

- And change the values of `announce_wss_port` in the `[entry_gateway]` and `hostname` in the `[host]` section:

```toml
announce_wss_port =  <ANNOUNCE_WSS_PORT>

# example
# announce_wss_port = 9001

hostname = '<HOSTNAME>'

# example
# hostname = 'exit-gateway1.squad.nsl'
```

- Restart your `nym-node`
```sh
systemctl daemon-reload && service nym-node restart
```

Your `nym-node` should be configured to run over WSS now. Test it using the steps in the chapter [below](#test-wss-setup).

### Test WSS Setup

You can do a few quick checks to test that your installation worked out and your `nym-node` is running correctly using WSS:

- Check out connection with `wscat` from another (local) machine:
```sh
# install
sudo apt install node-ws

# run
wscat -c wss://<HOSTNAME>:<WSS_PORT>
```

- Check Swagger API of your node using the hostname: `https://<HOSTNAME>/api/v1/swagger/#/`

## Troubleshooting

In some cases Nginx may cache expired certificates, old configurations and other snippets creating confussion in a proper routing of your server. To purge this cache you can run:
```sh
apt purge nginx nginx-common
apt install nginx
service nginx reload && service nginx restart
```
This will pickup only the current configuration.

---
title: Bonding Nym Node
url: https://nym.com/docs/operators/nodes/nym-node/bonding
---

# Bonding Nym Node

To you unbond your Nym Node means you are leaving Nym network and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**.

Nym Mixnet operators are rewarded for their work every epoch (60 minutes). To prevent centralisation, [Nym API](../validator-setup/nym-api.mdx) is ran by distributed validators on Nyx blockchain.

You are asked to `sign` a transaction and bond your node to Nyx blockchain so that the Mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks.

**Before you bond your `nym-node` make sure you went through all the previous steps**

1. [Build](../../binaries/building-nym.mdx) or [download](../../binaries/pre-built-binaries.mdx) `nym-node` binary
2. [Configure VPS]( ../preliminary-steps/vps-setup.mdx) correctly
3. [Prepare Nym wallet](../preliminary-steps/wallet-preparation.mdx)
4. [Setup & Run](setup.mdx) the node
5. [Configure your node](configuration.mdx)

Do not bond your node to the API if the previous steps weren't finished. Bad connectivity, closed ports, or other poor setup will result in your node getting blacklisted.

Any new bonded node will provide only the bare minimum information: host, identity key and optionally custom port of its HTTP API - we highly recommend to set that one up to `8080`. Everything else will be discovered via the self-described API for maximum flexibility. This also includes the sphinx key, meaning if the API is not exposed, the node will be unable to route any traffic.

**Every operator has to make sure that their nodes [self-described endpoint works](/operators/performance-and-testing#functionality--performance-check), otherwise the node will be un-routable and thus won't get any rewards!**

**Reveal your menominc phrase only in areas out of surveillance of other people and never share it with others. Nym team will never ask you for your mnemonic phrase - in case you were asked by someone it's a scam, do *not* reply to it!**

## Bond via the Desktop wallet (recommended)

You can bond your `nym-node` via the Desktop wallet. Nym wallet, just like any Nym binary can be downloaded, verified and made executable following [these simple steps](../../binaries/pre-built-binaries#setup-binaries).

###### 1. Insert bonding information

- Open your wallet, and head to the `Bonding` page and click on `Bond` Button, and input your node details. Press `Next`.
- To find out your `nym-node` details, run this command in your VPS:
```sh
./nym-node bonding-information --id <ID>
```
- To get a correct host address, run this command in your VPS
```sh
echo "$(curl -4 https://ifconfig.me)"
```

###### 2. Bond to correct HTTP port

- In your wallet: Open the box called `Show advanced options` and make sure that your `Custom HTTP port` is set correctly like in your `config.toml`. **We strongly recommend to keep it on default `8080`.** For reference these are the ports used by `nym-node`:

| Node type              | Port name                           | Correct port value |
| :--                    | :--                                 | :--                |
| Mixnode                | Mix port                            | `1789`             |
| Mixnode                | Verloc port                         | `1790`             |
| Mixnode                | HTTP api port (picture below)       | `8080`             |
| Gateway (entry & exit) | Mix port                            | `1789`             |
| Gateway (entry & exit) | Client WS API port                  | `9000`             |

- Use own `ID_KEY`, and `Host`, which can be either your IPv4 address or hostname:

![](/images/operators/wallet-screenshots/bonding_nym-node.png)

###### 3. Enter your values and sign with your node

- Enter the `Amount`, `Operating cost` and `Profit margin` and press `Next`

If you are part of [Nym Delegation Program](https://delegations.explorenym.net) or Service Grants Program, make sure your values are within the [rules](https://forum.nym.com/t/nym-delegations-program-update/466) of the programs. Operators setting up larger OP or PM than defined in the rules will be excluded from the program without prior warning!

- You will be asked to run a `sign` command with your `nym-node` - copy and paste the long signature as the value of `--contract-msg` and sing it on your VPS:

```sh
./nym-node sign --id <ID> --contract-msg <PAYLOAD_GENERATED_BY_THE_WALLET>
```

- Copy the resulting signature string and paste it into the wallet nodal, press `Next` and confirm the transaction:

```sh
# This is just an example, copy the one from your process
>>> The base58-encoded signature is:
2bbDJSmSo9r9qdamTNygY297nQTVRyQaxXURuomVcRd7EvG9oEC8uW8fvZZYnDeeC9iWyG9mAbX2K8rWEAxZBro1
```

![Paste Signature](/images/operators/wallet-screenshots/wallet-sign.png)

*This image is just an example, copy-paste your own base58-encoded signature*

Your node will now be bonded and ready to receive traffic, latest at the beginning of the next epoch (at most 1 hour).

If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which environment you're running.

**After migration to `nym-node` in Mixnet smart contract, many explorers, includyng Nym explorers will not pick up value correctly. While we are working on Nym Explorer v2, we would like to invite operators to use [Nym Harbourmaster](https://harbourmaster.nymtech.net) to track their nodes.**

## Change Settings via Desktop Wallet

In case you decide to change any settings like `custom HTTP port` or your `host` from an IP address to a hostname, don't forget to announce it to the API via changing these values in the desktop wallet.

- Go back to `Bonding` page, click on `Nym Node Settings` and change the values like in this example:

![](/images/operators/wallet-screenshots/settings_nym-node.png)

## Migrate to `nym-node` in Mixnet Smart Contract

From `nym-wallet` version `1.2.15` onward the application allows and prompts operators to migrate their gateway or mixnode to a `nym-node` in the Mixnet smart contract - an important step in [project smoosh](../../archive/faq/smoosh-faq.mdx). To do so follow these steps:

###### 1. Download the latest wallet from [the release page](https://github.com/nymtech/nym/releases), verify and make executable

Nym wallet, just like any Nym binary can be downloaded, verified and made executable following [these simple steps](../../binaries/pre-built-binaries#setup-binaries).

###### 2. Open the wallet and sign in

###### 3. Migrate!

- Go to Bonding and you will be prompted with such message:

![](/images/operators/wallet-screenshots/migrate_nym-node.png)

- In case you for some reason didn't see the prompt or you closed it - you can click in the upper right corner of the same window on this button:

![](/images/operators/wallet-screenshots/migrate_nym-node2.png)

- Confirm the transaction

###### 5. Welcome to new episode of `nym-node`!

</ Steps>

Versions older than `nym-wallet v 1.2.15` will not allow bonding new nodes.

## Bond via the CLI (power users)

If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](../../../developers/tools/nym-cli/usage#usage) docs.

## Fund `nym-node` Client Nyx Account

This is not relevant for operators running exclusively `mixnode` functionality. For any type of gateway functionality this is a preparation requirement for the upcoming [ticket rewarding](../../tokenomics/mixnet-rewards#roadmap).
</ Callout>

Every `nym-node` client contains a mnemonic of a Nyx account, generated with node initialisation (first `run` command creating all configuration and data files). This mnemonic is located in `$HOME/.nym/nym-nodes/<ID>/data/cosmos_mnemonic`. **This is *not* the same account as the one used for bonding!**

This client account will be used for the process of redemption of [zk-nym tickets](../../../network/cryptography/zk-nym) collected by nodes running as `entry-gateway` and `exit-gateway` as the redemption requires gateway to create a multisig proposal on the chain for which the client (node) needs to pay transaction fee.

Giving the low transaction cost on Cosmos, funding your client Nyx account with 25 NYM tokens should be more than enough. To do so, follow these steps:

###### 1. Get your `nym-node` client Nyx account mnemonic phrase
- Make sure your screen is not exposed to other people or recording devices
- To store sensitive credentials use audited and open source password managers, like [KeePassXC](https://keepassxc.org/)
- To print out your node client mnemonic phrase, run:
```sh
cat $HOME/.nym/nym-nodes/<ID>/data/cosmos_mnemonic
```
```sh
# for example
# cat $HOME/.nym/nym-nodes/default-nym-node/data/cosmos_mnemonic
```
- **Alternatively:** You can use `scp` command to copy the file `cosmos_mnemonic` remotely. If this is your preference, use this command:
```sh
scp <USER>@<HOST>:.nym/nym-nodes/<ID>/data/cosmos_mnemonic <LOCAL_TARGET_PATH>
```
- Copy this phrase and save it to your password manager

###### 2. Get the address of your client Nyx account using desktop wallet
- Open desktop wallet and choose to sign in with mnemonic
- Use the phrase from step 1
- Open `Receive` tab and copy Nym account address
- We recommend operators to store this address for future funding

###### 3. Fund the client Nyx account
- Open wallet with Nym tokens and send a minimum of 25 NYM to the address copied in the previous step
- In case you don't have any spare NYM, you can send tokens from any exchange directly to the address copied in the previous step
</ Steps>

Now your `nym-node` client can use inbuilt Nyx account to create a multisig proposal on chain and redeem user tickets.

---
title: Validators
url: https://nym.com/docs/operators/nodes/validator-setup
---

# Validators

> Nym has two main codebases:
> - the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code except for the validators.
> - the [Nym validators](https://github.com/nymtech/nyxd), written in Go & maintained as fork of [wasmd](https://github.com/CosmWasm/wasmd)

The validator is a Go application which implements it's functionalities using [Cosmos SDK](https://docs.cosmos.network). The underlying state-replication engine is powered by [CometBFT](https://cometbft.com/), where the consensus mechanism is based on the [Tendermint Consensus Algorithm](https://arxiv.org/abs/1807.04938). Finally, a [CosmWasm](https://cosmwasm.com) smart contract module controls crucial mixnet functionalities like decentralised directory service, node bonding, and delegated mixnet staking.

At present, our mainnet operates with a select group of reputed validators. We are not accepting new validators at this time. Any updates or changes to this policy will be promptly announced.

## Building your validator

### Prerequisites

Start with installing prerequisites needed for validator to work. Run following commands with root permissions or `sudo` prefix.

###### 1. Install `git`, `gcc`, `jq`

* Debian-based systems:
```sh
apt install git build-essential jq
```

* optional additional manual pages can be installed with:
```sh
apt-get install manpages-dev
```

* Arch-based systems:
Install `git`, `gcc` and `jq` with the following:
```
pacman -S git gcc jq
```

###### 2. Install `Go` language

`Go` can be installed via the following commands (taken from the [Go Download and install page](https://go.dev/doc/install)):

- First remove any existing old Go installation and extract the archive you just downloaded into /usr/local:

```sh
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.11.linux-amd64.tar.gz
```

- Then add /usr/local/go/bin to the PATH environment variable
```sh
export PATH=$PATH:/usr/local/go/bin
source $HOME/.profile
```

- Verify `Go` is installed with:

```sh
go version
```

- Should return something like:
```sh
go version go1.23.11 linux/amd64
```

### Download a precompiled validator binary

You can find pre-compiled binaries for Ubuntu `22.04` and `24.04` [here](https://github.com/nymtech/nyxd/releases).

### Manually compiling your validator binary

The codebase for the Nyx validators can be found [here](https://github.com/nymtech/nyxd).

The validator binary can be compiled by running the following commands:
```sh
git clone https://github.com/nymtech/nyxd.git
cd nyxd

# Make sure to check releases for the latest version information
git checkout release/<NYXD_VERSION>

# Build the binaries
make build
```
At this point, you will have a copy of the `nyxd` binary in your `build/` directory. Test that it's compiled properly by running:

```sh
./build/nyxd
```

You should see a similar help menu printed to you:

```sh
Nyx Daemon (server)

Usage:
  nyxd [command]

Available Commands:
  comet       CometBFT subcommands
  completion  Generate the autocompletion script for the specified shell
  config      Utilities for managing application configuration
  debug       Tool for helping with debugging your application
  export      Export state to JSON
  genesis     Application's genesis-related subcommands
  help        Help about any command
  init        Initialize private validator, p2p, genesis, and application configuration files
  keys        Manage your application's keys
  prune       Prune app history states by keeping the recent heights and deleting old heights
  query       Querying subcommands
  rollback    rollback Cosmos SDK and CometBFT state by one height
  snapshots   Manage local snapshots
  start       Run the full node
  status      Query remote node for status
  testnet     subcommands for starting or configuring local testnets
  tx          Transactions subcommands
  version     Print the application binary version information

Flags:
  -h, --help                help for nyxd
      --home string         directory for config and data (default "/Users/neo/.nyxd")
      --log_format string   The logging format (json|plain) (default "plain")
      --log_level string    The logging level (trace|debug|info|warn|error|fatal|panic|disabled or '*:<level>,<key>:<level>') (default "info")
      --log_no_color        Disable colored logs
      --trace               print out full stack trace on errors

Use "nyxd [command] --help" for more information about a command.
```

### Linking `nyxd` to `libwasmvm.so`

`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1` and above.

If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page.

If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.x86_64.so` file to correct location.

Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`.

### Adding `nyxd` to your `$PATH`
You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` or `~/.zshrc` file (depends on the terminal you use), and add that to our path. Replace `/home/<USER>/<PATH-TO-NYM>/binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder:

```sh
NYX_BINARIES=<PATH>/<BINARY>
```
- If you are using another shell like zsh replace '.bashrc' with the relevant config file

```sh
echo 'export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:'NYX_BINARIES >> ~/.bashrc
echo 'export PATH=$PATH:'${NYX_BINARIES} >> ~/.bashrc
source ~/.bashrc
```

- Test everything worked:

```sh
nyxd
```

- This should return the regular help menu:

```sh
Nyx Daemon (server)

Usage:
  nyxd [command]

Available Commands:
  comet       CometBFT subcommands
  completion  Generate the autocompletion script for the specified shell
  config      Utilities for managing application configuration
  debug       Tool for helping with debugging your application
  export      Export state to JSON
  genesis     Application's genesis-related subcommands
  help        Help about any command
  init        Initialize private validator, p2p, genesis, and application configuration files
  keys        Manage your application's keys
  prune       Prune app history states by keeping the recent heights and deleting old heights
  query       Querying subcommands
  rollback    rollback Cosmos SDK and CometBFT state by one height
  snapshots   Manage local snapshots
  start       Run the full node
  status      Query remote node for status
  testnet     subcommands for starting or configuring local testnets
  tx          Transactions subcommands
  version     Print the application binary version information

Flags:
  -h, --help                help for nyxd
      --home string         directory for config and data (default "/Users/neo/.nyxd")
      --log_format string   The logging format (json|plain) (default "plain")
      --log_level string    The logging level (trace|debug|info|warn|error|fatal|panic|disabled or '*:<level>,<key>:<level>') (default "info")
      --log_no_color        Disable colored logs
      --trace               print out full stack trace on errors

Use "nyxd [command] --help" for more information about a command.
```

## Initialising your validator

### Prerequisites:

- FQDN Domain name
- IPv4 and IPv6 connectivity

Choose a name for your validator and use it in place of `<ID>` in the following command:

```sh
# Mainnet
nyxd init <ID> --chain-id=nyx

# Sandbox testnet
nyxd init <ID> --chain-id=sandbox
```

`init` generates `priv_validator_key.json` and `node_key.json`.

If you have already set up a validator on a network, **make sure to back up the key located at**
`~/.nyxd/config/priv_validator_key.json`.

If you don't save the validator key, then it can't sign blocks and will be jailed all the time, and
there is no way to deterministically (re)generate this key.

At this point, you have a new validator, with its own genesis file located at `$HOME/.nyxd/config/genesis.json`. You will need to replace the contents of that file that with either the Nyx Mainnet or Sandbox Testnet genesis file.

You can use the following command to download them for the correct network:

```sh
# Mainnet
wget  -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json

# Sandbox testnet
curl https://rpc.sandbox.nymtech.net/genesis | jq '.result.genesis' > $HOME/.nyxd/config/genesis.json
```

### `config.toml` configuration

Edit the following config options in `$HOME/.nyxd/config/config.toml` to match the information below for your network:

- Mainnet:
```sh
persistent_peers = "ee03a6777fb76a2efd0106c3769daaa064a3fcb5@51.79.21.187:26656"
laddr = "tcp://0.0.0.0:26656"
```

- Sandbox testnet:
```sh
cors_allowed_origins = ["*"]
persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@:3.72.19.120:26656"
laddr = "tcp://0.0.0.0:26656"
```

These affect the following:

* `persistent_peers = "<PEER_ADDRESS>@<DOMAIN>.nymtech.net:26666"` allows your validator to start pulling blocks from other validators. **The main sandbox validator listens on `26666` instead of the default `26656` for debugging**. It is recommended you do not change your port from `26656`.
* `laddr = "tcp://0.0.0.0:26656"` is in your p2p configuration options

Optionally, if you want to enable [Prometheus](https://prometheus.io/) metrics then the following must also match in the `config.toml`:

- `prometheus = true`
- `prometheus_listen_addr = ":26660"`

> Remember to enable metrics in the 'Configuring Prometheus metrics' section below as well.

And if you wish to add a human-readable moniker to your node:

- `moniker = "<YOUR_VALIDATOR_NAME>"`

Finally, if you plan on using [Cockpit](https://cockpit-project.org/documentation.html) on your server, change the `grpc` port from `9090` as this is the port used by Cockpit.

### `app.toml` configuration
In the file `$HOME/.nyxd/config/app.toml`, set the following values:

- Mainnet
```sh
minimum-gas-prices = "0.025unym,0.025unyx"
```

- Sandbox testnet:
```sh
minimum-gas-prices = "0.025unym,0.025unyx"
```

### Setting up your validator's admin user
You'll need an admin account to be in charge of your validator. Set that up with:

```sh
nyxd keys add nyxd-admin
```

Cosmos SDK offers multiple backends for securing your keys. Please refer to the Cosmos SDK [docs on available keyring backends](https://docs.cosmos.network/sdk/v0.47/user/run-node/keyring#available-backends-for-the-keyring) to learn more

While using the default settings, this will add keys for your account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**.

You can get the current account address with:

```sh
nyxd keys show nyxd-admin -a
```

Type in your keychain **password**, not the mnemonic, when asked.

## Starting your validator

Everything should now be ready to go. You've got the validator set up, all changes made in `config.toml` and `app.toml`, the Nym genesis file copied into place (replacing the initial auto-generated one). Now let's validate the whole setup:

```sh
nyxd validate-genesis
```

If this check passes, you should receive the following output:

```sh
File at /path/to/genesis.json is a valid genesis file
```

> If this test did not pass, check that you have replaced the contents of `/<PATH>/.nyxd/config/genesis.json` with that of the correct genesis file.

### Setting up nyxd as full node (non-signing)

Skip this section if you're planning to run a validator node to join network consensus. To ensure security & maximum availability of validators, do not expose additional services to the Internet

Unlike signing validators, full nodes do not propose / sign blocks. A full node is typically used for indexing blocks produced on the chain and for exposing web interfaces such as RPC, API and gRPC endpoints required for external applications/services to interact with the blockchain.

By default, API server is disabled and RPC/gRPC servers listen to the loopback address only. In a production setup, it is recommended to use a webserver such as Nginx or caddy to proxy requests to the endpoints as required.

To enable Cosmos REST API, you can enable it in `$HOME/.nyxd/config/app.toml` like :

```toml
[api]

# Enable defines if the API server should be enabled. Toggle this to `true`
enable = true

# Swagger defines if swagger documentation should automatically be registered.
# You can also expose swagger documentation by toggling the below configuration to true
swagger = true
```

For more information on enabling access to various endpoints via Nginx, refer to the [example configuration here](./maintenance.md#setup)

### Open firewall ports

Before starting the validator, we will need to open the firewall ports:

```sh
# if ufw is not already installed:
sudo apt install ufw
sudo ufw enable

# Customise according to your port bindings. This is only for reference
# 26656 : p2p gossip port
# 26660: If prometheus is enabled
# 22 : Default SSH port
sudo ufw allow 26656,26660,22

## !! FOR FULL NODES ONLY !! - exposing Nginx for serving web requests
sudo ufw allow 80,443

# to check everything worked
sudo ufw status
```

For more information about your validator's port configuration, check the [validator port reference table](./maintenance.md#ports) below. These can be customised in `app.toml` and `config.toml` files.

> If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well.

Start the validator:

```sh
nyxd start
```

Once your validator starts, it will start requesting blocks from other validators. This may take several hours. Once it's up to date, you can issue a request to join the validator set with the command below.

### Syncing from a snapshot
If you wish to sync from a snapshot on **mainnet** use Polkachu's [mainnet](https://polkachu.com/networks/nym) resources.

If you wish to sync from a snapshot on **Sandbox testnet** use the below commands, which are a modified version of Polkachu's excellent resources. These commands assume you are running an OS with `apt` as the package manager:

```sh
# install lz4 if necessary
sudo apt install snapd -y
sudo snap install lz4

# download the snapshot
wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://rpc.sandbox.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4

# reset your validator state
nyxd tendermint unsafe-reset-all

# unpack the snapshot
lz4 -c -d nyxd-sandbox-snapshot-data.tar.lz4 | tar -x -C $HOME/.nyxd
```

You can then restart `nyxd` - it should start syncing from a block > 2000000.

### Joining Consensus

You can skip this section if you are planning to run a full-node. This step will make your node a signing validator which joins network consensus

Once your validator has synced and you have received tokens, you can join consensus and produce blocks.

- Mainnet:
```sh
nyxd tx staking create-validator
  --amount=<10000000unyx>
  --pubkey=$(/home/<USER>/<PATH-TO>/nyxd/binaries/nyxd tendermint show-validator)
  --moniker="<YOUR_VALIDATOR_NAME>"
  --chain-id=nyx
  --commission-rate="0.10"
  --commission-max-rate="0.20"
  --commission-max-change-rate="0.01"
  --min-self-delegation="1"
  --gas="auto"
  --gas-adjustment=1.15
  --gas-prices=0.025unyx
  --from=<"KEYRING_NAME">
  --node=https://rpc.nymtech.net:443
```

- Sandbox Testnet:
```sh
nyxd tx staking create-validator
  --amount=<10000000unyx>
  --pubkey=$(/home/<USER>/<PATH-TO>/nym/binaries/nyxd tendermint show-validator)
  --moniker="<YOUR_VALIDATOR_NAME>"
  --chain-id=sandbox
  --commission-rate="0.10"
  --commission-max-rate="0.20"
  --commission-max-change-rate="0.01"
  --min-self-delegation="1"
  --gas="auto"
  --gas-adjustment=1.15
  --gas-prices=0.025unyx
  --from=<"KEYRING_NAME">
  --node https://rpc.sandbox.nymtech.net:443
```

You'll need Nyx tokens on mainnet / sandbox to perform the above tasks.

If you want to edit some details for your node you will use a command like this:

- Mainnet:
```sh
nyxd tx staking edit-validator
  --chain-id=nyx
  --moniker="<YOUR_VALIDATOR_NAME>"
  --details="Nyx validator"
  --security-contact="<YOUR_EMAIL>"
  --identity="<YOUR_IDENTITY>"
  --gas="auto"
  --gas-adjustment=1.15
  --gas-prices=0.025unyx
  --from="KEYRING_NAME"
```

- Sandbox testnet
```sh
nyxd tx staking edit-validator
  --chain-id=sandbox
  --moniker="<YOUR_VALIDATOR_NAME>"
  --details="Sandbox testnet validator"
  --security-contact="your email"
  --identity="<YOUR_IDENTITY>"
  --gas="auto"
  --gas-adjustment=1.15
  --gas-prices=0.025unyx
  --from="KEYRING_NAME"
```

With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact.

### Automating your validator with systemd
You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md#systemd) with a quick tutorial.

### Setting the ulimit

Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](./maintenance.md#Setting-the-ulimit) to change the `ulimit` value for validators.

## Using your validator
### Un-jailing your validator
If your validator gets jailed, you can fix it with the following command:

- Mainnet:
```sh
nyxd tx slashing unjail
  --broadcast-mode=block
  --from="KEYRING_NAME"
  --chain-id=nyx
  --gas=auto
  --gas-adjustment=1.5
  --gas-prices=0.025unyx
```

- Sandbox Testnet:
```sh
nyxd tx slashing unjail
  --broadcast-mode=block
  --from="KEYRING_NAME"
  --chain-id=sandbox
  --gas=auto
  --gas-adjustment=1.5
  --gas-prices=0.025unyx
```

### Upgrading your validator

To upgrade your validator, follow the steps on the [maintenance page](./maintenance.md#setting-the-ulimit).

#### Common reasons for your validator being jailed

Your validator will be jailed if your node:
 - misses _`x`_ amount of blocks in _`y`_ interval, where _`x`_ and _`y`_ are parameters set by chain governance
 - performs double signing (two conflicting signatures on the same block using the same key)

Double signing is a serious infraction. If a node double signs, all the delegators to the node (including self-delegation) will be slashed by 5%. Additionally, the node will be permanently jailed and removed from consensus (called _tombstoning_)

One of the most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.

Running the command `df -H` will return the size of the various partitions of your VPS. If the partition with blockchain data is almost full, try pruning the blockchain data or expanding the storage size.

### Day 2 operations with your validator

You can check your current balances with:

```sh
nyxd query bank balances ${ADDRESS}
```

For example, on the Sandbox testnet this would return:

```yaml
balances:
- amount: "919376"
denom: unym
pagination:
next_key: null
total: "0"
```

You can, of course, stake back the available balance to your validator with the following command.

> **Remember to save some tokens for gas costs!**

- Mainnet:
```sh
nyxd tx staking delegate VALOPERADDRESS AMOUNTunyx
  --from="KEYRING_NAME"
  --keyring-backend=os
  --chain-id=nyx
  --gas="auto"
  --gas-adjustment=1.15
  --gas-prices=0.025unyx
```

- Sandbox Testnet:
```sh
nyxd tx staking delegate VALOPERADDRESS AMOUNTunyx
  --from="KEYRING_NAME"
  --keyring-backend=os
  --chain-id=sandbox
  --gas="auto"
  --gas-adjustment=1.15
  --gas-prices=0.025unyx
```

---
title: Nym API Setup
url: https://nym.com/docs/operators/nodes/validator-setup/nym-api
---

# Nym API Setup

> The nym-api binary was built in the [building nym](../../binaries/building-nym.mdx) section. If you haven't yet built Nym and want to run the code, go there first. You can build just the API with `cargo build --release --bin nym-api`.

## What is the Nym API?

The Nym API is a binary that will be operated by the Nyx validator set. This binary can be run in several different modes, and has two main bits of functionality:

* Network monitoring (calculating the routing score of Mixnet nodes)
* Generation and validation of [zk-nyms](../../../network/cryptography/zk-nym), our implementation of the Coconut Selective Disclosure Credential Scheme.

This is important for both the proper decentralisation of the network uptime calculation and, more pressingly, enabling the NymVPN to utilise privacy preserving payments.

The process of enabling these different aspects of the system will take time. At the moment, Nym API operators will only have to run the binary in a minimal 'caching' mode in order to get used to maintaining an additional process running alongside a full node.

It is highly recommended to run `nym-api` alongside a full node and NOT a validator node, since you will be exposing HTTP port(s) to the Internet. We also observed degradation in p2p and block signing operations when `nym-api` was run alongside a signing validator.

### Rewards

Operators of Nym API will be rewarded for performing the extra work of taking part in credential generation. These rewards will be calculated **separately** from rewards for block production.

Rewards for credential signing will be calculated hourly, with API operators receiving a proportional amount of the reward pool (333NYM per hour / 237,600 NYM per month), proportional to the percentage of credentials they have signed.

### Hardware Requirements

The specification mentioned below is for running a full node alongside the nym-api. It is recommended to run `nym-api` and a full Nyx node on the same machine for optimum performance.

Bear in mind that credential signing is primarily CPU-bound, so choose the fastest CPU available to you.

#### Minimum Requirements

| Hardware | Minimum Specification                      |
|----------|--------------------------------------------|
| CPU      | 8-cores, 2.8GHz base clock speed or higher |
| RAM      | 16GB DDR4+                                 |
| Disk     | 500 GiB+ NVMe SSD                          |

#### Recommended Requirements

| Hardware | Minimum Specification                       |
|----------|---------------------------------------------|
| CPU      | 16-cores, 2.8GHz base clock speed or higher |
| RAM      | 32GB DDR4+                                  |
| Disk     | 1 TiB+ NVMe SSD                             |

### Full node configuration

To install a full node from scratch, refer to the [validator setup guide](../validator-setup.mdx) and follow the steps outlined there.

Additionally, to ensure `nym-api` works as expected, ensure the configuration is as below:

1. ###### Ensure transaction index is turned on in your `config.toml`:

```toml
[tx_index]

# Ensure that this is not set to "null". You're free to use any indexer

indexer = "kv"
```

2. ###### Ensure pruning settings are manually configured

`nym-api` needs to check validity of user-submitted transactions (in the past) while issuing credentials and as part of double-spend check. Hence, aggressively pruning data will lead to errors with your `nym-api`

Make sure your pruning settings are configured as below in `app.toml`:

```toml
pruning = "custom"

# This number is likely to be updated once zk-nym signing goes live
pruning-keep-recent = "750000"
pruning-interval = "100"
```

The example value of `100` for `pruning-interval` can be customised as per your requirement.

### Credential Generation

Validators that took part in the DKG ceremony became part of the 'quorum' generating and verifying zk-nym credentials. These will initially be used for private proof of payment for NymVPN (more [here](https://nym.com/blog/invitation-for-privacy-experts-and-enthusiasts) and [here](https://nym.com/blog/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet), and in the future will be expanded into more general use-cases such as [offline ecash](https://arxiv.org/abs/2303.08221).

The DKG ceremony was used to create a subset of existing validators who run `nym-api` alongside a Nyx full-node. As outlined above, they are the ones taking part in the generation and verification of zk-nym credentials. The size of the 'minimum viable quorum' is 10 - the intial set taking part in DKG was 17 validators. This is in order to have some redundancy in the case of a validator dropping or going offline.

DKG ceremony in points:

* The deployment and initialisation of [`group`](https://github.com/nymtech/nym/tree/develop/contracts/multisig/cw4-group) and [`multisig`](https://github.com/nymtech/nym/tree/develop/contracts/multisig) contracts by Nym. Validators that are members of the `group` contract are the only ones that were able to take part in the ceremony.
* The deployment and initialisation of an instance of the [DKG contract](https://github.com/nymtech/nym/tree/develop/contracts/coconut-dkg) by Nym.
* Validators updated their `nym-api` configs with the address of the deployed contracts. They  also stopped running their API instance in caching only mode, instead switching over run with the `--enabled-credentials-mode`.
* From the perspective of validator operators, this is all they had to do. Under the hood, each `nym-api` instance then took part in several rounds of key submission, verification, and derivation. This will continue until quorum is acheived.

## Current version

## Setup and Usage

### Viewing command help
You can check that your binary is properly compiled with:

```bash
./nym-api --help
```

Which should return a list of all available commands.

You can also check the various arguments required for individual commands with:

```bash
./nym-api <COMMAND> --help
```

### Initialising your Nym API Instance in caching mode

Initialise your API instance with:

```bash
./nym-api init
```

You can optionally pass a local identifier for this instance with the `--id` flag. Otherwise the ID of your instance defaults to `default`.

### Enabling credential signing on your Nym API instance

To engage in the Distributed Key Generation (DKG) ceremony, it's essential to transition your `nym-api` instance from its default caching mode to the active credential signing mode. This section guides you through the process of enabling credential signing

#### Generate a new wallet

Begin by generating a new wallet address specifically for your instance to use in credential signing mode. Utilize the `nyxd` command-line tool with the following command:

```bash
nyxd keys add signer
```

It's critical to securely back up the mnemonic phrase generated during this process. This mnemonic is your key to recovering the wallet in the future, so store it in a secure, offline location.

#### Fund the address

Next, deposit NYM tokens into the newly created wallet address to ensure it can cover transaction fees incurred during the credential signing process. `nym-api` will not operate if the wallet's balance falls below 10 NYM tokens, displaying an error message upon startup.

We recommend beginning with an initial deposit of 100 NYM tokens and monitoring the balance regularly, topping it up as necessary to maintain operational readiness.

#### Update API configuration

With your new wallet ready and funded, proceed to update your `nym-api` configuration to enable credential signing:

Update your `config.toml` located in `$HOME/.nym/nym-api/foo/config/config.toml` as below:

Enable the coconut signer:

```toml
[coconut_signer]
# Specifies whether coconut signing protocol is enabled in this process.
enabled = true  # This was previously false
```

Set your announce address if it is empty. This is the URL you previously configured for your `nym-api` instance

```toml
# This is the address you previously configured for the nym-api
# Not to be confused with the Cosmos REST API URL
announce_address = 'https://nym-api.your.tld/'
```

Finally, input the mnemonic phrase generated during the wallet creation step into the mnemonic field

```toml
mnemonic = '<YOUR_MNEMONIC>'
```

After completing these steps, your `nym-api` instance is configured to participate in credential signing and the DKG ceremony.

### Running your Nym API Instance

The API binary currently defaults to running in caching mode. You can run your API with:

```bash
./nym-api run --id <ID>
```

By default the API will be trying to query your full node running locally on `localhost:26657`. If your node is hosted elsewhere, you can specify the RPC location by using the `--nyxd-validator ` flag on `run`:

```bash
./nym-api run --id <ID> --nyxd-validator https://rpc-nym.yourcorp.tld:443
```

You can also change the value of `local_validator` in the config file found by default in `$HOME/.nym/nym-api/<ID>/config/config.toml`.

This process is quite noisy, but informative:

```bash
Starting nym api...
 2023-12-12T14:29:55.800Z INFO  rocket::launch > 🔧 Configured for release.
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > address: 127.0.0.1
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > port: 8000
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > workers: 4
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > max blocking threads: 512
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > ident: Rocket
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > IP header: X-Real-IP
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > temp dir: /tmp
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > http/2: true
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > keep-alive: 5s
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > tls: disabled
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > log level: critical
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > cli colors: true
 2023-12-12T14:29:55.800Z INFO  rocket::launch    > 📬 Routes:
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_registered_names) GET /v1/names
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnodes) GET /v1/mixnodes
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_gateways) GET /v1/gateways
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_services) GET /v1/services
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /v1/openapi.json
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_full_circulating_supply) GET /v1/circulating-supply
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_current_epoch) GET /v1/epoch/current
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_active_set) GET /v1/mixnodes/active
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnodes_detailed) GET /v1/mixnodes/detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_rewarded_set) GET /v1/mixnodes/rewarded
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_gateways_described) GET /v1/gateways/described
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_interval_reward_params) GET /v1/epoch/reward_params
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_blacklisted_mixnodes) GET /v1/mixnodes/blacklisted
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_blacklisted_gateways) GET /v1/gateways/blacklisted
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_total_supply) GET /v1/circulating-supply/total-supply-value
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_circulating_supply) GET /v1/circulating-supply/circulating-supply-value
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_active_set_detailed) GET /v1/mixnodes/active/detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_rewarded_set_detailed) GET /v1/mixnodes/rewarded/detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /cors/<status>
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/index.css
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/index.html
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/swagger-ui.css
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/oauth2-redirect.html
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/swagger-ui-bundle.js
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/swagger-ui-config.json
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/swagger-initializer.js
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > GET /swagger/swagger-ui-standalone-preset.js
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnodes_detailed) GET /v1/status/mixnodes/detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnode_inclusion_probabilities) GET /v1/status/mixnodes/inclusion_probability
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnode_status) GET /v1/status/mixnode/<mix_id>/status
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_active_set_detailed) GET /v1/status/mixnodes/active/detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_rewarded_set_detailed) GET /v1/status/mixnodes/rewarded/detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnode_stake_saturation) GET /v1/status/mixnode/<mix_id>/stake-saturation
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (get_mixnode_inclusion_probability) GET /v1/status/mixnode/<mix_id>/inclusion-probability
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (network_details) GET /v1/network/details
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (nym_contracts) GET /v1/network/nym-contracts
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > (nym_contracts_detailed) GET /v1/network/nym-contracts-detailed
 2023-12-12T14:29:55.800Z INFO  rocket::launch    > 📡 Fairings:
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > Validator Cache Stage (ignite)
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > Circulating Supply Cache Stage (ignite)
 2023-12-12T14:29:55.800Z INFO  rocket::launch::_ > Shield (liftoff, response, singleton)
 2023-12-12T14:29:55.801Z INFO  rocket::launch::_ > CORS (ignite, request, response)
 2023-12-12T14:29:55.801Z INFO  rocket::launch::_ > Node Status Cache (ignite)
 2023-12-12T14:29:55.801Z INFO  rocket::shield::shield > 🛡️ Shield:
 2023-12-12T14:29:55.801Z INFO  rocket::shield::shield::_ > X-Content-Type-Options: nosniff
 2023-12-12T14:29:55.801Z INFO  rocket::shield::shield::_ > X-Frame-Options: SAMEORIGIN
 2023-12-12T14:29:55.801Z INFO  rocket::shield::shield::_ > Permissions-Policy: interest-cohort=()
 2023-12-12T14:29:55.801Z WARN  rocket::launch            > 🚀 Rocket has launched from http://127.0.0.1:8000
 2023-12-12T14:29:56.375Z INFO  nym_api::nym_contract_cache::cache::refresher > Updating validator cache. There are 888 mixnodes and 105 gateways
 2023-12-12T14:29:56.375Z INFO  nym_api::node_status_api::cache::refresher    > Updating node status cache
 2023-12-12T14:29:57.359Z INFO  nym_api::circulating_supply_api::cache        > Updating circulating supply cache
 2023-12-12T14:29:57.359Z INFO  nym_api::circulating_supply_api::cache        > the mixmining reserve is now 220198535489690unym
 2023-12-12T14:29:57.359Z INFO  nym_api::circulating_supply_api::cache        > the number of tokens still vesting is now 145054386857730unym
 2023-12-12T14:29:57.359Z INFO  nym_api::circulating_supply_api::cache        > the circulating supply is now 634747077652580unym
 2023-12-12T14:30:00.803Z INFO  nym_api::support::caching::refresher          > node-self-described-data-refresher: refreshing cache state
 2023-12-12T14:31:56.290Z INFO  nym_api::nym_contract_cache::cache::refresher > Updating validator cache. There are 888 mixnodes and 105 gateways
 2023-12-12T14:31:56.291Z INFO  nym_api::node_status_api::cache::refresher    > Updating node status cache
```

## Automation

You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](nyx-configuration.mdx#nym-api-systemd-automation) for an example `service` file.

You can also use `nymvisor` to automatically update the `nym-api` node. The steps to install Nymvisor can be found [here](../maintenance/nymvisor-upgrade.mdx).

## Exposing web endpoint using HTTPS
It is recommended to expose the webserver over HTTPS by using a webserver like Nginx. An example configuration for configuring Nginx is listed on [Reverse proxy page](../nym-node/configuration/proxy-configuration.mdx). If you're using a custom solution, ensure to allow requests from anywhere by setting a permissive CORS policy.

For example, it is configured in Nginx using: `add_header 'Access-Control-Allow-Origin' '*';`

---
title: Nyx Validator & Nym API Configuration
url: https://nym.com/docs/operators/nodes/validator-setup/nyx-configuration
---

# Nyx Validator & Nym API Configuration

## Automation

### Validator `systemd` Automation

To automate with `systemd` use this init service file by saving it as `/etc/systemd/system/nymd.service` and follow the steps below running all commands with root permissions (root shell or `sudo` prefix).

###### 1. Create an init service file

- Open text editor

```sh
nano /etc/systemd/system/nymd.service
```

- Paste this file
```ini
[Unit]
Description=Nyxd
StartLimitInterval=350
StartLimitBurst=10

[Service]
User=<USER>                          # change to your user
Type=simple
Environment="LD_LIBRARY_PATH=<PATH>" # change to correct path
ExecStart=<PATH>/nymd start          # change to correct path
Restart=on-failure
RestartSec=30
LimitNOFILE=infinity

[Install]
WantedBy=multi-user.target
```

###### 2. Start validator as `systemd` service

- To pick up new unit file, run:

```sh
systemctl daemon-reload
```

- Enable the service:

```sh
systemctl enable nymd
```

- Start the service:

```sh
systemctl start nymd
```

- Optionally you can monitor status logs by running:
```sh
journalctl -f -u nymd
```

###### 3. If you make any changes to your `systemd` script after you've enabled it

- You need to run:

```sh
systemctl daemon-reload
```

This lets your operating system know it's ok to reload the service configuration. Then restart your validator.

### Nym API `systemd` Automation

To automate with `systemd` use this init service file by saving it as `/etc/systemd/system/nym-api.service` and follow the steps below running all commands with root permissions (root shell or `sudo` prefix).

###### 1. Create an init service file

- Open text editor
```sh
nano /etc/systemd/system/nym-api.service
```

- Paste this file
```ini
[Unit]
Description=NymAPI
StartLimitInterval=350
StartLimitBurst=10

[Service]
User=<USER>                                # change to your user
Type=simple
ExecStart=<PATH>/nym-api start             # change to correct path
Restart=on-failure
RestartSec=30
LimitNOFILE=infinity

[Install]
WantedBy=multi-user.target
```
###### 2. Start your API as `systemd` service

- To pick up new unit file, run:
```sh
systemctl daemon-reload  # to pickup the new unit file
```

- Enable the service:
```sh
systemctl enable nym-api # to enable the service
```

- Start the service:
```sh
systemctl start nym-api  # to actually start the service
```

- Optionally you can monitor status logs by running:
```sh
journalctl -f -u nym-api # to monitor system logs showing the service start
```

**Note:** if you make any changes to your `systemd` script after you've enabled it, you will need to run:

```sh
systemctl daemon-reload
```

###### 3. If you make any changes to your `systemd` script after you've enabled it

- You need to run:

```sh
systemctl daemon-reload
```

This lets your operating system know it's ok to reload the service configuration. Then restart your API.

## Nym API (previously 'Validator API') endpoints

Numerous API endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer.

```sh
sudo ufw allow 'Nginx Full'
```

Check nginx is running via systemctl:

```sh
systemctl status nginx
```

Which should return:

```sh
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2018-04-20 16:08:19 UTC; 3 days ago
     Docs: man:nginx(8)
 Main PID: 2369 (nginx)
    Tasks: 2 (limit: 1153)
   CGroup: /system.slice/nginx.service
           ├─2369 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
           └─2380 nginx: worker process
```

## Full Node Configuration

Proxying various full node services through port 80 can then be done by creating a file with the following at `/etc/nginx/sites-enabled/nyxd-webrequests.conf`:

Setting up a reverse proxy using a webserver such as Nginx allows you to easily configure SSL certificates for the endpoints. When running on mainnet, it is recommended to encrypt all web traffic to your node.

```sh
### To expose RPC server
server {
  listen 80;
  listen [::]:80;
  server_name "<rpc.nyx.yourdomain.tld>";

  location / {
    proxy_pass http://127.0.0.1:26657;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location /websocket {
      proxy_pass http://127.0.0.1:26657;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
      proxy_set_header Host $host;
    }
}

### To expose Cosmos API server
server {
  server_name "<api.nyx.yourdomain.tld>";
  location / {
    proxy_pass http://127.0.0.1:1317;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade websocket;
    proxy_set_header Connection Upgrade;
  }
}

### To expose GRPC endpoint
server {
  server_name "<grpc.nyx.yourdomain.tld>";
  location / {
    grpc_pass 127.0.0.1:9090;
  }
}
```

## nym-api Configuration

```sh
### To expose nym-api webserver
server {
  listen 80;
  listen [::]:80;
  server_name "<nym-api.nyx.yourdomain.tld>";
  add_header 'Access-Control-Allow-Origin' '*';

  location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}
```

Followed by:

```sh
sudo apt install certbot nginx python3
certbot --nginx -m <EMAIL> --agree-tos
```

If using a VPS running Ubuntu 20: replace `certbot nginx python3` with `python3-certbot-nginx`

These commands will get you an https encrypted nginx proxy in front of the various endpoints.

## Configuring Prometheus metrics (optional)

Configure Prometheus with the following commands (adapted from NodesGuru's [Agoric setup guide](https://nodes.guru/agoric/setup-guide/en)):

```sh
echo 'export OTEL_EXPORTER_PROMETHEUS_PORT=9464' >> $HOME/.bashrc
source ~/.bashrc
sed -i '/\[telemetry\]/{:a;n;/enabled/s/false/true/;Ta}' $HOME/.nymd/config/app.toml
sed -i "s/prometheus-retention-time = 0/prometheus-retention-time = 60/g" $HOME/.nymd/config/app.toml
sudo ufw allow 9464
echo 'Metrics URL: http://'$(curl -s ifconfig.me)':26660/metrics'
```

Your validator's metrics will be available to you at the returned 'Metrics URL'.

```sh
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 6.7969e-05
go_gc_duration_seconds{quantile="0.25"} 7.864e-05
go_gc_duration_seconds{quantile="0.5"} 8.4591e-05
go_gc_duration_seconds{quantile="0.75"} 0.000115919
go_gc_duration_seconds{quantile="1"} 0.001137591
go_gc_duration_seconds_sum 0.356555301
go_gc_duration_seconds_count 2448
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 668
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.15.7"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 1.62622216e+08
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 2.09341707264e+11
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 5.612319e+06
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 2.828263344e+09
# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.
# TYPE go_memstats_gc_cpu_fraction gauge
go_memstats_gc_cpu_fraction 0.03357798610671518
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 1.3884192e+07
```

## Validator port reference

All validator-specific port configuration can be found in `$HOME/.nymd/config/config.toml`. If you do edit any port configs, remember to restart your validator.

| Default port | Use                                  |
|--------------|--------------------------------------|
| 1317         | REST API server endpoint             |
| 26656        | Listen for incoming peer connections |
| 26660        | Listen for Prometheus connections    |

---
title: Maintenance
url: https://nym.com/docs/operators/nodes/maintenance
---

# Maintenance

## Useful commands

* **`--no-banner`**: Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment.

* **`build-info`**: A `build-info` command prints the build information like commit hash, rust version, binary version just like what command `--version` does. However, you can also specify an `--output=json` flag that will format the whole output as a json, making it an order of magnitude easier to parse.

For example `./target/debug/nym-network-requester --no-banner build-info --output json` will return:
```json
{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"}
```

## Configure your firewall

Although your `nym-node` or `validator` (denoted as `<NODE>`) is now ready to receive traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`.

SSH to your server as `root` or become one running `sudo -i` or `su`. If you prefer to administrate your VPS from a user environment, supply the commands with prefix `sudo`.

###### 1. Start with setting up the essential tools on your server.

- Get your system up to date
```sh
apt update -y && apt --fix-broken install
```

- Install dependencies
```sh
apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git
```

- Double check ufw is installed correctly
```sh
apt install ufw --fix-missing
```

###### 2. Configure your firewall using Uncomplicated Firewall (UFW)

For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on the server. The following commands will allow you to set up a firewall using `ufw`.

- Check if you have `ufw` installed:
```sh
ufw version
```

- If it's not installed, install with:
```sh
apt install ufw -y
```

- Enable ufw
```sh
ufw enable
```

- Check the status of the firewall
```sh
ufw status
```

###### 3. Open all needed ports to have your firewall for `nym-node` working correctly

  <Tabs items={[
    <code>nym-node</code>,
    <code>validator</code>,
    ]} defaultIndex="0">
    <MyTab><PortsNymNode /></MyTab>
    <MyTab><PortsValidator /></MyTab>

- In case of reverse proxy setup add:
```sh
ufw allow 443/tcp
```

- Re-check the status of the firewall:
```sh
ufw status
```

For more information about your node's port configuration, check the [port reference table](#ports) below.

## Backup a node

Anything can happen to the server on which your node is running. To back up your `nym-node` keys and configuration protects the operators against the negative impact of unexpected events. To restart your node on another server, two essential pieces are needed:

1. **Node keys to initialise the same node on a new VPS**
2. **Access to the bonding Nyx account (wallet seeds) to update host on the Mixnet smart contract**

Optionally, it can be useful to have a backup your configuration directories to setup [reverse proxy and WSS](nym-node/configuration/proxy-configuration.mdx) quickly as well.

Assuming that everyone access their wallets from local machine and does *not* store their seeds on VPS, point \#2 should be a given.

Never store your mnemonic seed anywhere online nor do *not* share it with anyone!

To backup your `nym-node` keys and configuration in the easiest way possible, copy the entire config directory `.nym` from your VPS to your local machine, using a special copy command `scp`:

###### 1. Create a local directory where you want to store your backup
```sh
mkdir -pv <PATH_TO_TARGET_DIRECTORY>
```

```sh
# for example
# mkdir -pv $HOME/backup/my_nym_node/.nym
```

###### 2. Backup `clients.sqlite` database

- Install `sqlite3`
```sh
apt install sqlite3
```
- **Stop your node**
```sh
service nym-node stop
```
- Open sqlite CLI shell inside `clients.sqlite` database
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite
```
- Create backup called `clients_backup.sqlite`
```sh
.backup .nym/nym-nodes/default-nym-node/data/clients_backup.sqlite
```
- Exit sqlite CLI shell
```sh
.exit
```

###### 3. Copy configuration folder `.nym` from your VPS to your newly created backup directory

```sh
scp -r <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:~/.nym/nym-nodes/<ID> <PATH_TO_TARGET_DIRECTORY>
```

###### 4. Verify the success of the backup & start your node

The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the backup target directory.

- Start your node
```sh
service nym-node start && journalctl -u nym-node -f
```

Now you have everything needed to restore your `nym-node` on another server. If you are in a need of doing so, follow the steps in [*Restoring a node*](#restoring-a-node) chapter below.

### Backup proxy configuration

If you run your node behind a [reverse proxy and WSS](nym-node/configuration/proxy-configuration.mdx) (suggested for all Exit Gateways), you may find it useful to backup configuration directories for that as well. It's done by following the same logic, using `scp` command for remote copy:

Given that servers hosting a `nym-node` are expected to be a single purpose machines, we assume in this guide, that there are no other `<HOSTNAME>` sub-directories in `/var/www` and `/etc/nginx/sites-available` then the ones relevant to `nym-node`. In case you prefer to only backup configuration for a particular hostname, just append your `<HOSTNAME>` to the path in the commands below.
</ Callout>

###### 1. Create local sub-directories where you want to store your backup

```sh
mkdir -pv <PATH_TO_TARGET_DIRECTORY>
mkdir -pv <PATH_TO_TARGET_DIRECTORY>
```

```sh
# for example
# mkdir -pv $HOME/backup/my_nym_node/var/www
# mkdir -pv $HOME/backup/my_nym_node/etc/nginx/sites-available
```

###### 1. Backup `/var/www` directory

```sh
scp -r <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:/var/www <PATH_TO_TARGET_DIRECTORY>
```

###### 2. Backup `/etc/nginx/sites-available` directory

```sh
scp -r <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:/etc/nginx/sites-available <PATH_TO_TARGET_DIRECTORY>
```

###### 3. Verify the success of the backup

The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the backup target directory.

To copy files from the root directory (paths starting with `/`), you need root permissions on the remote machine. If your server is not running as the root user, the `scp` command won't work directly, as using the `sudo` prefix would apply to your local machine instead of the remote server.

To resolve this, you need to SSH into the remote server first, and there use the `sudo cp -r <SOURCE_PATH> <TARGET_PATH>` command to copy the necessary directories to a location outside the root directory. After that, you can run `scp` with the correct source path to transfer the files.

## Restoring a node

In case your VPS was terminated and you have a [backup](#backup-a-node) of your node keys and access to your [bonding](nym-node/bonding) wallet, you can easily restore your node on another server without losing your delegation.

###### 1. Prepare new VPS

SSH into your new VPS and start with:

- Do all [preliminary steps](preliminary-steps.mdx) needed to run a `nym-node`.

- Create a `.nym/nym-nodes` configuration folder:
```sh
mkdir -pv ~/.nym/nym-nodes
```

###### 2. Restore your node configuration

Copy the folder with your node configuration and keys from your local machine to the newly created folder on your VPS using `scp` command. Make sure to grab the entire `nym-node` configuration folder, which is called after your local `nym-node` identifier (`<ID>`), the `-r` (recursive) flag will take care of all sub-directories and their content:

```sh
scp -r <PATH_TO_LOCAL_NODE_CONFIGURATION_FOLDER> <VPS_USER_NAME>@<VPS_HOST_ADDRESS>:~/.nym/nym-nodes/
```
```sh
# for example:
scp -r $HOME/backup/my_nym_node/.nym/nym-nodes/default-nym-node root@my-nym-node:~/.nym/nym-nodes/
```

###### 3. Verify the success of the backup

The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the target directory `.nym/nym-nodes` on your VPS.

###### 4. Configure your node on the new VPS

* SSH to your VPS
* Run a command `echo "$(curl -4 https://ifconfig.me)"` to see your public IPv4
* Edit config file located at `~/.nym/nym-nodes/<ID>/config/config.toml` correct IP - it's the field under the header `[host]`, called `public_ips = [<PUBLIC_IPS>,]`
* Add your new location field `location = <LOCATION>`, (formats like: 'Jamaica', or two-letter alpha2 (e.g. 'JM'), three-letter alpha3 (e.g. 'JAM') or three-digit numeric-3 (e.g. '388') can be provided).

###### 5. Restore `clients.sqlite` database

- Install `sqlite3`
```sh
apt install sqlite3
```
- Open sqlite CLI shell inside `clients.sqlite` database
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite
```
- Restore your backup called `clients_backup.sqlite`
```sh
.restore .nym/nym-nodes/default-nym-node/data/clients_backup.sqlite
```
- Exit sqlite CLI shell
```sh
.exit
```
- Check integrity
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite "PRAGMA integrity_check;"
```
The result should return `ok` if the database is intact.

###### 6. Test & validate your setup
* Dry run the node and see if everything works.
* Setup the [systemd](nym-node/configuration.mdx#systemd) automation (don't forget to add the [terms and conditions flag](nym-node/setup.mdx#terms--conditions)) to `ExecStart` command, reload the daemon and run the service.

###### 4. Change the node smart contract info via the wallet interface

Open Nym Wallet, go to *Bonding*, open *Settings* and change *Host* value to the new `nym-node` IP address. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks, returning zero performance.

Everything should work now. If not, have a look through the `config.toml` file and ensure that there are no details from the past VPS, things like WSS port, landing page asset etc. If you had a configuration with reverse proxy and WSS, continue to set that up as well. If you had it backed up, you can follow the steps to [restore proxy configuration](#restore-proxy-configuration) below, or you can start to [configure proxy from scratch](nym-node/configuration/proxy-configuration.mdx).

### Restoring proxy configuration

If operators moving to a new server had their [proxy configuration backed up](#backup-proxy-configuration), it's possible to simply restore it, following these steps:

###### 1. Copy your backed up directory `/var/www` for landing page to the server
- Start setting up reverse proxy and WSS following [this guide](nym-node/configuration/proxy-configuration.mdx) but instead of creating a new `/var/www/<HOSTNAME>` directory, simply copy there the one from the old server, using `scp` command

```sh
scp -r <PATH_TO_LOCAL_WWW_CONFIGURATION_BACKUP> <VPS_USER_NAME>@<VPS_HOST_ADDRESS>:/var/www/
```
```sh
# for example:
scp -r $HOME/backup/my_nym_node/var/www root@my-nym-node:/var/www
```
###### 2. Make sure that domain is correctly setup
As you see in the guide you use a domain (same like your `<HOSTNAME>`), make sure you have it registered as and redirected to the new IP by logging into your DNS provider and editing the dashboard of the domain.

###### 3. Proceed with all needed `node` configuration
- In the guide follow the steps to [configure your node reverse proxy](nym-node/configuration/proxy-configuration#reverse-proxy-configuration), like installing Nginx, opening the needed ports etc

###### 4. Restore Nginx config
- When you arrive to the point to configure your [`/etc/nginx/sites-available/<HOSTNAME>`](nym-node/configuration/proxy-configuration#2-add-your-endpoint-configuration-to-nginx-by-creating-a-config-file), use again `scp` instead of creating a new one

```sh
scp -r <PATH_TO_LOCAL_NGINX_CONFIGURATION_BACKUP> <VPS_USER_NAME>@<VPS_HOST_ADDRESS>:/etc/nginx/sites-available
```
```sh
# for example:
scp -r $HOME/backup/my_nym_node/etc/nginx/sites-available root@my-nym-node:/etc/nginx/sites-available
```
###### 5. Edit Nginx configuration file with correct hostname
- Open the Nginx config file on your server and see if a domain name needs to be changed to new one. To open the file, use for example nano text editor:
```sh
nano /etc/nginx/sites-available/<HOSTNAME>
```
###### 6. Continue with the Nginx setup
- Go back to the [proxy setup guide](nym-node/configuration/proxy-configuration#3-activate-and-test-nginx-configuration) and continue from the point [\#3](nym-node/configuration/proxy-configuration#3-activate-and-test-nginx-configuration)

###### 7. Edit WSS configuration with the correct hostname
- Open the WSS config file on your server and see if a domain name needs to be changed to new one. To open the file, use for example nano text editor:
```sh
nano /etc/nginx/sites-available/wss-config-nym
```
###### 8. Finish and test the setup

Continue with the [activating and testing](nym-node/configuration/proxy-configuration#2-activate-and-test-nginx-wss-configuration) your reverse proxy and WSS until the end of the guide.
</ Steps>

To copy files to the root directory (paths starting with `/`), you need root permissions on the remote machine. If your server is not running as the root user, the `scp` command won't work directly, as using the `sudo` prefix would apply to your local machine instead of the remote server.

To resolve this, you can SSH into the remote server and create the configuration files manually using the prefix `sudo` and then copy their content from your local backup.

## Moving a node

In case of a need to move a Nym Node from one machine to another and avoiding to lose the delegation, here are few steps how to do it.

##### 1. Prepare both servers

Assuming both machines are remote VPS.

* Make sure your `~/.ssh/<SSH_KEY>.pub` is in both of the servers `~/.ssh/authorized_keys` file
* Create a `nym-node` folder in the target VPS. SSH in from your terminal and run:

```sh
# in case none of the nym configs was created previously
mkdir ~/.nym

#in case no `nym-node` was initialized previously
mkdir ~/.nym/nym-nodes
```
###### 2. Backup `clients.sqlite` database

- **Stop your node**
```sh
service nym-node stop
```
- Install `sqlite3`
```sh
apt install sqlite3
```
- Open sqlite CLI shell inside `clients.sqlite` database
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite
```
- Create backup called `clients_backup.sqlite`
```sh
.backup .nym/nym-nodes/default-nym-node/data/clients_backup.sqlite
```
- Exit sqlite CLI shell
```sh
.exit
```

###### 3. Move the node data and keys to the new machine

* Open your **local terminal** (as that one's ssh key is authorized in both of the VPS) and run:
```sh
scp -r -3 <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:~/.nym/nym-nodes <TARGET_USER_NAME>@<TARGET_HOST_ADDRESS>:~/.nym/nym-nodes/
```

###### 4. Open new/target VPS terminal and configure the node

* Edit `~/.nym/nym-nodes/<ID>/config/config.toml` config with the new listening address IP - it's the one under the header `[host]`, called `public_ips = [<PUBLIC_IPS>,]` and add your new location (field `location = <LOCATION>`, formats like: 'Jamaica', or two-letter alpha2 (e.g. 'JM'), three-letter alpha3 (e.g. 'JAM') or three-digit numeric-3 (e.g. '388') can be provided). You can see your IP by running a command `echo "$(curl -4 https://ifconfig.me)"`.

###### 5. Restore `clients.sqlite` database

- Install `sqlite3`
```sh
apt install sqlite3
```
- Open sqlite CLI shell inside `clients.sqlite` database
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite
```
- Restore your backup called `clients_backup.sqlite`
```sh
.restore .nym/nym-nodes/default-nym-node/data/clients_backup.sqlite
```
- Exit sqlite CLI shell
```sh
.exit
```
- Check integrity
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite "PRAGMA integrity_check;"
```
The result should return `ok` if the database is intact.

###### 6. Test & validate your setup
* Dry run the node and see if everything works.
* Setup the [systemd](nym-node/configuration.mdx#systemd) automation (don't forget to add the [terms and conditions flag](nym-node/setup.mdx#terms--conditions)) to `ExecStart` command, reload the daemon and run the service.

* If you want to use the exact same service config file, you can also copy it from one VPS to another following the same logic by opening your **local terminal** (as that one's ssh key is authorized in both of the VPS) and running:
```sh
scp -r -3 <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:/etc/systemd/system/nym-node.service <TARGET_USER_NAME>@<TARGET_HOST_ADDRESS>:/etc/systemd/system/nym-node.service
```

###### 4. Change the node smart contract info via the wallet interface

* Open Nym Wallet, go to *Bonding*, open *Settings* and change *Host* value to the new `nym-node` IP address. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks, returning zero performance.

* Make sure to stop the old node.

## Rename Node Local Identifier

Local node identifier, denoted as `<ID>` accross the documentation (not the identity key) is a name chosen by operators which defines where the nodes configuration data will be stored, where the ID determines the path to `~/.nym/nym-nodes/<ID>/`. This ID is never shared on the network.

When running a [`nym-node`](nym-node), a local identifier specified with a flag `--ID <ID>` is no longer necessary. Nodes without a specified ID will be assigned a default ID `default-nym-node`. This streamlines node management, particularly for operators handling multiple nodes via ansible and other automation scripts, as all data is stored at `~/.nym/nym-nodes/default-nym-node`.

If you already operate a `nym-node` and wish to change the local ID to `default-nym-node` or anything else, follow the steps below to do so.

In the example we use `default-nym-node` as a target `<ID>`, if you prefer to use another name, edit the syntax in the commands accordingly.

###### 1. Copy the configuration directory to the new one

```sh
cp -r  ~/.nym/nym-nodes/<ID> ~/.nym/nym-nodes/default-nym-node/
```

###### 2. Rename all original `<ID>` occurrences in `config.toml` to `default-nym-node`

```sh
# check occurences of the <SOURCE_ID>
grep -ir  "<ID>" ~/.nym/nym-nodes/default-nym-node/*
```

If your node `<ID>` was too generic (like 'gateway' etc) and it occurs elsewhere than just a custom value, **do not use `sed` command but rewrite the values manually using a text editor!**

- If you are clear with occurrence found above, move on using `sed` command:

```sh
sed -i -e "s/<ID>/default-nym-node/g" ~/.nym/nym-nodes/default-nym-node/config/config.toml
```

- If you are not sure and want to play it safe, do it manually by opening `config.toml` and rewriting each occurence of `<ID>`:
```sh
nano ~/.nym/nym-nodes/default-nym-node/config/config.toml
```

###### 3. Validate by rechecking the config file content
```sh
# either re-run
grep -ir  "<ID>" ~/.nym/nym-nodes/default-nym-node/*

# or by reading the config file
less ~/.nym/nym-nodes/default-nym-node/config/config.toml
```
- Pay extra attention to the `hostname` line. In case its value was somehow correlated with the source `<ID>` string you may need to correct it back

###### 4. Reload your [systemd service daemon](nym-node/configuration.mdx#systemd) and restart the service

- If you chosen `default-nym-node` as an ID, you can drop `--id` flag from node running commands, otherwise specify with the new `<ID>`.
- If automation isn't your thing, simply reboot the node. To automate with `systemd` is highly recommended.

###### 5. Be careful before removing old config

- If you double-checked that everything works fine, you can consider removing your old config directory

## Ports

All `<NODE>`-specific port configuration can be found in `$HOME/.nym/<NODE>/<YOUR_ID>/config/config.toml`. If you do edit any port configs, remember to restart your client and node processes.

### Nym Node Port Reference
| Default port | Use                       |
| ------------ | ------------------------- |
| `1789`       | Listen for Mixnet traffic |
| `1790`       | Listen for VerLoc traffic |
| `8080`       | Metrics http API endpoint |
| `1789`       | Listen for Mixnet traffic |
| `9000`       | Listen for Client traffic |
| `9001`       | WSS                       |
| `51822/udp`  | WireGuard                 |

### Validator Port Reference

All validator-specific port configuration can be found in `$HOME/.nymd/config/config.toml`. If you do edit any port configs, remember to restart your validator.

| Default port | Use                                  |
|--------------|--------------------------------------|
| 1317         | REST API server endpoint             |
| 26656        | Listen for incoming peer connections |
| 26660        | Listen for Prometheus connections    |

---
title: Manual Node Upgrade
url: https://nym.com/docs/operators/nodes/maintenance/manual-upgrade
---

# Manual Node Upgrade

This page explains how to upgrade [`nym-node`](#nym-node-upgrade) or [`validator`](#validator-upgrade) to the latest version in a few steps. If you prefer to automate the process, try to setup your flow with [Nymvisor](nymvisor-upgrade).

## Nym node Upgrade

Since `v2024.13-magura` (`nym-node v1.1.10`), **operators NO longer update node information in the Mixnet smart contract** (wallet version information), **only upgrade node binary** (on VPS), resulting in `~/.nym/nym-nodes/<ID>/config/config.toml` update.

Below are detailed steps how to do it:

###### 1. Upgrade `nym-node` binary

- Pause your node process.
    - If you run your node as `systemd` service (recommended), run: `service nym-node stop`
    - Otherwise open the terminal window with your node logs and press once `ctrl + c` and wait for the node to terminate gracefully

- Replace the existing `nym-node` binary with the newest binary (which you can either [compile yourself](../../binaries/building-nym.mdx) or [download](../../binaries/pre-built-binaries.mdx).

- To verify node version, run `./nym-node --version`

###### 2. Restart the node

- [Re-run with the same values](../nym-node/setup.mdx#initialise--run) as you use to run your `nym-node`. If you want keep changes in your config file, use flag `-w` (`--write-changes`), **This will just update the config file, it will not overwrite existing keys**.

- If you automated your node with `systemd` (recommended), make sure you have all needed flags in `ExecStart` line of the service config file, and run:
```sh
systemctl daemon-reload
service nym-node start
```

- If you want to monitor the logs of your `nym-node.service`, run:
```sh
journalctl -f -u nym-node.service
```

###### 3. Check if your node is reporting the version correctly

- Open [Nym Harbourbourmaster](https://harbourmaster.nymtech.net), search your node and verify that everything is working as expected and your node shows expected version.

After changes coming along with `v2024.13-magura` (`nym-node v1.1.10`), Nym Explorer is no longer picking all values correctly. Instead of fixing this outdated explorer, we are working on a new one, coming out soon.

[Nym Harbourmaster](https://harbourmaster.nymtech.net) has cache of 90min, expect your values to be updated with delay. We are aware of some issues with Nym Harbourmaster and working hard to resolve them in the upcoming explorer v2. To check your routing values in real time, you can use [`nym-gateway-probe`](/operators/performance-and-testing/gateway-probe).

## Validator Upgrade

Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files:

- The new validator (`nyxd`) v0.32.0
- The new `wasmvm` (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`)

Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then:

- Coopy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name.
- Swap in your new `nyxd` binary and restart.

You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9).

Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place.

### Common Reasons Validator Being Jailed

The most common reason for your validator being jailed is that it runs out of memory because of bloated syslogs.

Running the command `df -H` will return the size of the various partitions of your VPS.

If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process.

---
title: Automatic Node Upgrade: Nymvisor Setup & Usage
url: https://nym.com/docs/operators/nodes/maintenance/nymvisor-upgrade
---

export const NymvisorInitD = () => (

);

# Automatic Node Upgrade: Nymvisor Setup & Usage

> The Nymvisor binary was built in the [building nym](../../binaries/building-nym.mdx) section. If you haven't yet built Nym and want to run the code, go there first. You can build just Nymvisor with `cargo build --release --bin nymvisor`.

## What is Nymvisor?

Nymvisor is a process manager for Nym binaries that monitors the Nym release information for any newly released binaries. If it detects any changes, Nymvisor can automatically download the binary, stop the current binary, switch from the old binary to the new one, and finally restart the underlying process with the new binary.

In essence, it tries to mirror the behaviour of [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor), a tool used by Cosmos blockchain operators for managing/automating chain upgrades. Nymvisor, however, introduces some Nym-specific changes since, for example, upgrade information is obtained from our GitHub [releases page](https://github.com/nymtech/nym/releases) instead of (in the case of Cosmos blockchains) governance proposals.

### Supported Binaries

You can use Nymvisor to automate the upgrades of the following binaries:

* `nym-api`
* `nym-node`
* `nym-client`
* `nym-socks5-client`

Nymvisor is an early and experimental software. Users should use it at their own risk.

## Current version

## Preliminary steps

You need to have at least one Nym Node / client / Nym API instance already set up on the **same VPS** that you wish to run Nymvisor on.

Using Nymvisor presumes your VPS is running an operating system that is compatible with the pre-compiled binaries availiable on the [Github releases page](https://github.com/nymtech/nym/releases). If you're not, then until we're packaging for a greater variety of operating systems, you're stuck with [manually upgrading your node](manual-upgrade.mdx).

## Setup and Usage

### Viewing command help

You can check that your binaries are properly compiled with:

```sh
./nymvisor --help
```

Which should return a list of all available commands.

You can also check the various arguments required for individual commands with:

```sh
./nymvisor <COMMAND> --help
```

### Initialising your Nymvisor Instance

> This example will use the Nym Node binary as an example - however replacing `nym-node` with any other [supported binary](#supported-binaries) will work the same.

Initialise your Nymvisor instance with the following command. You must initialise Nymvisor with the binary you wish to add upgrades for:

```sh
./nymvisor init --daemon-home ~/.nym/nym-node/<ID> <PATH>/nym-node
```

Where the value of `--daemon-home` might be `~/.nym/nym-nodes/default-nym-node` and `<PATH>` might be `/home/sakine/nym/target/release/nym-node`, or wherever your node binary is located.

By default this will create config files at `~/.nym/nymvisors/instances/nym-node-default/config/config.toml` as shown in the console output above. For config options look at the different `--flags` available, or the [environment variables](#environment-variables) section below.

### Running your Nymvisor Instance

Nymvisor acts as a wrapper around the specified node process - it has to do this in order to be able to pause and restart this process. As such, you need to run your node _via_ Nymvisor!

The interface to the `nymvisor run <ARGS>` command is quite simple. Any argument passed after the `run` command will be passed directly to the underlying daemon, for example: `nymvisor run run --id default-nym-node` will run the `$DAEMON_NAME run --id default-nym-node` command (where `DAEMON_NAME` is the name of the binary itself (e.g. `nym-api`, `nym-node`, etc.)).

`run` Nymvisor and start your node via the following command. Make sure to stop any existing node before running this command.

```sh
./nymvisor run run --id <ID>
```

Nymvisor will now manage your node process (for an in-depth overview of this command check the [in-depth command information](./nymvisor-upgrade.md#commands-in-depth) below). It will periodically poll [this endpoint](https://nymtech.net/.wellknown/nym-node/upgrade-info.json) (replace `nym-node` with whatever node you may actually be running via Nymvisor) and check for a new `version` of the binary it is watching. If this exists, it will then, using the information proceed with these steps:

* Pause your node process
* Grab the new binary (`version`)
* Verify it against the provided `checksum`
* Perform a data backup of the existing node
* Replace the old binary with the new one
* Restart the process

And that's it!

### Creating an Adhoc Upgrade

This section is for advanced users. Generally users **will not have to use this command**.

`nymvisor add-upgrade <PATH_TO_EXECUTABLE> --upgrade-name=<NAME> --arg1=value1 --arg2=value2 ...` can be used to amend an existing `upgrade-plan.json` by creating new entries or to add an executable to an existing scheduled upgrade so that it would not have to be downloaded.

Situations in which this command might be used are:
 - An adhoc upgrade if e.g. a patched version of a binary was required
 - If a user doesn't trust the verification process of Nymvisor's pipeline and wishes to build/verify the binary themselves before using Nymvisor to perform the upgrade
 - If a user isn't using a currently supported operating system and needs to manually specify a binary they have built themselves

Similarly to `init`, `add-upgrade` requires a positional argument specifying a valid path to the upgrade binary. Furthermore, the `--upgrade-name` keyword argument must be set in order to declare the upgrade name. The remaining arguments are optional. They include:

- `--force` - if specified, will allow Nymvisor to overwrite existing upgrade binary / `upgrade-info.json` files if they already exist
- `--add-binary` - indicate that this command should only add binary to an existing scheduled upgrade
- `--now` - if specified will force the upgrade to be performed immediately (technically not 'immediately' within few seconds). It can't be specified alongside either `--upgrade-time` or `--upgrade-delay` arguments
- `--publish-date` - if a new `upgrade-info.json` file is going to be created, this argument will specify the `publish_date` metadata field. Otherwise, the current time will be used. The [RFC3339 datetime](https://www.rfc-editor.org/rfc/rfc3339) format is expected
- `--upgrade-time` - specifies the time at which the provided upgrade will be performed (RFC3339 formatted). If left unset, the upgrade will be performed in 15 minutes. It can't be specified alongside either `--now` or `--upgrade-delay` arguments.
- `--upgrade-delay` - specifies delay until the provided upgrade is going to get performed. If let unset, the upgrade will be performed in 15 minutes. It can't be specified alongside either `--upgrade_time` or `--now` arguments.

## Maintenance and Configuration

Check the [Nymvisor Configuration page](nymvisor-upgrade/nymvisor-configuration.mdx) for information on Nymvisor process maintenance and automation. You can find more in-depth information about the various aspects of Nymvisor such as what happens [under the hood](#commands-in-depth) for various commands.

## Config

The output format of `nymvisor config` can be further configured with `--output` argument. By default a human-readable text representation is used:
```ini
id:                                nym-node-default
daemon name:                       nym-node
daemon home:                       /home/nym/.nym/nym-nodes/default-nym-node
upstream base upgrade url:         https://nymtech.net/.wellknown/
disable nymvisor logs:             false
CUSTOM upgrade data directory      ""
upstream absolute upgrade url:     ""
allow binaries download:           true
enforce download checksum:         true
restart after upgrade:             true
restart on failure:                false
on failure restart delay:          10s
max startup failures:              10
startup period duration:           2m
shutdown grace period:             10s
CUSTOM backup data directory       ""
UNSAFE skip backups                false
```

- Adding `--output=json` would format the same data into JSON which can be more easily parsed programmatically to e.g. pipe the output into `jq` for further processing.
```sh
nymvisor config --output=json
```
- Outputs:
```json
{"nymvisor":{"id":"nym-node-default","upstream_base_upgrade_url":"https://nymtech.net/.wellknown/","upstream_polling_rate":"1h","disable_logs":false,"upgrade_data_directory":null},"daemon":{"name":"nym-node","home":"/home/nym/.nym/nym-nodes/default-nym-nodee","absolute_upstream_upgrade_url":null,"allow_binaries_download":true,"enforce_download_checksum":true,"restart_after_upgrade":true,"restart_on_failure":false,"failure_restart_delay":"10s","max_startup_failures":10,"startup_period_duration":"2m","shutdown_grace_period":"10s","backup_data_directory":null,"unsafe_skip_backup":false}}
```

## CLI Overview

Command options are:

- `help`, `--help`, or `-h` - Output Nymvisor help information and display the available commands.
- `config` - Display the current Nymvisor configuration, that means displaying the current configuration file that might have been overridden with environment variables value that Nymvisor is using.
- `init` - Generate a `config.toml` file for this instance of Nymvisor that will use the provided arguments alongside any environmental variables that are set.
- `add-upgrade` - Add an upgrade manually to Nymvisor. This command allows you to easily add the binary corresponding to an upgrade or amend the existing `upgrade-plan.json` whilst creating new `upgrade-info.json` file.
- `build-info` - Output the build information.
- `daemon-build-info` - Output the build information of the current binary used by the associated daemon.
- `run` - Run the configured binary using the rest of the provided arguments.
- `-V` or `--version` - Output the Nymvisor version

Similarly to other Nym binaries, Nymvisor supports a global `--config-env-file` or `-c` flag that allows specifying path to a `.env` file defining any relevant environmental variables that are going to be applied to any of the Nymvisor commands as described in the [Environment section](#environment-variables).

For commands that depend on Nymvisor config file (i.e. all but `init`), the configuration file is loaded as follows:

- If available, reading `$NYMVISOR_CONFIG_PATH`
- Otherwise, if `$NYMVISOR_ID` is set, a default path will be used, i.e. `$HOME/.nym/nymvisors/instances/$NYMVISOR_ID/config/config.toml`
- Finally, if there's only a single `nymvisor` instance instantiated (as defined by directories in `$HOME/.nym/nymvisors/instances`), that one will be loaded
- If all of the above fails, an error is returned

Nymvisor attempts to load the file from the derived path. If it fails, it attempts to use one of the older schemes and upgrade it as it goes, the loaded configuration is then overridden with any value that might have been set in the environment.

## Environment Variables

Please note environmental variables take precedence over any arguments passed, i.e. if one were to specify `--daemon_home="/foo"` and set `DAEMON_HOME="bar"`, the value of `"bar"` would end up being used.

For any of its commands as described in [CLI Overview section](#cli-overview), Nymvisor reads its configuration from the following environment variables:

- `NYMVISOR_ID` is the human-readable identifier of the particular Nymvisor instance.
- `NYMVISOR_CONFIG_PATH` is used to manually override path to the configuration file of the Nymvisor instance.
- `NYMVISOR_UPSTREAM_BASE_UPGRADE_URL` (defaults to https://nymtech.net/.wellknown/) is the base url of the upstream source for obtaining upgrade information for the daemon. It will be used fo constructing the full url, i.e. `$NYMVISOR_UPSTREAM_BASE_UPGRADE_URL/$DAEMON_NAME/upgrade-info.json`.
- `NYMVISOR_UPSTREAM_POLLING_RATE` (defaults to 1h) is polling rate the upstream url for upgrade information.
- `NYMVISOR_DISABLE_LOGS` (defaults to `false`). If set to `true`, this will disable Nymvisor logs (but not the underlying process) completely.
- `NYMVISOR_UPGRADE_DATA_DIRECTORY` is the custom directory for upgrade data - binaries and upgrade plans. If not set, the global Nymvisors' data directory will be used instead.
- `DAEMON_NAME` is the name of the binary itself (e.g. `nym-api`, `nym-node`, etc.).
- `DAEMON_HOME` is the location where the `nymvisor/` directory is kept that contains the auxiliary files associated with the underlying daemon instance, such as any backups or current version information, e.g. `$HOME/.nym/nym-api/my-nym-api`, `$HOME/.nym/nym-nodes/default-nym-node`, etc.
- `DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL` is the absolute (i.e. the full url) upstream source for upgrade plans for this daemon. The url has to point to an endpoint containing a valid `UpgradeInfo` json file. If set it takes precedence over `NYMVISOR_UPSTREAM_BASE_UPGRADE_URL`.
- `DAEMON_ALLOW_BINARIES_DOWNLOAD` (defaults to `true`), if set to `true`, it will enable auto-downloading of new binaries (as declared by urls in corresponding `upgrade-info.json` files). For security reasons one might wish to disable it and instead manually provide binaries by either placing them in the appropriate directory or by invoking `add-upgrade` command.
- `DAEMON_ENFORCE_DOWNLOAD_CHECKSUM` (defaults to `true`), if set to `true` Nymvisor will require that a checksum is provided in the upgrade plan for the upgrade binary to be downloaded. If disabled, Nymvisor will not require a checksum to be provided, but still check the checksum if one is provided.
- `DAEMON_RESTART_AFTER_UPGRADE` (defaults to `true`), if set to `true` Nymvisor will restart the subprocess with the same command-line arguments and flags (but with the new binary) after a successful upgrade. Otherwise (`false`), Nymvisor stops running after an upgrade and requires the system administrator to manually restart it. **Note restart is only after the upgrade and does not auto-restart the subprocess after an error occurs.** That is controlled via `DAEMON_RESTART_ON_FAILURE`.
- `DAEMON_RESTART_ON_FAILURE` (defaults to `true`), if set to `true`, Nymvisor will restart the subprocess with the same command-line arguments and flags if it has terminated with a non-zero exit code.
- `DAEMON_FAILURE_RESTART_DELAY` (defaults to 10s), if `DAEMON_RESTART_ON_FAILURE` is set to `true`, this will specify a delay between the process shutdown (with a non-zero exit code) and it being restarted.
- `DAEMON_MAX_STARTUP_FAILURES` (defaults to 10) if `DAEMON_RESTART_ON_FAILURE` is set to `true`, this defines the maximum number of startup failures the subprocess can experience in a quick succession before no further restarts will be attempted and Nymvisor will terminate.
- `DAEMON_STARTUP_PERIOD_DURATION` (defaults to 120s) if `DAEMON_RESTART_ON_FAILURE` is set to `true`, this defines the length of time during which the subprocess is still considered to be in the startup phase when its failures are going to be counted towards the limit defined in `DAEMON_MAX_STARTUP_FAILURES`.
- `DAEMON_SHUTDOWN_GRACE_PERIOD` (defaults to 10s), specifies the amount of time Nymvisor is willing to wait for the subprocess to undergo graceful shutdown after receiving an interrupt before it sends a kill signal.
- `DAEMON_BACKUP_DATA_DIRECTORY` specifies custom backup directory for daemon data. If not set, `DAEMON_HOME/nymvisor/backups` is used instead.
- `DAEMON_UNSAFE_SKIP_BACKUP` (defaults to `false`), if set to `true`, all upgrades will be performed directly without performing any backups. Otherwise (`false`), Nymvisor will back up the contents of `DAEMON_HOME` before trying the upgrade.

## Dir structure

The folder structure of Nymvisor is heavily inspired by Cosmovisor, but with some notable changes to accommodate our binaries having possibly multiple instances due to their different `--id` flags. The data is spread through three main directories:

- In a global `nymvisors` data directory shared by all Nymvisor instances (default: `$HOME/.nym/nymvisors/data`) that contains daemon upgrade plans, binaries and upgrades histories. It includes a sub-directory for each version of the application (i.e. `genesis` or `upgrades/<NAME>`). Within each sub-directory is the application binary (i.e. `bin/$DAEMON_NAME`), the associated `upgrade-info.json` and any additional auxiliary files associated with each binary. `current` is a symbolic link to the currently active directory (i.e. `genesis` or `upgrades/<NAME>`)

- In a home directory of a particular `nymvisor` instance (e.g. `$HOME/.nym/nymvisors/instances/<NYMVISOR_INSTANCE_ID>/`). It includes sub-directories for its configuration file (i.e. `config/config.toml`), that preconfigures the instance, and for any additional persistent data that might be added in the future (i.e. `data`)

- In a `nymvisor` data directory inside the home directory of the managed daemon instance (default: `$HOME/.nym/$DAEMON_NAME/nymvisor`) that contains sub-directories for data backups (i.e. `backups/<NAME>`) and current version information (`current-version-info.json`)

A sample full structure looks as follows:

```sh
~/.nym
├── nymvisors
│   ├── instances
│   │   ├── <id1>
│   │   │   ├── config
│   │   │   │   └── config.toml
│   │   │   └── data
│   │   │       └── ...
│   │   └── <id2>
│   │       └── ...
│   └── data
│       ├── nym-api
│       │   ├── current -> genesis or upgrades/<name>
│       │   ├── genesis
│       │   │   ├── bin
│       │   │   │   └── nym-api
│       │   │   └── upgrade-info.json
│       │   ├── upgrades
│       │   │   └── <upgrade-name>
│       │   │       ├── bin
│       │   │       │   └── nym-api
│       │   │       └── upgrade-info.json
│       │   ├── upgrade-history.json
│       │   └── upgrade-plan.json
│       ├── nym-node
│       │   └── ...
│       └── $DAEMON_NAME
│           └── ...
└── nym-api
├── <id1>
│   ├── config
│   │   └── <nym-api-config-data>
│   ├── data
│   │   └── <nym-api-data>
│   └── nymvisor
│       ├── backups
│       │   └── <upgrade-name>
│       │       └── ....
│       └── current-version-info.json
└── <id2>
└── ...
```

## Commands In-Depth
This section outlines what happens under the hood with the following commands:

### `init`

`init` does the following:

- Executes the `$DAEMON_NAME build-info` command on the daemon executable to check its validity and obtain its name
- Creates the required directory structure:
  - `$DAEMON_HOME/nymvisor` folder if it doesn't yet exist
  - `$DAEMON_BACKUP_DATA_DIRECTORY` folder if it doesn't yet exist
  - `$NYMVISOR_UPGRADE_DATA_DIRECTORY` folder if it doesn't yet exist
  - `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis/bin` folder if it doesn't yet exist
  - `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/upgrades` folder if it doesn't yet exist
- Copies the provided executable to `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis/bin/$DAEMON_NAME`
- Generates initial `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis/upgrade-info.json` file based on the provided binary
- Generates initial `$DAEMON_HOME/nymvisor/current-version-info.json` file based on the provided binary
- Creates a `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/current` symlink pointing to `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis`
- Saves the Nymvisor instance's config file to `$NYMVISOR_CONFIG_PATH` and creates the full directory structure for the file
- Outputs (to `stdout`) the full configuration used

`nymvisor init` is specifically for initializing Nymvisor, and should **not** be confused with a daemon's `init` command - such as `nym-socks5-client init` (e.g. `nymvisor run init`).

### `run`

`nymvisor run` is a lightweight wrapper around the underlying daemon. It uses only a single thread and spawns three simple tasks:

- An upstream puller that checks the upstream source (as defined by `DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL` or derived from `NYMVISOR_UPSTREAM_BASE_UPGRADE_URL`) for any recently released upgrades. It then creates appropriate `upgrade-info.json` file and updates the `upgrade-plan.json`
- A file watcher for the `upgrade-plan.json` file that can notify the main run loop of upgrades that were added by either the above upstream puller task or via the `add-upgrade` command,
- The daemon run loop that:
  - Runs the `DAEMON_NAME` with the provided arguments until:
    - It completes the execution (with any exit code),
    - Nymvisor receives a `SIGINT`, `SIGTERM` or `SIGQUIT`,
    - A new upgrade is scheduled to be performed (by other task watching for changes in `upgrade-plan.json` and waiting until the `upgrade_time`,
  - If `DAEMON_UNSAFE_SKIP_BACKUP` is not set to `true`, it backups the content of `DAEMON_HOME` directory,
  - Performs the binary upgrade by:
    - Creating a temporary, exclusive and non-blocking, `upgrade.lock` file for the `DAEMON_NAME`. `flock` with `LOCK_EX | LOCK_NB` is used for that purpose. The file is created in case users didn't read any warnings and attempted to run multiple instances of `nymvisor` managing the same `DAEMON_NAME`,
    - Downloading the upgrade binary for the runners architecture using one of the urls defined in `upgrade-info.json`. Note, however, that this is only done if the binary associated with the `<UPGRADE-NAME>` does not already exist and `DAEMON_ALLOW_DOWNLOAD_BINARIES` is set to `true`,
      - If the binary has been downloaded and `DAEMON_ENFORCE_DOWNLOAD_CHECKSUM` is set to true, the file checksum is verified using the specified algorithm,
    - Verifying the upgrade binary - checking if it's a valid executable with expected `build-info`. Note that this will also set `a+x` bits on the file if those permissions have not already been set,
      - removing the queued upgrade from `upgrade-plan.json`,
      - Inserting new upgrade into the `upgrade-history.json`,
      - Updating the `current-version-info.json`,
      - Updating the `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/current` symlink to the upgrade directory,
      - Removing the `upgrade.lock` file.
  - The above loop is repeated if either:
    - The daemon has crashed and `DAEMON_MAX_STARTUP_FAILURES` has not been reached yet,
    - The daemon has successfully been upgraded, `DAEMON_RESTART_AFTER_UPGRADE` has been set to `true` and the manual flag on the performed upgrade has been set to `false`.

### `add-upgrade`

`nymvisor add-upgrade` does the following:

- Executes the `$DAEMON_NAME build-info` command on the daemon executable to check its validity and obtain its name
- Attempts to load existing `upgrade-info.json` for the provided `<upgrade-name>`. If it already exists and neither `--force` nor `--add-binary` was specified, Nymvisor will terminate
- Checks if `upgrades/<UPGRADE_NAME>/$DAEMON_NAME` binary already exists. If it does and `--force` flag was not specified, Nymvisor will terminate the provided upgrade binary is copied to its appropriate location
- if applicable, new `upgrade-info.json` is created and written to its appropriate location
- `upgrade-plan.json` is updated with the new upgrade details. If there's an active Nymvisor instance running, this change will be detected to initialise upgrade process

---
title: Nymvisor Configuration
url: https://nym.com/docs/operators/nodes/maintenance/nymvisor-upgrade/nymvisor-configuration
---

# Nymvisor Configuration

## Nymvisor Automation with `systemd`

This section contains guide how to setup `systemd` automation for Nymvisor. If you are looking for other chapters, visit these pages: [VPS setup](../../preliminary-steps/vps-setup), advanced terminal tools like [tmux and nohup setup](../../nym-node/configuration.mdx#vps-setup-and-automation), [`nym-node` automation](../../nym-node/configuration.mdx#systemd) or [`validator` automation](../../validator-setup/nyx-configuration#automation).

Since you're planning to run your node via a Nymvisor instance, as well as creating a Nymvisor `.service` file, you will also want to **stop any previous node automation process you already have running**.

SSH to your server as `root` or become one running `sudo -i` or `su`. If you prefer to administrate your VPS from a user environment, supply the commands with prefix `sudo`.

###### 1. Create a service file

To automate with `systemd` use this init service file by saving it as `/etc/systemd/system/nymvisor.service` and follow the [next steps](#2-following-steps-for-nym-node-running-as-systemd-service).

- Open service file in a text editor
```sh
nano /etc/systemd/system/nymvisor.service
```

- Paste this config file, substitute `<USER>` and `<PATH>` with your correct values and add all flags to run your `nymvisor` to `ExecStart` line instead of `<ARGUMENTS>`:

```ini
[Unit]
Description=Nymvisor <VERSION>
StartLimitInterval=350
StartLimitBurst=10

[Service]
User=<USER> # replace this with whatever user you wish
LimitNOFILE=65536
ExecStart=<PATH>/nymvisor run <ARGUMENTS>
KillSignal=SIGINT
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
```

- Save config and exit

###### 2. Following steps for `nymvisor` running as `systemd` service

Once your service file is saved follow these steps.

- Reload systemctl to pickup the new unit file:
```sh
systemctl daemon-reload
```

- Enable the newly created service:
```sh
systemctl enable nymvisor.service
```

- Start your Nymvisor instance as a `systemd` service:
```sh
service nymvisor start
```

This will cause your Nymvisor instance to start at system boot time. If you restart your machine, your service will come back up automatically.

###### 3. Useful `systemd` commands for easier management

- You can monitor system logs of your node by running:
```sh
journalctl -u nymvisor -f
```

- Or check service status by running:
```sh
systemctl status nymvisor.service
# for example systemctl status nymvisor.service
```

- You can also do `service nymvisor stop` or `service nymvisor restart`.

###### 4. Anytime you make any changes to your `systemd` script after you've enabled it, you will need to run:
```sh
systemctl daemon-reload
service nymvisor restart
```

This lets your operating system know it's ok to reload the service configuration and restarts the node in a graceful way.

---
title: Orchestration of Multiple Nym Nodes
url: https://nym.com/docs/operators/orchestration
---

# Orchestration of Multiple Nym Nodes

Nym is a distributed network operated by admins all around the world. As the network grows, it attracts experienced operators of various infrastructure and builds an ever evolving community of builders, developers, admins and privacy enthusiasts.

Operators form squads, DAOs and different entities managing multiple nodes per organisation. Orchestration of multiple servers with Nym nodes allows operators to be more efficient in deployment, changes implementation and upgrade flow following our demanding [release cycle](/operators/release-cycle).

The operators who understand well basic `nym-node` [requirements](/operators/nodes#minimum-requirements) and general server administration, can use these two guides to lower cost and energy spent to maintain their nodes.

1. [**Virtualising dedicated server with KVM**](/operators/nodes/preliminary-steps/vps-setup/advanced)
2. [**Orchestration of multiple nodes with Ansible**](/operators/orchestration/ansible)

---
title: Orchestrating Nym Nodes with Ansible
url: https://nym.com/docs/operators/orchestration/ansible
---

# Orchestrating Nym Nodes with Ansible

[Ansible](https://docs.ansible.com/) is an open-source automation engine that can perform IT tasks and remove complexity from workflows. Ansible ensures that your environment is exactly as you describe it. You can automate any command with Ansible to make your system maintenance very efficient. **For `nym-node` operators Ansible is particularly useful as it can scale infinitely the amount of nodes operators can setup, bond, upgrade, maintain and re-configure from their local shell, removing the complexity and required time when managing many nodes one by one.**

**This setup should be used only by operators who understand `nym-node` administration and [requirements](/operators/nodes#minimum-requirements)**

**Ansible is more suitable for skilled power users managing multiple nodes at the same time!**

If you are not familiar with Ansible, operating Nym nodes may be a good motivation to learn something new and improve your admin skills, it's worth the time.

Start by reading through [Ansible documentation pages](https://docs.ansible.com)

## Installation

### Ansible installation

For anything regarding the installation and management of Ansible itself, the best is to refer to their documentation. On [this page](https://docs.ansible.com/projects/ansible/latest/installation_guide/intro_installation.html#latest-release-via-dnf-or-yum) you can see the installation guide.

If you are confident and want to start right away, install Ansible on your machine using one of these two ways:

1. `apt` repository:
```sh
sudo apt-get update
sudo apt-get install ansible
```
2. `pip` or `pipx` - recommended by Ansible community:
```sh
pip install ansible
# or
pipx install ansible
```

### Nym Node Playbook Installation

Nym Node Ansible playbook template is located in our monorepo [`nymtech/nym/ansible/nym-node`](https://github.com/nymtech/nym/tree/develop/ansible/nym-node)

###### 1. Get `nym/ansible/nym-node` playbook:

The easiest way is to use `git` to `clone` or `pull` the repository:

```sh
git clone https://github.com/nymtech/nym.git

# or navigate where you already have the repo and run

git checkout develop
git pull origin develop
```

###### 2. Save the template to your location:

You may want to create a directory outside of the repository and move the template there so it can be modified without risking that your configuration will be accidentally shared when working with the repository in the future.

- Navigate to any location and create a directory for your Ansible `nym-node` playbook:
```sh
cd <PATH>
mkdir `ansible`
cd ansible
```

- Copy the template to the newly created location:
```sh
cp -r <PATH>/nym/ansible/nym-node ./
```

</ Steps>

Now you have the template of Ansible playbook for `nym-node` remote administration. To make it work, there are a few variables requiring your attention.

## Configuration

After [getting the ansible Nym node playbook](#ansible-installation) to your location, it's time to configure it for your own needs.

> Mind that *idempotency* is an essential character when dealing with orchestration. A playbook, even when run many times should ensure that state of your targeted system will not change from what you intended. Therefore, it is important to make sure that all tasks in your playbook do not change the system in any way if the change you required has already been applied.

Before starting Ansible, ensure that your `A` and `AAAA` records are pointed to your server IPs and propagated. Good test is to be able to ping them or use them for ssh into the server.
</ Callout>

**Open your local copy of the playbook in your favourite text editor and begin with these steps:**

###### 1. Configure global variables:
- Open `playbooks/group_vars/all.yml`
- Setup any variables which you want to have propagated on all your nodes globally
- Note that in the next step we will be setting up a node inventory, where each of the variable can be configured per node, taking priority over the global ones.
- Setup a correct path for your SSH kety to `ansible_ssh_private_key_file:`
- Use these variables or comment them out with `#`:
    - `ansible_user`
    - `email`
    - `website`
    - `description`
- Keep `hostname=""` as a fallback for nodes without a hostname

###### 2. Create node inventory:
- Open `playbooks/inventory/all`
- Make an entry for each of your node:
```sh
node1 ansible_host=<YOUR_SERVER_IP> ansible_user=<USER> hostname=<HOSTNAME> location=<LOCATION> email=<EMAIL> mode=<MODE> wireguard_enabled=<true/false> moniker=<MONIKER> description=<DESCRIPTION>
```
- These are mandatory values specific for each node - must be defined in the inventory:
    - `ansible_host`: IPv4 host address
    - `hostname`: node domain, otherwise fallbacks to `""` for nodes without domain
    - `location`: node server location
- These are mandatory values which can be setup per node or in `group_vars/all` globally:
    - `ansible_user`
    - `email`
    - `website`
    - `moniker`
    - `description`
    - `mode`
    - `wireguard_enabled`

###### 3. Test your setup
Run this command to check if everything is configured correctly in your inventory:
```sh
cd playbooks
ansible-inventory --graph
```

###### 4. Configure `nym-node run` command arguments
Open `roles/nym/defaults/main.yml` and have a look on the variables used:

- If you agree with [Terms and conditions](/operators/nodes/nym-node/setup#terms--conditions) uncomment the line: `accept_operator_terms: true` without which your node can never take part in Nym Network.
- The rest is up to your configuration but generally these flags workflows

These variables are read by the main task for `nym-node` installation: `roles/nym/tasks/config.yaml`
- Open that yaml and have a look on the flags
- In case of not needing some of the, delete them (ie when running `--mode mixnode` you can delete everything from `--hostname` to `--announce-wss-port`)

###### 5. Configure `deploy.yml` playbook
Open `playbooks/deploy.yml` and comment out `tunnel` and `quic` roles in case of running your playbook for nodes in a mode `mixnode`.

Save all the files and test with:
```sh
cd playbooks
ansible-inventory --graph
```

Right now you should be ready to go.

## Flow & Usage

This chapter describes fundamental commands for using Ansible playbooks in relation to orchestrating multiple servers running a `nym-node`. For a full understanding of Ansible usage, read [Ansible documentation pages](https://docs.ansible.com).

### Logic

The main logic of the playbook flow when running with a basic command and playbook like this:
```sh
ansible-playbook <PLAYBOOK>.yml
```

###### 1. Read inventory
Ansible parses `inventory/all` and performs the playbook on all entries in it, unless specified otherwise

###### 2. Read global vars
Ansible parses `group_vars/all.yml` and asigns global variables to all inventory entries, unless they were defined in the inventory.

**Variables defined in the inventory per entry take highest priority!**

###### 3. Follow roles in the playbook
Ansible reads the roles defined in `<PLAYBOOK>.yml` passed with the command and executes the tasks defined under each role

</ Steps>

### Usage

The simplest way is to run `ansible-playbook` binary with a provided playbook as a command. That will do the defined roles on all entries in the inventory. In Nym we currently have these playbooks:

###### 1. Deploy

A playbook to deploy server and `nym-node` from scratch, configuring networking, routing, firewall, systemd, bridges, reverse proxy, exit policy and all required tasks.

This playbook will run roles on all the inventory entries in parallel by default.

```sh
cd playbooks
ansible-playbook deploy.yml
```

###### 2. Bond

A playbook to interactively register your node to Nym network by bonding it to Nyx blockchain account.

This playbook is intercative as it prompts user for data from Nym wallet to sign a message. It will run roles on one inventory entry at a time by default.

```sh
cd playbooks
ansible-playbook bond.yml
```

###### 3. Upgrade

A playbook to upgrade `nym-node` binary to the *Latest* by default. Operators can hard code a specific binary version in `roles/upgrade/defaults/main.yml` by un-commenting the `nym-version` line and providing their desired version.

This playbook will run roles on all the inventory entries in parallel by default.

```sh
cd playbooks
ansible-playbook upgrade.yml
```

###### 4. System Maintenance

A playbook to de-clogg and cleanup the servers (VMs) hosting `nym-node`. This playbook should be used for operators having issues with their servers filling up disk space too fast. For operators hosting many VMs on a hypervisor dedicated / bare metal server - run this playbook alongside [the guide to clean up the hypervisor](/operators/troubleshooting/vps-isp#on-the-hypervisor-host-machine).

Maintaining the VMs using this playbook and reclaiming space on hypervisor will prevent your servers from:

- Sudden *disk full* crashes
- `journald` runaway growth
- Duplicate `rsyslog` logs
- `nym-node` log growth
- `qcow2` like allocation growth inside VPS storage

The playbook is located in `roles/upgrade/defaults/system-maintenance.yml`, but the most important part is in `playbooks/group_vars/all.yml`, starting with a header `## SYSTEM MAINTENANCE PLAYBOOK KNOBS`. This commented list of adjustable knobs serves as a dashboard to tweak values of the playbook. Any overwrite will superseed the default ones in the playbook itself.

This playbook will run roles on all the inventory entries in parallel by default.

```sh
cd playbooks
ansible-playbook system-maintenance.yml
```

</ Steps>

### Useful Commands

[Ansible](https://docs.ansible.com) has many smart ways to manage your playbooks, roles or inventory entries.

**Here are some useful tips:**

###### One node at a time
To test new configuration, it's advised to try it on one server at first. Of course you can comment out any entries in the inventory, but there are easier ways to do it.

- Provide flag `-l` followed by inventory entry and Ansible will change state only of that entry:

- Some possibilities are (in example we use upgrade.yml, you can use any playbook):
```sh
# point to one entry
ansible-playbook upgrade.yml -l node1

# point to multiple entries
ansible-playbook upgrade.yml -l "node1,node2"

# use regex
ansible-playbook upgrade.yml -l "*exit*"
```

###### Role limit

To update your exit policy by using the newest [NTM](https://github.com/nymtech/nym/blob/develop/scripts/nym-node-setup/network-tunnel-manager.sh) via Ansible, just run:
```sh
ansible-playbook deploy.yml -t network_tunnel_manager
```
This will download the script from `develop`, make executable and run it with the command `complete_networking_configuration`.

Sometimes you may want to run just one tag at a time, for that use `-t` flag, for example:
```sh
# in case of wanting to run only quic deployment role
ansible-playbook deploy.yml -t quic

# in case of running the same on only one node
ansible-playbook deploy.yml -l node2 -t quic
```

To list all tags, run:
```sh
ansible-playbook <PLAYBOOK>.yml --list-tags

# for example
ansible-playbook deploy.yml --list-tags
```

###### nocows

Yes, by default there is a cow printed under each task, you can turn it off by opening `playbooks/ansible.cfg` and un-commenting the `nocows` line:

```cfg
nocows = 1
```
</ Steps>

---
title: Nym Node Performance Monitoring & Testing Guide
description: Monitor your Nym node performance with Prometheus, Grafana, and community tools. Covers key metrics, routing score analysis, and testing best practices.
url: https://nym.com/docs/operators/performance-and-testing
---

# Performance Monitoring & Testing

As Nym developers constantly improve the software, the role of Node Operators is to keep their nodes up to date, monitor their performance and share feedback with the rest of the community and Nym team. Node performance measurements and [server monitoring](#monitoring) are an essential pillar of our common work.

Nym Network is routed either through the Mixnet (5-hop) or through Wireguard (2-hop). In all cases Nym node operators always employ only one binary called [`nym-node`](/operators/nodes/nym-node). Through provided arguments (or changes in the config file), `nym-node` can be utilised for different [functionalities](/operators/nodes/nym-node/setup#functionality-mode). However, once it's [registered to Nym Network](/operators/nodes/nym-node/bonding) it's by default available for Nym Mixnet not for Wireguard routing. Only nodes with Wireguard enabled, are also available for Wireguard routing. This creates a situation where every Wireguard enabled `nym-node` is required to have a solid performance score in Mixnet to begin with, but not every Mixnet routing `nym-node` must have Wireguard enabled.

Given this complexity, we divided the part below about performance calculation logic and node selection into two parallel tabs: Mixnet and Wireguard.

  <Tabs items={[
    <strong>Mixnet: Nodes Performance Calculation</strong>,
    <strong>WireGuard: Gateways Performance Calculation</strong>,
    ]} defaultIndex="0">
    <MyTab><NodePerfMixnet /></MyTab>
    <MyTab><NodePerfWG /></MyTab>

## Functionality & Performance Check

If you want to check your nodes performance, connectivity and much more, see some of the dashobards:

- [Node Status dashboard](https://node-status.nym.com/dvpn): Shows latest probe results on one board
- [Nym Node Status Observatory](https://harbourmaster.nymtech.net): New version of a good old Nym Harbourmaster, allowing operators preview stats of each node

For more information about available endpoints and their status, you can refer to [`nymvpn.com/api/public/v1/directory/gateways`](https://nymvpn.com/api/public/v1/directory/gateways) or see directly self described endpoints of your node:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
# or
http://<IPv4_ADDRESS>/api/v1/swagger/#/

# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/swagger/#/
```

For example to determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/roles
# or
http://<IPv4_ADDRESS>/api/v1/roles

# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/roles
```

## Socks5 Score Calculation

Gateway probe also runs tests through a Network requester - a module build as a part of `nym-node`, active only in mode Exit Gateway, used for [Socks5](/developers/clients/socks5) proxy TCP connection.

Socks5 score is displayed in [Nym Node Status Observatory](https://harbourmaster.nymtech.net) (if you open a page with a particular gateway) and in detail it can be previewed at [mainnet-node-status-api.nymtech.cc/dvpn/v1/directory/gateways](https://mainnet-node-status-api.nymtech.cc/dvpn/v1/directory/gateways) or when running own instance of [Gateway probe](/operators/performance-and-testing/gateway-probe).

### Socks5 Score Calculation Process

Socks5 score is defined in the json output of Gateway probe as `"socks5"` key. Here is an example of the dictionary:

```json
        "socks5": {
          "can_proxy_https": true,
          "score": "medium",
          "errors": null
        }
```

> Note: When we write *gateway* we refer to a `nym-node --mode exit-gateway` in this sub-chapter.

1. Gateway gets probed as part of a Gateway probe test where other components get tested as well

2. Probe tries to connect to the Gateway through Socks5 10 times per testing instance

3. Latency is calculated as an average of the successful attempts

4. Gateway is scored as `"low"`, `"medium"`, `"high"` or `"offline"`, in numbers it means:
    - `"offline"`: Gateway failed the test 3 or more times (out of 10 attempts)
    - `"high"`: Top 50% of nodes with lowest average latency
    - `"medium"`: Following 25% of nodes with lowest average latency below top 50% nodes
    - `"low"`: Remaining 25% of nodes with the highest average latency time

## Monitoring

There are multiple ways to monitor performance of nodes and the machines on which they run. For the purpose of maximal privacy and decentralisation of the data - preventing Nym Mixnet from any global adversary takeover - we created these pages as a source of mutual empowerment, a place where operators can share and learn new skills to **setup metrics monitors on their own infrastructure**.

### Guides to Setup Own Metrics

A list of different tools, templates and guides for easier navigation:

* [`nym-gateway-probe`](performance-and-testing/gateway-probe.mdx): a useful tool used under the hood of [Node Status Observatory](https://harbourmaster.nymtech.net)

* [Diagnostic Tool](/developers/tools/diagnostic-tool): diagnose connectivity issues and provides insights into network performance

* [Prometheus and Grafana](performance-and-testing/prometheus-grafana.mdx) self-hosted setup

### Collecting Testing Metrics

For the purpose of the performance testing Nym core developers plan to run instances of Prometheus and Grafana connected to Node explorer in the house. The network overall key insights we seek from these tests are primarily internal. We're focused on pinpointing bottlenecks, capacity loads, and monitoring cpu usage on the nodes' machines.

{/* LEAVING THIS BIT FOR FUTURE F&F CASES:
## Testing

For the moment we paused Fast and Furious `perf` environment. All load and speed testing is carried on directly Nym Mainnet as this is the only way to collect real performance data.

We do testing in order to **understand and increase the overall quality of the Nym Network**. The main takeaways of such event are:

1. Understanding of the network behavior under full load
    - How many mixnet client users can all active set entry gateways handle simultaneously?
    - How much sustained IP traffic can a subset of mainnet nodes sustain?
2. Needed improvements of Nym Node binaries to improve the throughput on mainnet
3. Measurement of required machine specs
4. Raw data record
5. Increase quality of Nym Nodes
6. Show each operator a way to monitor their nodes in a distributed fashion
7. Adjust rewarding based on the machine specs and server pricing

Visit [Nym Harbour Master](https://harbourmaster.nymtech.net/) monitoring page to monitor network components (nodes) performance.
*/}

---
title: NS API: Deployment Guide
url: https://nym.com/docs/operators/performance-and-testing/ns-api-deployment
---

# NS API: Deployment Guide

## Components
The Node Status API is made up of 3 components:
- `nym-node-status-api`
- `nym-node-status-client`
- `nym-node-status-agent`

The API stores its data in a local SQLite database. It periodically gets most of its data from a [NymAPI](/apis/nym-api) instance, and for instances also running with the Gateway Probe, uses the stored topology to conduct performance probe tests.

## Gateway Probe
You can run the `nym-node-status-api` alone, but if you want to run probes for `nym-node`s running as Gateways, you have to also run the `nym-node-status-agent` (which consumes the `nym-node-status-client` lib). The probe will run a set of tests per Gateway node, and return the sort of results seen [here](https://harbourmaster.nymtech.net/gateway/23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb).

## UI
The API exposes a [Swagger](https://swagger.io/docs/) documentation UI by default on port `8000` (see an example [here](https://mainnet-node-status-api.nymtech.cc/swagger/)).

Currently we are not shipping a custom UI component for the Node Status API. The [Harbourmaster](https://harbourmaster.nymtech.net/) frontend consumes this API, amongst other things, but this is an internal repo we use to experiment with new APIs and data on, so it is not public yet.

We invite developers to roll their own UI for their Node Status API instance.

## Docker Images
We will ship Docker images for both the `agent` and `api` in the future. There are Docker images for both in root of each corresponding crate ([`agent`](https://github.com/nymtech/nym/blob/09ea406c02e9a3beebc062f525e4ea1b4222dcbb/nym-node-status-api/nym-node-status-agent/Dockerfile), [`api`](https://github.com/nymtech/nym/blob/develop/nym-node-status-api/nym-node-status-api/Dockerfile)) which are used internally, which could be a starting point for developers to dockerize their instance for the moment.

## Build
### Prerequisites
- Rust
- SQLite
- Get an `ipinfo` key following instructions [here](https://github.com/ipinfo/rust?tab=readme-ov-file#getting-started).

### Compilation
```shell
cargo build --release --package nym-node-status-api --package nym-node-status-agent --package nym-node-status-client
```

## Run
Since the Node Status API depends on both flags and environmental variables, it might be easier to run the binary via a script like the one below - this this script essentially just `source`-s the defined `.env` file after exporting certain binary-specific variables, and then runs the binary. You can find the `.env` files [here](https://github.com/nymtech/nym/tree/master/envs).

    All CLI flags are configurable as environmental variables and vice versa, so take the following scripts / setups as guides that you can change however best suits your setup. You can see all definitions [here](https://github.com/nymtech/nym/blob/develop/nym-node-status-api/nym-node-status-api/src/cli/mod.rs#L14).

```bash
#!/bin/bash

set -e

export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} # see nym/envs/ for all possible environments
export NYM_API_CLIENT_TIMEOUT=60
export NODE_STATUS_API_TESTRUN_REFRESH_INTERVAL=120
export IPINFO_API_TOKEN=<YOUR_IPINFO_API_KEY>

monorepo_root=<PATH/TO/NYM/>
set -a
source "${monorepo_root}/envs/${ENVIRONMENT}.env"
echo ${monorepo_root}/envs/${ENVIRONMENT}.env
set +a
export RUST_LOG=${RUST_LOG:-debug} # debug is useful to check everything is working initially, but quite verbose

echo "Verifying environment variables were properly sourced:"
echo "RUST_LOG=${RUST_LOG}"
echo "BECH32_PREFIX=${BECH32_PREFIX}"
echo "NETWORK_NAME=${NETWORK_NAME}"

<PATH/TO/>nym-node-status-api -- --ipinfo-api-token $IPINFO_API_TOKEN
```

### Functionality Without Gateway Probe
Data will be restricted to information that doesn't involve Probe results; `routing` and `config` scores will be `0` and `last_probe` results `null`, as you can see in this snipped output of the `gateways` endpoint:

```shell
{
      "gateway_identity_key": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
      "bonded": true,
      "performance": 99,
      "self_described": {
        "authenticator": {
          "address": "6Gdtw13Fa46AvkqkHELZZCMKWASDodoJeK9APRNpjjdj.7ji8DDkpjA2AdgwK7wbZm8yi4xZGogGJeypBQt4hAw3P@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb"
        },
        "auxiliary_details": {
          "accepted_operator_terms_and_conditions": true,
          "announce_ports": {
            "mix_port": null,
            "verloc_port": null
          },
          "location": null
        },
        "build_information": {
          "binary_name": "nym-node",
          "build_timestamp": "2025-02-13T11:49:34.670488195Z",
          "build_version": "1.5.0",
          "cargo_profile": "release",
          "cargo_triple": "x86_64-unknown-linux-gnu",
          "commit_branch": "HEAD",
          "commit_sha": "a3e19b4563843055b305ea9a397eb1ad84b5c378",
          "commit_timestamp": "2025-02-10T18:14:47.000000000+01:00",
          "rustc_channel": "stable",
          "rustc_version": "1.84.1"
        },
        "declared_role": {
          "entry": true,
          "exit_ipr": true,
          "exit_nr": true,
          "mixnode": false
        },
        "host_information": {
          "hostname": "bwng1.bwnym.xyz",
          "ip_address": [
            "95.164.2.86"
          ],
          "keys": {
            "ed25519": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
            "x25519": "H6pFjqtdSVxkxEQ3wFnuSoobDAUqHx1bYMVJzPZdRByn",
            "x25519_noise": null
          }
        },
        "ip_packet_router": {
          "address": "7ms2D2uYiTuhX6MKeVL5rz5usgehEoxAAovwYm9nJyBF.3siMjk3wTU7ykaXLNi9c7LpX8yonYKPCA4BQoMwhsfTV@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb"
        },
        "last_polled": "2025-03-03 09:48:03.635274187 +00:00:00",
        "mixnet_websockets": {
          "ws_port": 9000,
          "wss_port": 9001
        },
        "network_requester": {
          "address": "HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
          "uses_exit_policy": true
        },
        "wireguard": {
          "port": 51822,
          "public_key": "6o8x9GitFjcrkjrJnivWaQCPnxXykQPYLneNr2FEB8Vq"
        }
      },
      "explorer_pretty_bond": {
        "identity_key": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
        "location": {
          "latitude": 52.5083,
          "longitude": 5.475,
          "two_letter_iso_country_code": "NL"
        },
        "owner": "n1cp5gq0apat6c7qmenqp5zjprn2vwvc7jl29j8r",
        "pledge_amount": {
          "amount": "100000000",
          "denom": "unym"
        }
      },
      "description": {
        "moniker": "bwn_g1",
        "website": "https://bwnym.xyz",
        "security_contact": "bwnym@proton.me",
        "details": "This gateway is part of the NYM project, which is dedicated to create outstanding privacy software that is legally compliant without sacrificing integrity or having any backdoors."
      },
      "last_probe_result": null,
      "last_probe_log": null,
      "last_testrun_utc": null,
      "last_updated_utc": "2025-03-03T10:45:48+00:00",
      "routing_score": 0.0,
      "config_score": 0
    },
```

If you have already run the API before, make sure to add the following to your script `--database-url "sqlite://node-status-api.sqlite?mode=rwc` so it will continue using the same DB.

### Functionality with Gateway Probe
If you want to enable Gateway node probes and have the NS API store that data, you need to periodically run the `nym-node-status-agent`, authenticated with your `nym-node-status-api` instance. Authentication is to make sure that only the `-agent` you are operating (or others you trust) are submitting data to your API instance.

#### Compile Gateway Probe
The `nym-node-status-agent` is a thin wrapper around the Gateway Probe binary which lives in the [Nym monorepo](https://github.com/nymtech/nym/tree/develop/nym-gateway-probe). Compile the probe by following the readme instructions there. You will point the `-agent` at this binary when doing Probe testruns.

#### Generate Keypair
```shell
<PATH/TO/>nym-node-status-agent generate-keypair --path <PATH/TO/KEY/FILE/TO/GENERATE>/<KEY_NAME>
# e.g.
# nym-node-status-agent generate-keypair --path ~/.ssh/ns-agent-key
```

You will then want to export the generated `public-key` so its accessible to the `nym-node-status-api` however you are setting your environmental variables, as `NODE_STATUS_API_AGENT_KEY_LIST`:

```bash
export NODE_STATUS_API_AGENT_KEY_LIST=<YOUR_KEY> # e.g. "H4z8kx5Kkf5JNQHfxaE1MwRndjDCD1C7HsVhHTFfBZ4J"
```

In this situation, you are probably only using one key. However, it is possible to set multiple keys as a comma seperated list, in case you wish to whitelist multiple `-agent`s to be able to submit to a single `-api` instance.

#### Run the Node Status Agent
```shell
<PATH/TO/>nym-node-status-agent run-probe --server-address http://127.0.0.1 --server-port 8000 --ns-api-auth-key "<NS_AGENT_PRIVATE_KEY>" --probe-path <PATH/TO/> nym-gateway-probe
```

You will see a lot of output like so:

```shell
listen_port=48586
public_key=3f95caf771b8a63b9bdae6c186f7aba2eae93483f1c82c0243b5e00c85b4ec26
preshared_key=0000000000000000000000000000000000000000000000000000000000000000
protocol_version=1
endpoint=185.186.78.251:51822
last_handshake_time_sec=0
last_handshake_time_nsec=0
tx_bytes=0
rx_bytes=0
persistent_keepalive_interval=0
allowed_ip=0.0.0.0/0
2025/03/03 18:58:28 Pinging nymtech.net seq=0
2025/03/03 18:58:29 Ping latency: 44.503483ms
2025/03/03 18:58:29 Pinging nymtech.net seq=1
2025/03/03 18:58:29 Ping latency: 42.852414ms
2025/03/03 18:58:29 Pinging nymtech.net seq=2
2025/03/03 18:58:29 Ping latency: 43.627256ms
2025/03/03 18:58:29 Pinging nymtech.net seq=3
2025/03/03 18:58:29 Ping latency: 43.638839ms
2025/03/03 18:58:29 Pinging nymtech.net seq=4
2025/03/03 18:58:29 Ping latency: 43.345357ms
2025/03/03 18:58:29 Pinging 1.1.1.1 seq=0
2025/03/03 18:58:29 Ping latency: 46.327233ms
2025/03/03 18:58:34 Pinging 1.1.1.1 seq=1
2025/03/03 18:58:34 Ping latency: 46.273726ms
2025/03/03 18:58:39 Pinging 1.1.1.1 seq=2
2025/03/03 18:58:39 Ping latency: 46.542774ms
2025/03/03 18:58:44 Pinging 1.1.1.1 seq=3
2025/03/03 18:58:44 Ping latency: 45.663545ms
2025/03/03 18:58:49 Pinging 1.1.1.1 seq=4
2025/03/03 18:58:49 Ping latency: 43.803063ms
2025/03/03 18:58:56 Downloaded file content length: 1.00 MB
2025/03/03 18:58:56 Download duration: 1.308072386s
2025/03/03 18:58:56 private_key=1083749e43f4f8fb008f3f7deef9107ef86a68969670ddbb9f07bf85f94fb564
listen_port=39129
public_key=3f95caf771b8a63b9bdae6c186f7aba2eae93483f1c82c0243b5e00c85b4ec26
preshared_key=0000000000000000000000000000000000000000000000000000000000000000
protocol_version=1
endpoint=185.186.78.251:51822
last_handshake_time_sec=0
last_handshake_time_nsec=0
tx_bytes=0
rx_bytes=0
persistent_keepalive_interval=0
allowed_ip=::/0
2025/03/03 18:58:56 Pinging ipv6.google.com seq=0
2025/03/03 18:58:56 Ping latency: 42.839528ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=1
2025/03/03 18:58:56 Ping latency: 54.844651ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=2
2025/03/03 18:58:56 Ping latency: 51.23104ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=3
2025/03/03 18:58:56 Ping latency: 43.320409ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=4
2025/03/03 18:58:56 Ping latency: 63.517358ms
2025/03/03 18:58:56 Pinging 2001:4860:4860::8888 seq=0
2025/03/03 18:58:56 Ping latency: 54.682534ms
2025/03/03 18:59:01 Pinging 2001:4860:4860::8888 seq=1
2025/03/03 18:59:01 Ping latency: 55.56235ms
2025/03/03 18:59:06 Pinging 2001:4860:4860::8888 seq=2
2025/03/03 18:59:06 Ping latency: 55.970418ms
2025/03/03 18:59:11 Pinging 2001:4860:4860::8888 seq=3
2025/03/03 18:59:14 Failed to send ping: i/o timeout
2025/03/03 18:59:19 Pinging 2001:4860:4860::8888 seq=4
2025/03/03 18:59:22 Failed to send ping: i/o timeout
2025/03/03 18:59:27 Pinging 2606:4700:4700::1111 seq=0
2025/03/03 18:59:27 Ping latency: 45.072616ms
2025/03/03 18:59:32 Pinging 2606:4700:4700::1111 seq=1
2025/03/03 18:59:32 Ping latency: 44.357306ms
2025/03/03 18:59:37 Pinging 2606:4700:4700::1111 seq=2
2025/03/03 18:59:37 Ping latency: 44.013562ms
2025/03/03 18:59:42 Pinging 2606:4700:4700::1111 seq=3
2025/03/03 18:59:42 Ping latency: 46.94342ms
2025/03/03 18:59:47 Pinging 2606:4700:4700::1111 seq=4
2025/03/03 18:59:48 Ping latency: 43.372288ms
2025/03/03 18:59:53 Pinging 2620:fe::fe seq=0
2025/03/03 18:59:53 Ping latency: 42.164952ms
2025/03/03 18:59:58 Pinging 2620:fe::fe seq=1
2025/03/03 18:59:58 Ping latency: 42.295812ms
2025/03/03 19:00:03 Pinging 2620:fe::fe seq=2
2025/03/03 19:00:03 Ping latency: 43.117534ms
2025/03/03 19:00:08 Pinging 2620:fe::fe seq=3
2025/03/03 19:00:08 Ping latency: 44.26068ms
2025/03/03 19:00:13 Pinging 2620:fe::fe seq=4
2025/03/03 19:00:13 Ping latency: 45.29956ms
2025/03/03 19:00:21 Downloaded file content length: 10.00 MB
2025/03/03 19:00:21 Download duration: 3.39529252s
```

Whilst you can run the `-agent` directly, it might be easier to run multiple instances in parallel with a script like so:

```bash
#!/bin/bash

set -eu
export ENVIRONMENT=${ENVIRONMENT:-"mainnet"}

probe_git_ref="nym-vpn-core-v1.4.0" # check for the most recent release
monorepo_root=<PATH/TO/NYM/>

set -a
source "${monorepo_root}/envs/${ENVIRONMENT}.env"
set +a

export RUST_LOG="info"
export NODE_STATUS_AGENT_SERVER_ADDRESS="http://127.0.0.1"
export NODE_STATUS_AGENT_SERVER_PORT="8000"
export NODE_STATUS_AGENT_AUTH_KEY=<NS_AGENT_PRIVATE_KEY>
export NODE_STATUS_AGENT_PROBE_MNEMONIC=<NS_AGENT_MNEMONIC>
export NODE_STATUS_AGENT_PROBE_EXTRA_ARGS="netstack-download-timeout-sec=30,netstack-num-ping=2,netstack-send-timeout-sec=1,netstack-recv-timeout-sec=1"

workers=${1:-1}
echo "Running $workers workers in parallel"

function swarm() {
  local workers=$1

  for ((i = 1; i <= workers; i++)); do
    ${monorepo_root}/target/release/nym-node-status-agent run-probe --probe-path ${monorepo_root}/target/release/nym-gateway-probe &
  done

  wait

  echo "All agents completed"
}

swarm $workers
```

And run specifying the number of workers with `./<SCRIPT_NAME>.sh <NUMBER_OF_WORKERS>`.

When running the probe, use logging level `RUST_LOG=info`. The Node Status API relies on that granularity for parsing probe results, and the logs grow incessantly if a lower level (e.g. `DEBUG`) is used.

### Ports
By default the API listens on `8000`, so you will need to configure this post to be reachable on your remote server. You can modify this with the `--http_port` flag.

---
title: Nym Gateway Probe
url: https://nym.com/docs/operators/performance-and-testing/gateway-probe
---

# Nym Gateway Probe

Nym Node operators running Gateway functionality are already familiar with the monitoring tool [Harbourmaster.nymtech.net](https://harbourmaster.nymtech.net). Under the hood of Nym Harbourmaster runs iterations of `nym-gateway-probe` doing various checks and displaying the results on the interface. Operators don't have to rely on the probe ran by Nym and wait for the data to refresh. With `nym-gateway-probe` everyone can check any Gateway's networking status from their own computer at any time. In one command the client queries data from:

- [`nym-api`](https://validator.nymtech.net/api/v1/nym-nodes/described)
- [`explorer-api`](https://mainnet-node-status-api.nymtech.cc/swagger/#/Gateways)
- [`harbour-master`](https://harbourmaster.nymtech.net/)

## Preparation

We recommend to have installed all [the prerequisites](../binaries/building-nym.md#prerequisites) needed to build `nym-node` from source including latest [Rust Toolchain](https://www.rust-lang.org/tools/install), **and** make sure to have [Go](https://go.dev/doc/install) installed. Go is necessary as the probe uses the `rust2go` FFI library to use `netstack` when making requests.

## Installation

`nym-gateway-probe` source code is in [`nym` monorepo](https://github.com/nymtech/nym). The probe needs to be built from source.

1. Clone the repository:

```sh
git clone https://github.com/nymtech/nym.git
```

2. Build `nym-gateway-probe`:

```sh
cargo build --release -p nym-gateway-probe
```

## Running the Client

To list all commands and options run the binary with `--help` command:

```sh
./target/release/nym-gateway-probe --help
```

```sh
Usage: nym-gateway-probe [OPTIONS] <COMMAND>

Commands:
  run-local  Run the probe on an unannounced gateway. IP must be provided. Bypasses directory lookup
  run        Run the probe on a bonded gateway. Uses directory lookup
  run-ports  Check WG exit policy ports on a bonded gateway. Tests TCP connectivity through the WG tunnel for each port. Use --check-ports to pick specific ports, or --check-all-ports for the full exit policy list
  run-agent  Run the probe by NS agents
  help       Print this message or the help of the given subcommand(s)

Options:
  -c, --config-env-file <CONFIG_ENV_FILE>  Path pointing to an env file describing the network
      --no-log                             Disable logging during probe
  -h, --help                               Print help
  -V, --version                            Print version
```
</ AccordionTemplate>

Use `--help` with any sub-command, for example with `run --help`:

```sh
./target/release/nym-gateway-probe run --help
```

```sh
Run the probe on a bonded gateway. Uses directory lookup

Usage: nym-gateway-probe run [OPTIONS] --entry-gateway <ENTRY_GATEWAY> <--use-mock-ecash|--mnemonic <MNEMONIC>>

Options:
      --config-dir <CONFIG_DIR>
          Directory for credential and mixnet storage

  -g, --entry-gateway <ENTRY_GATEWAY>
          The specific gateway specified by ID

      --exit-gateway <EXIT_GATEWAY>
          Optional identity of the exit node to test, if not provided, entry_gateway is used

      --use-mock-ecash
          Use mock ecash credentials for testing (requires gateway with --lp-use-mock-ecash)

      --mnemonic <MNEMONIC>
          Mnemonic to get credentials from the blockchain. It needs NYMs

      --min-gateway-mixnet-performance <MIN_GATEWAY_MIXNET_PERFORMANCE>
          Only choose gateway with that minimum performance

      --no-log
          Disable logging during probe

      --test-mode <TEST_MODE>
          Test mode - explicitly specify which tests to run

          Modes:
            core        - Traditional mixnet testing (entry/exit pings + WireGuard via authenticator)
            wg-mix      - Wireguard via authenticator
            wg-lp       - Entry LP + Exit LP (nested forwarding) + WireGuard
            lp-only     - LP registration only (no WireGuard)
            socks5-only - Socks5 network requester test
            all         - Mixnet, wireguard over authenticator and LP registration

          [default: core]

      --ignore-egress-epoch-role

      --amnezia-args <AMNEZIA_ARGS>
          Arguments to be appended to the wireguard config enabling amnezia-wg configuration

      --use-target <PORT_CHECK_TARGET>
          Target host for exit policy port checks (must listen on all tested ports)

          [default: portquiz.net]

      --check-ports <PORT_CHECK_PORTS>
          TCP ports to check through the WireGuard tunnel for exit policy verification. Only used with the `run-ports` subcommand. For all exit policy ports, use --check-all-ports instead

      --port-check-timeout-sec <PORT_CHECK_TIMEOUT_SEC>
          Timeout in seconds for each individual TCP port check

          [default: 5]

  -h, --help
          Print help (see a summary with '-h')
```
</ AccordionTemplate>

To run you must run it with a mnemonic of a funded Nyx account; this is required to test the ticketbook generation. **Note that this accout needs to have NYM tokens; you cannot use an account with a NymVPN subscription**. Make sure to have at least a few NYM tokens in there.

- Always add this:
```sh
--mnemonic <MNEMONIC>
```

For any `nym-node --mode exit-gateway` the aim is to have this outcome:

```json
{
  "gateway": "<GATEWAY_IDENTITY_KEY>",
  "outcome": {
    "as_entry": {
      "can_connect": true,
      "can_route": true
    },
    "as_exit": {
      "can_connect": true,
      "can_route_ip_v4": true,
      "can_route_ip_external_v4": true,
      "can_route_ip_v6": true,
      "can_route_ip_external_v6": true
    },
    "wg": {
      "can_register": true,
      "can_handshake": true,
      "can_resolve_dns": true,
      "ping_hosts_performance": 1.0,
      "ping_ips_performance": 1.0
    }
  }
}
```

---
title: Gateway Probes Details & Contradictions
url: https://nym.com/docs/operators/performance-and-testing/gateway-probe-details
---

# Gateway Probes Details & Contradictions

## Summary

A simplified explanation of node performance measuring is that the [Node Status API](https://node-status.nym.com) runs [gateway probes](/operators/performance-and-testing/gateway-probe) that connect to gateways to:

- Check the configuration of gateways
  - Checks a list of capabilities (e.g. can route IPv4 traffic in mixnet mode)
  - Checks a list of configuration (e.g. runs <abbr title={IPR}>IPR</abbr>, has exit policy)
- Acts like a user:
  - Registers a mixnet client
  - Registers a wireguard peer and tops up bandwidth with a zk-nym
  - Sends <abbr title={ICMP}>ICMP</abbr> ping packets
  - Downloads files

The results are collected and stored in the [Node Status API](https://node-status.nym.com) and can be also veiwed per node in [Node Status Observatory](https://harbourmaster.nymtech.net).

The [NymVPN API directory](https://nymvpn.com/api/public/v1/directory/gateways) cache uses the output of the gateway probes to calculate and display hints to users about the contention on each gateway and what they might expect if they use the gateway.

## Heisenberg’s Uncertainty Principle for Gateways

> The uncertainty principle, also known as Heisenberg's indeterminacy principle, is a fundamental concept in quantum mechanics. It states that there is a limit to the precision with which certain pairs of physical properties, such as position and momentum, can be simultaneously known. In other words, the more accurately one property is measured, the less accurately the other property can be known.
>
> [https://en.wikipedia.org/wiki/Uncertainty\_principle](https://en.wikipedia.org/wiki/Uncertainty_principle)

The nodes in the Nym network are run by independent operators, so we can only know:

- What we see from the outside
  - Probes can run tests like users
  - Users can report performance from a Gateway (also includes the performance of the user’s internet connection and the speed of the host they are using)
- What we ask operators to report
  - They can lie
  - We can’t check them

### Gateway Probe Generates a Stream to Fill Available Bandwidth on Gateway

The probe can check a Gateway periodically and can generate a traffic stream to use the remaining bandwidth:

![](/images/operators/performance/perceived-gw-dwl.png)

Depending on how busy the Gateway is with user streams, the probe will report different values for the available remaining bandwidth.

This is currently what we do with downloading a 10MB file

If the timing of the probe and user activity overlaps, then the “available bandwidth” remaining looks like this from the probe’s perspective:

![](/images/operators/performance/bandwith-probe-user-overlaps.png)

### Fully Utilised Gateways Will Have Low Availability

If a Gateway is popular, then there will not be a lot of room for the probe’s stream:

![](/images/operators/performance/popular-gw-probe.png)

The Gateway is doing a fine job is serving 92.5% of its available capacity to clients, and it only have 7.5Mbps available for another user.

Is that enough for a user? Only they can know!

### Can Another Netflix 4k Stream Fit?

Streaming Netflix at 4k takes anywhere from 11-15Mbps, so lets see what that looks like in a few cases:

###### “Yay, Netflix will fit most of the time”

![](/images/operators/performance/netflix-fits-bandwidth.png)

###### “Netflix is not going to fit”

![](/images/operators/performance/netflix-not-fit.png)

### Does Measuring Affect Users of the Gateway?

If we add heavy traffic streams to Gateways, what happens to other users?

Imagine there are 6 \* Netflix 4k users on a 100Mbps Gateway, let's look at different traffic stream scenarios:

###### Take the space of 2 streams

Two users will stall while we use their space:

![](/images/operators/performance/two-streams-space.png)

###### Scale the user space down by the test stream

Adjust the Gateway settings to force users into less bandwidth and make the test take priority:

*Sad users for 5 minutes*

![](/images/operators/performance/sad-users.png)

*Angry users for 5 minutes*

![](/images/operators/performance/angry-users.png)

*Furious users for 5 minutes*

![](/images/operators/performance/furious-users.png)

## Gateways, IaaS and Network Quotas

IaaS providers like Linode, AWS, etc and data centre providers have a mix of methods where they can cap or rate limit VMs or physical connections:

- **Fixed quota:** you can only use the outbound networking available, e.g. AWS limits to 100Mbps

![](/images/operators/performance/capped-bandwidth.png)

- **Fixed quota with burst:** you get a fixed outbound network rate, but can burst above it
  - You pay penalties when you burst - many data centres and fixed lines do this
  - You have a leaky bucket - you can only burst with your saved quota

![](/images/operators/performance/burst-charges.png)

- **Leaky bucket quota:** you start with a small quota that builds up to a maximum, but once you use your “saved quota” you drop down to the rate at which your quota comes in. Or sometimes no matter how much you pour into the bucket, only a fixed amount drains out the other side (see [https://en.wikipedia.org/wiki/Leaky\_bucket](https://en.wikipedia.org/wiki/Leaky_bucket))

![](/images/operators/performance/leaky-bucket.png)

This means that if there is a flexible quota, a gateway with high usage, can burn through its quota early in the monthly billing cycle leaving it rate limited for the majority of the month:

![](/images/operators/performance/vps-quota.png)

The cheaper the VPS, the more it is likely to be rate limited or have a leaky bucket quota that will appear to users as “unreliable”.

The best hosts will be ones with a fixed bandwidth that is capped by the hosting provider with network equipment, because:

- Users will scale with the available bandwidth
- No weird side effects of quotas
- Most predictable behaviour
- Will not be the cheapest, but will also not be the most expensive

Bursting sounds attractive, but could be financially crippling for operators.

---
title: Prometheus & Grafana
url: https://nym.com/docs/operators/performance-and-testing/prometheus-grafana
---

# Prometheus & Grafana

Besides monitoring node performance, it's quite useful to setup monitoring system for servers on which operators run their nodes.

The combination of Prometheus and Grafana is a common stack used by Nym team for internal monitoring as well as by core community operators like [ExploreNym](https://github.com/ExploreNYM/self-hosted-monitor).

## Prometheus

[Prometheus](https://prometheus.io) is a free and open source monitoring systems. It allows operators to have their metrics, events, and alerts under full control. This ecosystem offers multiple advantages:

- Collects and records metrics from servers, containers, and applications
- Provides a [flexible query language (PromQL)](https://prometheus.io/docs/prometheus/latest/querying/basics/)
- Multiple modes visualization tools
- An alerting mechanism that sends notifications

Prometheus collects and stores its metrics as time series data, i.e. metrics information is stored with the timestamp at which it was recorded, alongside optional key-value pairs called labels.

## Grafana

[Grafana](https://grafana.com/docs/grafana/latest/) is an open-source analytics and interactive front end. It is widely used for its easy to manage dashboards with visualizations like graphs, charts and alerts, all connected to live data sources.

## Setup Guides

There are various ways how to setup this stack. You can chose based on your preferences to do your own flow or follow some of the documented ones:

- [ExploreNYM scripts](prometheus-grafana/explorenym-scripts.mdx) for self-hosted monitoring
- Setup monitoring in a Docker container (*Under review - will be out soon*)

## References and further reading

* [Prometheus release page](https://prometheus.io/download/)
* [Prometheus documentation](https://prometheus.io/docs/introduction/overview/)
* Installation [guide to install Prometheus](https://www.cherryservers.com/blog/install-prometheus-ubuntu) on Ubuntu by cherryservers
* [Grafana installation guide](https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/)
* Nym's script [`prom_targets.py`](https://github.com/nymtech/nym/blob/develop/scripts/prom_targets.py) - a python program to request data from API and can be plugged to this stack
* [Nym-node CPU cron service](https://gist.github.com/tommyv1987/97e939a7adf491333d686a8eaa68d4bd) - an easy bash script by Nym core developer [@tommy1987](https://gist.github.com/tommyv1987), designed to monitor a CPU usage of your node, running locally

---
title: ExploreNym Monitoring Scripts
url: https://nym.com/docs/operators/performance-and-testing/prometheus-grafana/explorenym-scripts
---

# ExploreNym Monitoring Scripts

This setup and the scripts included were not written by Nym developers. As always do your own audit before installing any scripts on your machine and familiarize yourself with the security risks involved when opening ports or allowing http access.

## Community Monitoring Tools

Individual operators, node families and squads are the foundation of distributed network. There has been a great number of tools coming out of this community some of which can be deployed for the node monitoring setup.

## ExploreNYM Tools

Long term involved operator Pawnflake, an author of [ExploreNYM](https://explorenym.net/) explorer, created a monitoring flow, which can be used by other operators called [`self-hosted-monitor`](https://github.com/ExploreNYM/self-hosted-monitor). It utilises bash scripts to enable operators setup [Prometheus](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/prometheus.sh) and [Grafana](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/grafana.sh) together with [Node Exporter](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/node-exporter.sh) and [Nginx](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/nginx-certbot.sh) to run their metrics monitoring stack locally.

In collaboration with ExploreNYM we published a [step by step guide](#setup) to set this up.

ExploreNYM also has a network measuring instance called `enym-monitor`. This setup is very simple for users, however it means that their data are all aggregated into one server such design always brings a risk of centralisation of distributed node's data into one computer.

Make sure you understand and properly evaluate what degree of control you give permission to before granting access to your data to any tools running on someone else's servers.

## Setup

**Minimum requirements of the monitor stack**

- 2 CPU
- 4 GB RAM
- 20 GB of free disk space.

SSH to your server as `root` or become one running `sudo -i` or `su`. If you prefer to administrate your VPS from a user environment, supply the commands with prefix `sudo`.

###### 1. The monitoring part setup

This can be setup on another VPS than the node if desired. We recommend to try to set this up on the same VPS, as your node as we expect the machine to be strong enough to handle the node with enough capacity reserve for monitor.

- Install git
```sh
apt install git
```

- Clone the repository to `~/self-hosted-monitor`
```sh
git clone https://github.com/ExploreNYM/self-hosted-monitor ~/self-hosted-monitor
```

- Give permissions to [`prometheus.sh`](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/prometheus.sh) script and run it to setup Prometheus
```sh
chmod +x ~/self-hosted-monitor/prometheus.sh && ~/self-hosted-monitor/prometheus.sh
```

- Give permissions to [`grafana.sh`](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/grafana.sh) script and run it to setup Grafana
```sh
chmod +x ~/self-hosted-monitor/grafana.sh && ~/self-hosted-monitor/grafana.sh
```

- Open port `3000` to allow access to Grafana
```sh
sudo ufw allow 3000
```

- You can now access Grafana at `http://<IP_ADDRESS>:3000`.

- *Optional step*: If you have a registered domain and prefer to use  it with `https`, give permissions to [`nginx-certbot.sh`](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/nginx-certbot.sh) script and run it to setup Nginx and Certbot
```sh
chmod +x ~/self-hosted-monitor/nginx-certbot.sh && ~/self-hosted-monitor/nginx-certbot.sh
```

- Give permissions to [`prometheus-target.sh`](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/prometheus-target.sh) script and run it to add a scrape target. This can be run multiple times to add a new server to be monitored via Prometheus/
```sh
chmod +x ~/self-hosted-monitor/prometheus-target.sh && ~/self-hosted-monitor/prometheus-target.sh
```

###### 2. The target server (the part to be monitored) setup

- In case you run this part on another VPS: Install git
```sh
apt install git
```

- In case you run this part on another VPS: Clone the repository to `~/self-hosted-monitor`
```sh
git clone https://github.com/ExploreNYM/self-hosted-monitor ~/self-hosted-monitor
```

- Give permissions to [`node-exporter.sh`](https://github.com/ExploreNYM/self-hosted-monitor/blob/main/node-exporter.sh) script and run it to setup Node exporter.
```sh
chmod +x ~/self-hosted-monitor/node-exporter.sh && ~/self-hosted-monitor/node-exporter.sh
```

###### 3. Grafana dashboard setup

Finally we need to access Grafana dashboards.

- Open a browser at `http://<IP_ADDRESS>:3000` or `https://<HOSTNAME>` (depends on your setup), enter username `admin` and password `admin` and setup new credentials on prompt

- Setup *Data source* by opening menu -> `Connections` -> `Data sources` -> `+ Add new data source` -> `Prometheus`

![](/images/operators/grafana/add-data-sources.png)
![](/images/operators/grafana/add-data-source-prometheus.png)

- In the field *Connection* next to `Prometheus server URL` enter `http://localhost:9090` (regardless if you accessing Grafana via `http` or `https` as this is for internal connection on the server). When you are done in the bottom confirm by `Save & Test`

- In the menu open: `Dashboards` -> `+ Create dashboard` -> `Import dashboard`

![](/images/operators/grafana/import-dashboard.png)

- ID field: enter `1860` -> `Load`

![](/images/operators/grafana/id-1860.png)

- In *Import dashboard* page select Prometheus in the bottom and finally `Import`

![](/images/operators/grafana/add-prometheus.png)

Now you have your Prometheus panels displayed via Grafana dashboard for a simple monitoring of your node.

## Verification and Troubleshooting

To ensure that your services are running correctly, you can verify that by running `systemctl status <SERVICE>` or run a `journalctl -f -u <SERVICE>` to print service logs. It shall return status `Active: active (running)`. For example:

- To check if Prometheus service is active:
```sh
systemctl status prometheus
```

- To check if Grafana service is active:
```sh
systemctl status grafana-server
```

- To check if node-exporter service is active:
```sh
systemctl status node_exporter
```

- To run journal log:
```sh
journalctl -f -u prometheus # or any other service you want to see
```

---
title: Tools
url: https://nym.com/docs/operators/tools
---

export const NymNodeCliCommand = () => (

    Arguments and options: <code>./nym-node-cli.py install --help</code>

);

# Tools

On this page you can find tools to [setup a node automatically](#nym-node-cli), [explorers](#explorers) and other useful dashboards and [scripts](#cmd-reward-tracker).

## Explorers

Nym Network stats can be humanly read on some of the explorers and dashboards.

- **[Nym Explorer v2](https://nym.com/explorer):** Official Nym Explorer

- **[SpectreDAO Explorer](https://explorer.nym.spectredao.net/):** By operators for operators - currently the most used Nym explorer

- **[Nym Node Status Observatory](https://harbourmaster.nymtech.net/):** An explorer with a list of Nym Nodes, their properformance and per node data

- **[Nym Node Status UI](https://node-status.nym.com/):** A dashboard displaying results of Gateway probes and much more in one table

- **[Nymesis](https://nymesis.vercel.app/):** A slick dashboard by operator community

## Nym Node CLI

This interactive command-line-based tool takes an operator through a journey of installing, configuring and starting a `nym-node` as a systemd service, doing most of the steps automatically for them.

**Installation & Running**

###### 1. SSH into your server (VPS)

- The installation of `nym-node` using this program requires you to run as `root`

###### 2. Download `nym-node-cli.py` and make executable

```sh
wget https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/nym-node-setup/nym-node-cli.py && \
chmod +x ./nym-node-cli.py
```

###### 3. Run the program

There are two ways how to run the program. fully interactive or with provided arguments. The former has a shorter initial command but then operators must fill the values on the go, the latter requires more complex command, but then there is a minimum prompts during the process.

1. Fully interactive mode - just run:
```sh
./nym-node-cli.py install
```

2. Use arguments - run this command to see all options:
```sh
./nym-node-cli.py install --help
```
<AccordionTemplate name={<NymNodeCliCommand/>}>

</ AccordionTemplate>
- An example can look like this:
```sh
# substitute with your real values:
./nym-node-cli.py install
  --hostname node-install.devrel.nymte.ch
  --moniker MainnetGW-DE
  --description "This node is installed with nym-node-cli v1.2.0"
  --wireguard-enabled true
  --location DE
  --mode exit-gateway
  --email kawa_hesinkar@example.ku
```

###### 4. Read and follow the prompts

There ware a few required confirmations and in case of running the program without the arguments, you will be prompted for values neccessary to setup a `nym-node` and configure your server.

**Read these prompts carefully!**

###### 5. Setup finished

Congratulation, your node is installed.

This version of the program does not prompt an operator for the local node moniker (`--id <ID>`) therefore it asigns your node an automatic one `default-nym-node`.

All configuration and data of your node can be found in this location:
```sh
ls $HOME/.nym/nym-nodes/default-nym-node/
```
</ Steps>

## CMD Reward Tracker

A command-line-based program locally calculating nodes rewards based on provided Nyx account addresses in `data/wallet-addresses.csv`.

**Installation & Running**

###### 1. Pull / clone `nymtech/nym` repository

- Open terminal and navigate to where you want to have `nym` repostiry and run:
```sh
git clone https://github.com/nymtech/nym
```

###### 2. Add your Nyx accounts to `wallet-addresses.csv`

- Navigate to `nym/scripts/rewards-tracker/data`
- Open `wallet-addresses.csv` in your favourite text editor or a sheet managing tool (Like Libre Office Calc)
- To the first collumn called `address` add all Nyx addresses you want to track
- Delete all `add_wallet_or_delete` template examples

###### 3. Add entity to `wallet-addresses.csv` - optional

- In the same file operators who want to separate their nodes by an entity, can add this entity to the `tag` column
- If not leave this column empty - delete all `optional_tag_or_delete` fields

- Csv example with `tag`s:
```
address, tag
n1foofoofoo, personal
n1barbarbar, personal
n1bazbazbaz, mysquad
n1lollollol, mysquad
```
- For operators having all nodes under one entity, the tag field will be left empty. Example:
```csv
address, tag
n1foofoofoo
n1barbarbar
n1bazbazbaz
```

###### 4. Save `wallet-addresses.csv` and exit

###### 5. Run the program

- In terminal navigate to `nym/scripts/rewards-tracker`
- Run the program:
```
./node_rewards_tracker.py
```
</ Steps>

**The Output**

The result of running `node_rewards_tracker.py` is:

1. Printed table in terminal
2. Updated sheet with complete info stored in `data/node-balances.csv`
3. Historical data file stored in `data/data.yaml` - this file should not be changed manually, as all values older than 30 days get auto-removed

## Node Ping Tester

This tool is used to diagnose how many nodes providing self-described endpoint allow your IP to ping them. It's a very simple script fetching all [`/described`](https://validator.nymtech.net/api/v1/nym-nodes/described) nodes and trying to ping each of them.

The output is collected into two files:
```
  ├── ping_not_working.csv
  └── ping_works.csv
```

**Installation & Running**

###### 1. SSH into your node server (VPS)

###### 2. Download and make executable

- Navigate to the directory where you want to have this script
- Download and make executable:
```sh
wget https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/test-nodes-pings.sh && \
chmod +x test-nodes-pings.sh
```

###### 3. Run the script

- Default running command is straight forward
```sh
./test-nodes-pings.sh
```
- If you want to increase the `ping` attempts from default 2 or lower the concurency, feel free to change the variables, like this:
```sh
PING_RETRIES=10 PING_TIMEOUT=5 CONCURRENCY=16 ./test-nodes-pings.sh
```

You can look up the IPs from `ping_not_working.csv`, using some online database, like [ipinfo.io](https://ipinfo.io).

Feel invited to share the outcome with Nym team, mentors and the rest of the operators in our [Matrix Node Operators channel](https://matrix.to/#/#operators:nymtech.chat).

## Guides to Setup Own Metrics

A list of different tools, templates and guides for easier navigation:

* [`nym-gateway-probe`](performance-and-testing/gateway-probe.mdx): a useful tool used under the hood of [Node Status Observatory](https://harbourmaster.nymtech.net)

* [Diagnostic Tool](/developers/tools/diagnostic-tool): diagnose connectivity issues and provides insights into network performance

* [Prometheus and Grafana](performance-and-testing/prometheus-grafana.mdx) self-hosted setup

---
title: Troubleshooting VPS Setup
url: https://nym.com/docs/operators/troubleshooting/vps-isp
---

# Troubleshooting VPS Setup

## System Hygiene

Maintaining a Nym node requires keeping a good care of the hosting server. Running a `nym-node` as a standalone process or wrapped in a service can produce gigabytes of logs. Eventually your operation can malfunction due to the logs chewing up too much disk space or memory.

This chapter guides operators to address these points:

- Sudden *disk full* crashes
- `journald` runaway growth
- Duplicate `rsyslog` logs
- `nym-node` log growth
- `qcow2` like allocation growth inside VPS storage

Choose if you administer VPS based node manually, or self-administered VMs on a hypervizor, using [Ansible](/operators/orchestration/ansible).

`rm` is a powerful tool, without an easy way of revoking. If you need to extract or backup anything, do it now. Make sure you understand what you removing before you execute these commands.

  <Tabs items={[
    <strong>Prune logs: VPS</strong>,
    <strong>Prune logs: VM, hypervisor & Ansible</strong>,
    ]} defaultIndex="0">
    <MyTab><PruneLogsVPS /></MyTab>
    <MyTab><PruneLogsVM /></MyTab>

## IPv6 troubleshooting

To monitor connectivity of your Exit Gateway, use results of probe testing displayed in [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net).

### Incorrect Gateway Network Check

Nym operators community is working on a Nym version of tors [good bad ISP table](https://community.torproject.org/relay/community-resources/good-bad-isps/). There is no one solution fits all when it comes to connectivity setup. The operation of `nym-node` will vary depending on your ISP and chosen system/distribution.  While few machines will work out of the box, most will work after uisng our connectivity configuration guide, some need more adjustments.

Begin with the steps listed in [*Connectivity Test and Configuration*](../nodes/preliminary-steps/vps-setup.mdx#connectivity-test-and-configuration) chapter of the VPS setup page. If you still have a problem with the IPv6 connectivity try:

1. Nym operators community started an ISP table called [*Where to host your nym node?*](../community-counsel/isp-list.mdx), check it out and add your findings!

2. Tor community created a helpful [table of ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/). Make sure your one is listed there as a *"good ISP"*. If not, consider migrating!

3. Checkout your VPS dashboard and make sure your IPv6-public enabled.

4. If you are able to add IPv6 address `/64` range, do it.

![](/images/operators/ipv6_64.png)

5. Search or ask your ISP for additional documentation related to IPv6 routing and ask them to provide you with `IPv6 IP address` and `IPv6 IP gateway address`
- For example Digital Ocean setup isn't the most straight forward, but it's [well documented](https://docs.digitalocean.com/products/networking/ipv6/how-to/enable/#on-existing-droplets) and it works.

6. Search for guides regarding your particular system and distribution. For Debian based distributions using `systemd`, some generic guides such as [this one](https://cloudzy.com/blog/configure-ipv6-on-ubuntu/) or [this one](https://help.ovhcloud.com/csm/en-ie-vps-configuring-ipv6?id=kb_article_view&sysparm_article=KB0047567) work as well.

### Network configuration

On modern Debian based Linux distributions, the network is configured by either [Netplan](https://netplan.io/) or [ifup/ifdown](https://manpages.debian.org/testing/ifupdown/ifup.8.en.html) utilities. It is very easy to check which one you have.

- If you have the following folder `/etc/netplan` which has got a YAML file - you are likely to have Netplan.
- If you have the following folder `/etc/network` and it is not empty - you are likely to have ifup/down.

Most contemporary Ubuntu/Debian distributions come with Netplan, however it is possible that your hosting provider is using a custom version of ISO. For example, Debian 12 (latest version as of June 2024) may come with ifup/down.

Nym operator community members have tested a VPS with Netplan and where in some cases `nym-node --mode exit-gateway` was not routing IP packets properly even after running `network_tunnel_manager.sh` script. We are working on a guide to setup Netplan configuration manually for such cases.

Configuration of ifup/ifdown is a bit simpler. If the `network_tunnel_manager.sh` script doesn't do the job, open `/etc/network/interfaces` file (research if your system uses a different naming for it) and configure it similarly to this:

```ini
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address <YOUR_IPV4_ADDRESS>
netmask NETMASK

gateway <ISP_IPV4_GATEWAY>
iface eth0 inet6 static
        accept_ra 0
        address <YOUR_IPV6_ADDRESS>
        netmask 64
        gateway <ISP_IPV6_GATEWAY>
post-up /sbin/ip -r route add <YOUR_IPV6_GATEWAY> dev eth0
post-up /sbin/ip -r route add default via <YOUR_IPV6_GATEWAY>
```
Last two lines are particularly important as they enable IPv6 routing. You can find YOUR_IPV6_GATEWAY using your server's control panel. There is no single way to find the gateway, so please access your control panel to find yours or open a support ticket. Here is an example of how it looks on [OVH](https://help.ovhcloud.com/csm/en-ie-vps-configuring-ipv6?id=kb_article_view&sysparm_article=KB0047567).

Be extra careful editing this file since you may lock yourself out of the server. If it happens, you can always access the server via the hoster's VNC panel.

Once finished, save the file and reboot the server. Now, running `ip a` command should return correct IPv4 and IPv6 addresses.

Finally re-run `network_tunnel_manager.sh` script, following the steps in node [IPv6 configuration chapter](../nodes/nym-node/configuration.mdx#ipv6-configuration).

## Other VPS troubleshooting

### Virtual IPs and hosting via Google & AWS

For true internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a `<NODE>` there, please read the following.

On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl -4 https://ifconfig.me)`, but that may not the public IP address to bond your `<NODE>` in the wallet.

You can run `ifconfig` command. For example, on a Google machine, you may see the following output:

```sh
ens4: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1460
        inet 10.126.5.7  netmask 255.255.255.255  broadcast 0.0.0.0
        ...
```

The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`.

To find the right IP configuration, contact your VPS provider for support to find the right public IP and use it to bond your `<NODE>` with the `nym-api` via Nym wallet.

### Self-hosted nodes

On self-hosted machine it's a bit more tricky. In that case as an operator you must be sure that your ISP allows for public IPv4 and IPv6 and then it may be a bit of playing around to find the right configuration. One way may be to bind your binary with the `--host` flag to local address `127.0.0.1` and run `echo "$(curl -4 https://ifconfig.me)"` to get a public address which you use to bond your Mix Node to `nym-api` via Nym wallet.

It's up to you as a node operator to ensure that your public and private IPs match up properly.

---
title: Nym Node Troubleshooting: Common Errors & Fixes
description: Solutions for common nym-node issues including build failures, connectivity problems, and configuration errors. Includes error messages and fix steps.
url: https://nym.com/docs/operators/troubleshooting/nodes
---

# Nym Node Troubleshooting

If you have problems running a `nym-node` you are likely to find a solution here.

## Binary Build Problems

### I am trying to build from the GitHub archive files and the build fails

GitHub automatically includes `.zip` and `tar.gz` files of the Nym repository in its release. You cannot extract these and build - you'll see something like this:

```sh
  process didn't exit successfully: `/build/nym/src/nym-0.12.1/target/release/build/nym-socks5-client-c1d0f76a8c7d7e9a/build-script-build` (exit status: 101)
  --- stderr
  thread 'main' panicked at 'failed to extract build metadata: could not find repository from '/build/nym/src/nym-0.12.1/clients/socks5'; class=Repository (6); code=NotFound (-3)', clients/socks5/build.rs:7:31
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: build failed
```

Why does this happen?

We have scripts which automatically include the Git commit hash and Git tag in the binary for easier debugging later. If you download a .zip and try building from that, it's not a Git repository and build will fail as above.

What to do?

* Follow the instructions in the Binaries section to [build nym from source](../binaries/building-nym.mdx) or [download precompiled binaries](../binaries/pre-built-binaries.mdx)
* To upgrade, follow the [upgrade instructions](../nodes/maintenance/manual-upgrade.mdx)

## General Node Config

### Where can I find my private and public keys and config?

All config and keys files are stored in a directory named after your node local identifier (`<ID>`) which you chosen (if not, default one is `default-nym-node`), and can be found at the following PATH: `$HOME/.nym/nym-node/<NODE_ID>` where `$HOME` is a home directory of the user (your current user in this case) that launched the node or client.

The directory structure for each node will be roughly as follows:

```sh
~/.nym/nym-nodes/
└── default-nym-node
    ├── config
    │   └── config.toml
    └── data
        ├── aes128ctr_ipr_ack
        ├── aes128ctr_nr_ack
        ├── clients.sqlite
        ├── cosmos_mnemonic
        ├── description.toml
        ├── ed25519_identity
        ├── ed25519_identity.pub
        ├── ed25519_ipr_identity
        ├── ed25519_ipr_identity.pub
        ├── ed25519_nr_identity
        ├── ed25519_nr_identity.pub
        ├── ipr_gateways_info_store.sqlite
        ├── nr_gateways_info_store.sqlite
        ├── nr_persistent_reply_store.sqlite
        ├── x25519_ipr_dh
        ├── x25519_ipr_dh.pub
        ├── x25519_noise
        ├── x25519_noise.pub
        ├── x25519_nr_dh
        ├── x25519_nr_dh.pub
        ├── x25519_sphinx
        └── x25519_sphinx.pub
```

If you `cat` the `public_sphinx.pem` key, the output will be different from the public key you will see on Nym [dashboard](https://nym.com/explorer). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding.

### Accidentally killing your node process on exiting session

When you close your current terminal session, you need to make sure you don't kill the Mix Node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](../nodes/nym-node/configuration.mdx#automating-your-node-with-tmux-and-systemd).

### What is `verloc` and do I have to configure my Nym Node to implement it?

`verloc` is short for _verifiable location_. Mix Nodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner.

You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet.

## Node Functionality Specific Troubleshooting

**Choose the mode that you want to troubleshoot.**

  <Tabs items={[
    <strong>Mode <code>mixnode</code></strong>,
    <strong>Mode <code>entry-gateway</code> & <code>exit-gateway</code></strong>,
    ]} defaultIndex="1">

## Mixnode Mode

### How can I tell my node is up and running and mixing traffic?

First of all check the 'Mixnodes' section of either of the Nym Network Explorers:
* [Mainnet](https://nym.com/explorer)
* [Sandbox testnet](https://sandbox-explorer.nymtech.net/)

You can also check [Nym Harbourmaster](https://harbourmaster.nymtech.net) which now also includes mixnode mode.

There are a few community explorers as well.

* [ExploreNYM](https://explorenym.net/)
* [Mixplorer](https://mixplorer.xyz/)

Enter your **identity key** to find your node. Check the contents of the `Mixnode stats` and `Routing score` sections.

[Here](https://github.com/cosmos/chain-registry/blob/master/nyx/chain.json#L183-L225) is a dictionary with Nyx chain registry entry regarding all explorers.

If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly.

#### Check from your VPS

Additional details can be obtained via various methods after you connect to your VPS:

##### Socket statistics with `ss`

```sh
sudo ss -s -t | grep 1789 # if you have specified a different port in your Mix Node config, change accordingly
```

This command should return a lot of data containing `ESTAB`. This command should work on every unix based system.

##### List open files and reliant processes with `lsof`

- Check if lsof is installed:
```sh
lsof -v
```

- Install if not installed
```sh
sudo apt install lsof
```

- Run against nym-mix-node node port
```sh
sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly
```
- This command should return something like this:

```sh
nym-node 103349 root   53u  IPv6 1333229972      0t0  TCP [2a03:b0c0:3:d0::ff3:f001]:57844->[2a01:4f9:c011:38ae::5]:1789 (ESTABLISHED)
nym-node 103349 root   54u  IPv4 1333229973      0t0  TCP nym:57104->194.5.78.73:1789 (ESTABLISHED)
nym-node 103349 root   55u  IPv4 1333229974      0t0  TCP nym:48130->static.236.109.119.168.clients.your-server.de:1789 (ESTABLISHED)
nym-node 103349 root   56u  IPv4 1333229975      0t0  TCP nym:52548->vmi572614.contaboserver.net:1789 (ESTABLISHED)
nym-node 103349 root   57u  IPv6 1333229976      0t0  TCP [2a03:b0c0:3:d0::ff3:f001]:43244->[2600:1f18:1031:2401:c04b:2f25:ca79:fef3]:1789 (ESTABLISHED)
```

##### Query `systemd` journal with `journalctl`

```sh
sudo journalctl -u nym-node -o cat | grep "Since startup mixed"
```

If you have created `nym-node.service` file (i.e. you are running your [Nym Node via `systemd`](../nodes/nym-node/configuration.mdx#systemd) - recommended) then this command shows you how many packets have you mixed so far, and should return a list of messages like this:

```sh
2021-05-18T12:35:24.057Z INFO  nym_node::node::metrics                      > Since startup mixed 233639 packets!
2021-05-18T12:38:02.178Z INFO  nym_node::node::metrics                      > Since startup mixed 233739 packets!
2021-05-18T12:40:32.344Z INFO  nym_node::node::metrics                      > Since startup mixed 233837 packets!
2021-05-18T12:46:08.549Z INFO  nym_node::node::metrics                      > Since startup mixed 234081 packets!
2021-05-18T12:56:57.129Z INFO  nym_node::node::metrics                      > Since startup mixed 234491 packets!
```

You can add ` | tail` to the end of the command to watch for new entries in real time if needed.

##### build-info

A `build-info` command prints the build information like commit hash, rust version, binary version just like what command `--version` does. However, you can also specify an `--output=json` flag that will format the whole output as a json, making it an order of magnitude easier to parse.

For example `./target/debug/nym-node --no-banner build-info --output json` will return:

```sh
{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"}
```

#### Check from your local machine

###### 1. Scan ports with `nmap`

```sh
nmap -p 1789 <PUBLIC_IP> -Pn
```

If your Nym Node is configured properly it should output something like this:

```sh
bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn

Host is up (0.053s latency).

PORT     STATE SERVICE
1789/tcp open  hello
```

###### 2. Check with `telnet`

Your node should connect to telnet when running:
```sh
telnet <PUBLIC_IP> <PORT>
```

###### 3. Query online nodes:

```sh
curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/'
```

Will return a list all nodes currently online.

You can query Gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the Mix Nodes and Gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`.

#### Check with Network API

We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your Mix Node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](../nodes/maintenance.md#metrics--api-endpoints).

For more information about available endpoints and their status, you can refer to:
```sh
# for http
http://<PUBLIC_IP>:8080/api/v1/swagger/#/

# for https reversed proxy
https://<HOSTNAME>/api/v1/swagger/#/
```

### Why is my node not mixing any packets?

If you are still unable to see your node on the dashboard, or your node is declaring it has not mixed any packets, there are several potential issues:

- The firewall on your host machine is not configured properly. Checkout the [instructions](../nodes/preliminary-steps/vps-setup.mdx#configure-your-firewall).
- You provided incorrect information when bonding your node.
- You are running your node from a VPS without IPv6 support.
- You did not configure your router firewall while running the node from your local machine behind NAT, or you are lacking IPv6 support
- Your Mix Node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](../nodes/nym-node/configuration.mdx#automating-your-node-with-tmux-and-systemd).

Your Nym Node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this!

#### Check IPv6 Connectivity

You can always check IPv6 address and connectivity by using some of these methods:

- Locally listed IPv6 addresses
```sh
ip -6 addr
```
- Globally reachable IPv6 addresses
```sh
ip -6 addr show scope global
```

- With DNS
```sh
dig -6 TXT +short o-o.myaddr.l.google.com @ns1.google.com
dig -t aaaa +short myip.opendns.com @resolver1.opendns.com
```

- https check
```sh
curl -6 https://ifconfig.co
curl -6 https://ipv6.icanhazip.com
```

- Using telnet
```sh
telnet -6 ipv6.telnetmyip.com
```
If your connection doesn't work make sure to follow [VPS IPv6 setup](../nodes/nym-node/configuration.mdx#connectivity-test-and-configuration). If there is more troubleshooting needed, check out [VPS IPv6 troubleshooting](vps-isp.mdx#ipv6-troubleshooting) page.

#### Incorrect bonding information

All delegated stake will be lost when un-bonding! However the Nym Node must be operational in the first place for the delegation to have any effect.

Check that you have provided the correct information when bonding your Nym Node in the web wallet interface. When in doubt and without any delegations on your node, un-bond and then re-bond your node!

### Running on a local machine behind NAT with no fixed IP address

Your ISP has to be IPv6 ready if you want to run a Nym Node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it.

Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone!

If all goes well and you have IPv6 available, you will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](#no-ipv6-connectivity).

Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support.

Make sure you check if your node is really mixing. We are aiming to improve the setup for operators running locally, however you may need a bit of patience to set this up from your home behind NAT.

### Common errors and warnings

Most of the `ERROR` and `WARN` messages in your node logs are benign - as long as your node outputs `since startup mixed X packets!` (`X` must be > 0) in your logs (and this number increases over time), your node is mixing packets. If you want to be sure, check the Nym [dashboard](https://sandbox-explorer.nymtech.net/) or see other ways on how to check if your node is mixing properly as outlined in the section [**How can I tell my node is up and running and mixing traffic?**](#how-can-i-tell-my-node-is-up-and-running-and-mixing-traffic?) above.

## Gateways Mode

### My `exit-gateway` is running but appears offline in the explorer

Let your Gateway run and follow these steps:

###### 1. Check if your [firewall configuration](../nodes/preliminary-steps/vps-setup.mdx#configure-your-firewall)

- If `ufw` is active and if the necessary ports are open / allowed, including the ones for Swagger page and Reversed proxy/WSS if this is your case.

###### 2. See if the Gateway is not on the [list of blacklisted Gateways](https://validator.nymtech.net/api/v1/gateways/blacklisted)

###### 3. If it's blacklisted, check out the [point below](#my-gateway-is-blacklisted)

### My Gateway is blacklisted

Nym API measures performance by routing traffic through the Mixnet. If the average of a Gateway's routing score in past 24h is less than 50%, the Gateway gets blacklisted and it remains so until its performance is higher than 50%.

In case your Gateway appeared on the [blacklist](https://validator.nymtech.net/api/v1/gateways/blacklisted), it's because there is some flaw in the configuration. The most common sources of problems are:

- Outdated version of `nym-node`
- Bonding before starting the node/service
- Bonding before opening [needed ports](../nodes/preliminary-steps/vps-setup.mdx#configure-your-firewall)
- VPS restarted without operator having a [systemd automation](../nodes/nym-node/configuration.mdx#systemd) or some alert notification flow setup (so the operator doesn't know the node was stopped)
- IP address or host is [incorrectly configured](../nodes/nym-node/setup.mdx)
- Process logs grew too big
- Node is wrapped in [systemd service](../nodes/nym-node/configuration.mdx#systemd) and the operator forgot to run `systemctl daemon-reload` after last changes

**What to do**

Begin with a sanity check by opening [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net) and check your node there. To see IPv4 and IPv6 routing in real time (harbourmaster can have a cache up to 90 min), run [Gateway Probe CLI](../performance-and-testing/gateway-probe.mdx).

Then follow these steps:

###### 1. Make sure your node is on the [latest version](../changelog.mdx) and it's running . Do *not* stop it if there is no need!

###### 2. Open all [needed ports](../nodes/preliminary-steps/vps-setup.mdx#configure-your-firewall)

###### 3. Check your `config.toml` - often people have filled `hostname` without the domain being registered to `nym-node` IP, or a wrong IP address after moving their node.

###### 4. [Check Gateway Connectivity](#check-gateway-connectivity)

###### 5. See logs of your Gateway and search [for errors](#nym-node-errors) - if you find any unusual one, you can ask in the [Element Node Operators](https://matrix.to/#/#operators:nymtech.chat) channel

If your logs show that your Node has `cover down: 0.00` that means that the embedded IPR and NR is not sending any cover traffic.

###### 6. [Check out if your `syslog`s](vps-isp.mdx#pruning-logs) aren't eating all your disk space and prune them

###### 7. When all problems are addressed: Restart the node service

Don't forget `systemctl daemon-reload`) and wait until your node gets above 50% of performance (average of last 24h) - this will likely take 24-48 hours. During this time your node is tested by `nym-api` and every positive response picks up your routing score.

###### 8. If your node doesn't pick up the routing score within 24h try changing mode

If it stayed on zero performance and you succeed in all the checks above, while your running in `--mode exit-gateway`, run it as `--mode entry-gateway`. When your node is above 75% performance (past 24h), switch back to `--mode exit-gateway`.

**Do not repeatedly restart your Nym Node without reason, your routing score will only get worse!**

### Check Gateway connectivity

Here are a few steps to check whether your Gateway is actually connecting.

###### 1. Check out the API endpoints

Start with checking if your Gateway IPR and NR is active. To determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint. For example:
```sh
# for http
http://<PUBLIC_IP>:8080/api/v1/roles
# or
http://<PUBLIC_IP>/api/v1/roles

# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/roles
```

Everything necessary will exist on your node by default. For instance, if you're running a mixnode, you'll find that a NR (Network Requester) and IPR (IP Packet Router) address exist, but they will be ignored in `mixnode` mode.

For more information about available endpoints and their status, you can refer to:
```sh
# for http
http://<PUBLIC_IP>:8080/api/v1/swagger/#/
# or
http://<PUBLIC_IP>/api/v1/swagger/#/

# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/swagger/#/
```

###### 2. Configure IPv4 and IPv6 tables and rules

In case you haven't lately, follow the steps in the node [configuration](../nodes/nym-node/configuration.mdx) chapter [connectivity test and configuration](../nodes/nym-node/configuration.mdx#connectivity-test-and-configuration).

###### 3. Test connectivity

Telnet - from your local machine try to connect to your VPS bu running:

```sh
telnet <PUBLIC_IP> <PORT>
```

[Websocket wcat](https://github.com/websockets/wscat):

- Install on your local machine:
```sh
sudo apt install node-ws
```

- Run `wscat` pointing to the IP of your VPS with port `9000`:
```
wscat -c ws://<PUBLIC_IP>:<PORT>
```

### My Exit Gateway "is still not online..."

The Nyx chain epoch takes up to 60 min. To prevent the Gateway getting blacklisted, it's essential to start it before the bonding process and let it running. In case it already got [blacklisted](#my-gateway-is-backlisted) check the steps above.

{/*
THIS NEEDS TO BE REWORKED
### When enabling `ip_packet_router` (IPR) I get a `client-core error`

This error tells you that you already have IPR keys in your data storage, to activate them you have two options:

1. Open `~/.nym/nym-nodes/<ID>/config/config.toml` and **set the correct values**
```toml
[ip_packer_router_enabled]
enabled = true

# UNDER [storage_paths] CHANGE
ip_packet_router_config = '~/.nym/nym-nodes/<ID>/config/ip_packet_router_config.toml'
```

2. Or **remove the IPR data storage and initialise a new one** with these commands
```toml
rm -rf ~/.nym/nym-nodes/<ID>/data/ip-packet-router-data

./nym-gateway setup-ip-packet-router --id <ID>
```

### My `ip_packet_router` (IPR) seems to not work

There are a few steps to mitigate problems with IPR:

1. Check out the issue right above regarding the [Exit Gateway config](#when-enabling-ip_packet_router-ipr-i-get-a-client-core-error)
2. Open your browser and checkout the Swagger UI page and see if all the roles are enabled:
```sh
# in case of IP
http://<YOUR_LISTENING_IP_ADDRESS>:8080/api/v1/roles

# in case of hostname domain
https://<YOUR_DOMAIN>/api/v1/roles
```
3. Make sure all your [ports are open](../nodes/preliminary-steps/vps-setup#install-dependencies--configure-firewall) properly
4. Make sure to run your Gateway with embedded IPR as root. Either in a root shell with your configs in `/root/.nym/` or with a command `sudo -E` which gives root privileges but looks for user config folder
5. If it's all good in the API but you don't see the right tick/badge in the [Performance testing list](https://nym.com/events/fast-and-furious), just wait some time and then try to refresh the page
*/}

---
title: Validators Troubleshooting
url: https://nym.com/docs/operators/troubleshooting/validators
---

# Validators Troubleshooting

### Common reasons for your validator being jailed

The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.

- Running the command `df -H` will return the size of the various partitions of your VPS.

- If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process.

- You can [check out if your `syslog`s](vps-isp.mdx#pruning-logs) aren't eating all your disk space and prune them.

## Where can I get more help?

The fastest way to reach one of us or get a help from the community, visit our [Telegram Node Setup Help Chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://nym.com/go/discord).

For more tech heavy question join our [Matrix core community channel](https://matrix.to/#/#general:nymtech.chat), where you can meet other builders and Nym core team members.

---
title: Nym Tokenomics
url: https://nym.com/docs/operators/tokenomics
---

# Nym Tokenomics

Nym Network is composed of two main elements, the Mixnet represented by [Nym Nodes](nodes/nym-node) routing and mixing the data packets, and Nyx blockchain distributted accros [validator set](tokenomics/validator-rewards.mdx), using smart contracts (based on [cosmwasm](https://cosmwasm.com/)) to monitor and reward Nym Nodes by querying API endpoints and distributing NYM token to operators according to work done by their nodes. All Nym nodes and validators are run by decentralised community of operators.

* Nym tokenomics are based on the research paper [*Reward Sharing for Mixnets*](https://nym.com/nym-cryptoecon-paper.pdf)
* For a more comprehensive overview, token live data and graphs, visit a community managed dashboard [*explorer.nym.spectredao.net/token*](https://explorer.nym.spectredao.net/dashboard)
* To read about rewards calculation, visit [Nym Node rewards page](tokenomics/mixnet-rewards.mdx)
* To understand the implementation and release plan, see [Nym operators roadmap](tokenomics/mixnet-rewards.mdx#roadmap)

{/*
**Formulas and Examples Annotation**

To make it easier for the reader, we use a highlighting line on the left side, with a specific color:

> **Turquoise with red pin for formulas.**

> Purple collapsible for examples.

*/}

## NYM Token: Incentivise Stability & Secure Reputation

Besides the Mixnet itself, Nym Network is secured by its own blockchain Nyx (IBC on Cosmos) with a native token NYM.

**NYM token key features**

* **Incentives:** Distribute rewards to decentralised nodes based on mixing and routing (work). This dynamic ensures that the network is as robust as possible - the nodes are chosen every hour according to their performance.

* **Network take over defense:** Another decisive factor for a node to be chosen to the network active set is reputation. Reputation is a size of stake (self bond + delegation stake) where delegators earn proportional percentage of nodes rewards. Nodes without reputation are not chosen to take part in the network active set.

* **Centralisation defense:** Any node can only have a certain stake called [stake saturation](#stake-saturation) (self bond + delegation stake) to earn maximum rewards, increasing node stake level beyond this point leads to decreasing rewards for the operator and all delegators. This feature makes it more difficult for whales to over-stake their nodes or to attract more delegators (stakers) as they would become dis-advantaged.

To learn more about rewards calculation and distribution, read the next page [*Nym Mixnet Rewards*](tokenomics/mixnet-rewards.mdx).

### Utility

*NYM token is a first and foremost a utility to secure Nym Network.*

![](/images/operators/tokenomics/nym_token_flow.png)

Nyx blockchain's validators run API to monitor the network and node performance. Based on the live input the operators and stakers of the working nodes get rewarded. The network is adjusted and re-randomized in the beginning of each epoch (60 min) composing the best performing nodes with the highest reputation.

This creates an incentive for people to operate Nym nodes as quality and reliable service. The reputation system also works as a network defense against a large adversary take over or sybil attacks.

Node reputation is calculated by delegation. Delegation is a stake done by NYM token holders on top of nodes they want to support to join the network as it compensate the stakers with APR. Therefore there is an incentive for NYM holders to stake their token on top of nodes which they believe will perform well.

To prevent a whale takeover and centralisation, the revenue grows alongside nodes stake size only until a certain point, after which the rewards per staker start to decrease. We call this mark *node stake saturation*.

Thanks to Nyx blockchain API monitoring, the flow is dynamic and constantly optimized based on live metrics. Below is a detailed explanation and reckoning of Nym tokenomics logic.

## Tokenomics

### Summary in Numbers

Below is a table with token supply distribution.

To get live data, visit [SpectreDAO token dashboard](https://explorer.nym.spectredao.net/token) or see how to [query API endpoints](#query-tokenomics-api).

### Calculation & Explanation

To get a full comprehension of [node operators rewards](tokenomics/mixnet-rewards.mdx) calculation and delegators APR height, we need to understand some basic logic behind the numbers presented. This chapter covers some of the most essential variables in Nym tokenomics flow.

```ascii

 ┌───────────┐   staking   ┌───────────┐   sum of      ┌───────────┐
 │           │   supply    │           │   nym nodes   │           │
 │circulating│   scale     │  staking  │   in rewarded │   stake   │
 │  supply   │   factor    │  target   │   set         │saturation │
 │           ├────────────►│           ├──────────────►│   level   │
 └───────────┘             └───────────┘               └───────────┘

```

#### Supply

<b>Circulating supply is <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM.</b>

NYM token is capped at 1b. Visit [SpectreDAO token dashboard](https://explorer.nym.spectredao.net/token) to see live data, graphs and historical data.

#### Staking target

A number of aimed NYM tokens to be staked in the network. The staking target a is multiplier of staking supply scale factor and circulating supply.

> **staking_target = staking_supply_scale_factor \* circulating_supply**

Staking supply scale factor is currently at <span style={{display: 'inline-block'}}><StakingScaleFactor /></span>.

The value of this variable can is changed from time to time to optimize the metrics of the network. With a current circulating supply of <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM and staking supply scale factor <span style={{display: 'inline-block'}}><StakingScaleFactor /></span>, <b>the staking target is <span style={{display: 'inline-block'}}><StakingTarget /></span> NYM.</b>

#### Stake saturation

#### Rewarded Set

> To read more about rewards calculation, please see next page [*Nym Operators Rewards*](tokenomics/mixnet-rewards.mdx) or you can go directly into details about [Rewarded set selection logic](tokenomics/mixnet-rewards#rewarded-set-selection).

Nym Network needs an optimised number of nodes to route and mix the packets. This healthy balance lies in between being too congested - which would detriment speed and user experience - on one side, and having too little traffic per node - which would could weaken anonymity - on the other.

The way how we approach this challenge is different for Mixnet (5-hop) and dVPN (2-hop) mode.

  <Tabs items={[
    <strong>Mixnet mode</strong>,
    <strong>dVPN mode</strong>,
    ]} defaultIndex="0">

Nym Mixnet is using an active set of chosen nodes. Currently <b>the [active set size](https://validator.nymtech.net/api/v1/epoch/reward_params) is 240 nodes</b>, 120 with Gateway functionality: 50 entry (1st layer) and 70 exit (5th layer) and 120 as Mixnode (2nd, 3rd and 4th mixing layer). The active set is chosen in the beginning of each epoch (60min).

The alorithm for selecting the nodes into the Rewarded set is in detail explained in the [Rewarded set selection logic part](tokenomics/mixnet-rewards#rewarded-set-selection).

In dVPN (2-hop) mode every node which meets the [performance criteria](tokenomics/mixnet-rewards#mixnet-node-performance-calculation), including wireguard and IPv6 routing tests, becomes eligible to take part in the network. Whether the node is working or not then depends on the NymVPN end users choise of the location or exact nodes selection.

In both cases, the selection algorithm also looks whether the node runs with [Terms & Conditions](nodes/nym-node/setup.mdx#terms--conditions) accepted **AND** if it's not a legacy binary version. In case either of these criterias are not met, the node will have be excluded from the [rewarded set selection](tokenomics/mixnet-rewards#rewarded-set-selection).

## Query Validator API

We have available API endpoints which can be accessed via [Swagger UI page](https://validator.nymtech.net/api/swagger/index.html). Or by querying the endpoints directly:

```sh
curl -X 'GET' \
  'https://validator.nymtech.net/api/v1/circulating-supply' \
  -H 'accept: application/json'

curl -X 'GET' \
  'https://validator.nymtech.net/api/v1/circulating-supply/total-supply-value' \
-H 'accept: application/json'

curl -X 'GET' \
  'https://validator.nymtech.net/api/v1/circulating-supply-value' \
-H 'accept: application/json'

curl -X 'GET' \
  'https://validator.nymtech.net/api/v1/epoch/reward_params' \
-H 'accept: application/json'
```

> The unit of value is measured in `uNYM`.

> **1 NYM = 1_000_000 uNYM**

---
title: Nym Operators Rewards
url: https://nym.com/docs/operators/tokenomics/mixnet-rewards
---

# Nym Operators Rewards

**Nym Network Rewarded set selection had been upgraded recently. Make sure to read the chapter *[Rewarded Set Selection](#rewarded-set-selection)* below carefully to fully understand all requirements to be rewarded!**

* Nym tokenomics are based on the research paper [*Reward Sharing for Mixnets*](https://nym.com/nym-cryptoecon-paper.pdf)
* For a more comprehensive overview, live data and supply graphs, visit [*explorer.nym.spectredao.net/token*](https://explorer.nym.spectredao.net/token)

We are working on the final architecture of [*Fair Mixnet*](#fair-mixnet) tokenomics implementation and its detailed documentation. **The current design is called [*Naive rewarding*](#naive-rewarding).** It is an intermediate step, allowing operators to migrate to `nym-node` in Mixnet smart contract and for the first time receive delegations and earn rewards for any `nym-node` [functionality](../nodes/nym-node/setup#functionality-mode), in opposite to the past system, where only Mixnodes were able to receive delegations and rewards.

**Please read the [roadmap section below](#roadmap) to see the planned development.**

{/*

**Formulas and Examples Annotation**

To make it easier for the reader, we use a highlighting line on the left side, with a specific color:

> **Turquoise with red pin for formulas.**

> Purple collapsible for examples.

*/}

Nodes bonded with vesting tokens are [not allowed to join rewarded set](https://github.com/nymtech/nym/pull/5129) - read more on [Nym operators forum](https://forum.nymtech.net/t/vesting-accounts-are-no-longer-supported/827).

## Rewards Logic & Overview

This is a quick summary, to understand the logic behind fundamentals like [rewarded set selection](#rewarded-set-selection), [node performance](#mixnet-node-performance-calculation), [stake saturation](#stake-saturation), or [rewards calculation](#rewards-calculation), please read the chapters below.

* **The current reward system is called [*Naive rewarding*](#naive-rewarding) - an intermediate step - where the operators of `nym-node` get rewarded from [Mixmining pool](https://validator.nymtech.net/api/v1/epoch/reward_params), which emits <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> NYM per hour**
* **Only nodes selected to [rewarded set](../tokenomics#rewarded-set) of Mixnet receive rewards**
* The [rewarded set](../tokenomics#rewarded-set) of the Mixnet is currently **240 nodes in total and it's selected for each new epoch (60 min)**, from all the nodes registered (bonded) in the network
* Each node gets the same proportion of work factor because of the *naive* distribution of work
* In the [final model](#roadmap), nodes will get rewarded based on their layer position and the work they do (collected user tickets), where the work factor distribution per layer will be according to a [decision made by the operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407) as [listed below](#nym-network-rewarded-set-distribution)
* If a node is selected to the rewarded set, it will be rewarded in the end of the epoch, based on this reward calculation formula:

> **node_epoch_rewards = [total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) \* <abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> \* [node_stake_saturation](#stake-saturation) \* [node_performance](#mixnet-node-performance-calculation)**
>
> We know that: <br/>
> **[total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span>** <br/>
> **<abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> = 1 / active_set_size** <br/>
> **[active_set_size](https://validator.nymtech.net/api/v1/epoch/reward_params) = 240**
>
> Therefore: <br/>
> **node_epoch_rewards = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> \* 1 / 240 \* [node_stake_saturation](#stake-saturation) \* [node_performance](#mixnet-node-performance-calculation)**

In reality there is a an additional value called **&alpha;**, giving a premium to nodes with a higher self bond. And additionally an operator gets more rewards based on [*Operators cost*](#rewards-distribution) and [*Profit margin*](#rewards-distribution) size. **Read chapter [Rewards calculation](#rewards-calculation) to be able to navigate in all the details relevant for operators and delegators.**

**In the current intermediate model we use one active set to reward all nodes and they are assigned same work factor of 1 / 240**, whether they work as Mixnode or Gateway of any kind, in both 2-hop and 5-hop mode (hence *naive rewarding*).

**In reality it means that all nodes are rewarded within the [Mixnet (5-hop) reward set](#rewarded-set-selection) only.**

**However NymVPN client can choose any `nym-node` with `--wireguard-enabled true` flag (which passed [wireguard probing test](https://harbourmaster.nymtech.net)) to route as dVPN Gateway, both entry and exit.**

{/*

### Nym Network rewarded set distribution

  <Tabs items={[
    <strong>Mixnet mode (5-hop)</strong>,
    <strong>dVPN mode (2-hop)</strong>,
    ]} defaultIndex="0">

```ascii

 Network
 layer:           1.           2.           3.           4.           5.

 --------
                            ┌► mixnode ─┐   mixnode      mixnode
                            │           │
 Node             entry     │           │                             exit
 type:            gateway ──┘  mixnode  │   mixnode  ┌─► mixnode ───► gateway
                                        │            │
                                        │            │
                               mixnode  └─► mixnode ─┘   mixnode

```

| **Network layer** | **1** | **2** | **3** | **4** | **5** |
| :-- | :---: | :---: | :---: | :---: | :---: |
| Node functionality in layer | Entry Gateway | Mixnode | Mixnode | Mixnode | Exit Gateway |
| Nodes in [active set](#rewarded-set-selection) |  50  | 40 | 40 | 40 | 70 |
| Naive rewarding \*: Maximum work fraction per node | 1 / 240 | 1 / 240 | 1 / 240 | 1 / 240 | 1 / 240 |
| Final model \*\*: Layer multiplier | 0.16 | 0.16 | 0.16 | 0.16 | 0.36 |

> \* Only nodes chosen to the [rewarded set](#rewarded-set-selection) will be rewarded in Mixnet mode (5-hop).<br/>
> \*\* In the final model the nodes routing as Exit Gateway get premium rewards due to the complexity and legal challenges coming along operating this type of node. Read [roadmap section](#roadmap) in the bottom of the page to get a detailed breakdown of the final implementation.

```ascii

 Network
 layer:           1.                                                  2.

 --------

 Node             entry                                               exit
 type:            gateway ──────────────────────────────────────────► gateway

```

| **Network layer** | **1** | **2** |
| :-- | :---: | :---: |
| Node functionality in layer | Entry Gateway  | Exit Gateway |
| Naive rewarding: Nodes in [active set](../tokenomics#rewarded-set) |  only Mixnet mode  | only Mixnet mode |
| Naive rewarding\*: Maximum work fraction per node | only Mixnet mode | only Mixnet mode |
| Final model\*\*: Layer multiplier | 0.33 | 0.67 |

> \* In the current state called [*Naive rewarding*](#naive-rewarding) only nodes in the Mixnet [rewarded set](#rewarded-set-selection) get rewarded.<br/>
> \*\* In the final model the nodes routing as Exit Gateway get premium rewards due to the complexity and legal challenges coming along operating this type of node. Read [roadmap section](#roadmap) in the bottom of the page to get a detailed breakdown of the final implementation.

*/}

## Rewarded Set Selection

For a node to be rewarded, the node must be part of a [Rewarded set](https://validator.nymtech.net/api/v1/epoch/reward_params) (which currently = active set) in the first place. The Rewarded set is freshly selected at the start of each epoch (every 60 min), and it consists of 240 Nym nodes that are probabilistically chosen from all the available nodes. These 240 nodes are composed of 120 gateways (50 entry and 70 exit) and 120 mixnodes (40 for each of 3 mixnet layers).

Nodes selected into the rewarded set are chosen probabilisticaly, and their selection chances increase the larger nodes weight is. Weight value is always between `0` and `1` and it's calculated by multiplying these parameters, each of them also having a value between `0` and `1` (some are floats, some are binary):

**1. [Performance](#mixnet-node-performance-calculation):** This value consists of:
- [Config score](#config-score-calculation): highest (`1`) when the node is running the latest version of the software, has [T&C's accepted](../nodes/nym-node/setup.mdx#terms--conditions) and self described API endpoint available
- [Routing ](#routing-score-calculation): highest (`1`) when the node is consistently online and correctly processes all the received traffic (100% of time)

**2. [Stake saturation](#stake-saturation):** combining bond and delegated stake (a float number between `0` and `1` representing percentage)

**Node weight is calculated with this formula:**

> **active_set_selection_weight = stake_saturation \* ( node_performance ^ 20 )**

For the rewarded set selection weight, good [performance](#mixnet-node-performance-calculation) is much more essential than [stake saturation](#stake-saturation), because it's lifted to 20th power in the selection algorhitm.

For a comparison we made an example with 5 nodes, where first number is node performance and second stake saturation (assuming all of them [`config_score`](#config-score-calculation) = `1` for simplification):

> node_1 = 1.00 ^ 20 \* 1.0 = **1** <br />
> node_2 = 1.00 ^ 20 \* 0.5 = **0.5** <br />
> node_3 = 0.99 ^ 20 \* 1.0 = **0.818** <br />
> node_4 = 0.95 ^ 20 \* 1.0 = **0.358** <br />
> node_5 = 0.90 ^ 20 \* 1.0 = **0.122** <br />

As you can see the performance is much more important during the Rewarded set selection. A node with 100% performance but only 50% stake saturation has much bigger chance to be chosen than a node with 95% performance and 100% stake saturation and incomparably bigger chance than 90% performing node with 100% stake saturation.

The nodes are chosen probababilistically in each epoch (60 min), so even nodes with lower performance will eventually be chosen, just much less often, as their chances decrease.
Note that the score helps prioritize some nodes over others. If all available nodes have the same score, then the selection is done uniformly at random. By raising the node performance to 20, values of these parameters that are below one incur a heavy penalization for the node’s selection chances.

**Explanation**

The nodes are selected probabilistically, that means that even nodes with lower weight have a small chace to get slected. The probabilistic alorithm follows this logic:

1. Summarize all nodes weight together
2. Make a random selection roll for the first slot in the active set
3. If a node is selected, take all its weight away from the draft queue
4. Repeat points 1. - 3. for each slot in the active set

**Example**

We know that nodes weight is a float between 0 and 1. For simplification we will use integers in this example and much smaller set.

- Total nodes:  8
- Rewarded set: 4
- Nodes weight:
    - node1 =  5
    - node2 =  5
    - node3 = 10
    - node4 = 10
    - node5 = 20
    - node6 = 40
    - node7 = 50
    - node8 = 60

1. Summarize all nodes weight together:
```
weight_total = 5 + 5 + 10 + 10 + 20 + 40 + 50 + 60
weight_total = 200
```
2. Roll a dice from 1 to 200:
- Imagine the nodes are in line each representing the weight like index:
    - node1 =   1-5
    - node2 =   6-10
    - node3 =  11-20
    - node4 =  21-30
    - node5 =  31-50
    - node6 =  51-90
    - node7 =  91-150
    - node8 = 151-200
- Say the function resulted in number 170
3. Add node8 to the rewarded set and take it out of the lottery, summarize all the weights again:
```
weight_total = 5 + 5 + 10 + 10 + 20 + 40 + 50
weight_total = 140
```
4. Roll a dice from 1 to 140:
- Say the function resulted in number 4
5. Add node1 to the rewarded set and take it out of the lottery, summarize all the weights again:
```
weight_total = 5 + 10 + 10 + 20 + 40 + 50
weight_total = 135
```
6. Roll a dice from 1 to 135:
- Say the function resulted in number 72
7. Add node6 to the rewarded set and take it out of the lottery, summarize all the weights again:
```
weight_total = 5 + 10 + 10 + 20 + 50
weight_total = 95
```
8. Roll a dice from 1 to 95:
- Say the function resulted in number 21
9. Add node4 to the rewarded set
10. Rewarded set of 4 nodes is selected with these nodes to be chosen:
    1. node8
    2. node1
    3. node6
    4. node4
11. After an epoch - 60 minutes - pull all bonded nodes and repeat the exact same process with their current weights

In reality we have mixing nodes selected into 3 layers. To increase security, there is an additional function in place where a node cannot be assigned to the same layer in two following epochs.

Below we break down [performance calculation](#mixnet-node-performance-calculation) and show examples.

## Stake Saturation

> If you want to understand more about NYM supply, read [tokenomics page](../tokenomics#tokenomics) first.

## Rewards Calculation

Once the [rewarded set](https://validator.nymtech.net/api/v1/epoch/reward_params) (currently 120 Mixnodes and 120 Gateways) is selected, the nodes can start to route and mix packets in the Nym Network. Each hour a total of <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> NYM is distributed between the layers from Mixmining pool. Currently in our *Naive rewarding* intermediate design, all layers get a same portion, therefore each node is *naively* assigned same working factor and therefore earns 1/240 of the rewards per epoch.

If a node is active in the rewarded set, it will receive rewards in the end of the epoch, the size is dependant on [stake saturation](../tokenomics.mdx#stake-saturation) and [performance](#performance-calculation). This is how rewards get distributed between nodes in the rewarded set.

**Node rewards calculation formula:**

> **node_epoch_rewards = [total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) \* [node_performance](#mixnet-node-performance-calculation) \* [node_stake_saturation](#stake-saturation) \* ( <abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> + <abbr title="&alpha; is a constant (0.3) working as a premium for nodes with higher self bond">&alpha;</abbr> \* ( ( <abbr title="The actual number of tokens in the bond. Node bond size is capped at stake saturation level.">node_bond_size</abbr> / [stake_saturation_level](https://validator.nymtech.net/api/v1/epoch/reward_params) ) / rewarded_set_size ) ) \* 1 / ( 1 + <abbr title="&alpha; is a constant (0.3) working as a premium for nodes with higher self bond">&alpha;</abbr> )**
>
> Where: <br/>
> **[total_epoch_reward_budget](https://validator.nymtech.net/api/v1/epoch/reward_params) = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span>** <br/>
> **<abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">node_work_fraction</abbr> = 1 / rewarded_set_size** <br/>
> **[rewarded_set_size](https://validator.nymtech.net/api/v1/epoch/reward_params) = 240** <br/>
> **[stake_saturation_level](https://validator.nymtech.net/api/v1/epoch/reward_params) = <span style={{display: 'inline-block'}}><StakeSaturation /></span>** <br/>
> **&alpha; = <abbr title="&alpha; is a constant (0.3) working as a premium for nodes with higher self bond">0.3</abbr>**
>
> Therefore: <br/>
> **node_epoch_rewards = <span style={{display: 'inline-block'}}><EpochRewardBudget /></span> \* [node_performance](#mixnet-node-performance-calculation) \* [node_stake_saturation](#stake-saturation) \* ( <abbr title="In Naive rewarding the node work fraction is same for all nodes in the active set">( 1 / 240 )</abbr> + <abbr title="&alpha; is a constant (0.3) working as a premium for nodes with higher self bond">0.3</abbr> \* ( (  <abbr title="The actual number of tokens in the bond. Node bond size is capped at stake saturation level.">node_bond_size</abbr> / <span style={{display: 'inline-block'}}><StakeSaturation /></span> ) / 240 ) ) \* 1 / ( 1 + <abbr title="&alpha; is a constant (0.3) working as a premium for nodes with higher self bond">0.3</abbr> )**

Performance and stake saturation (both are a float between `0` and `1` representing percentage) play an equally decisive role in the size of rewards earned after the epoch. The closer a node is to maximum value (`1`) of each of these parameters, the more rewards it will get.

Operators aim to get [stake saturation](#stake-saturation) on their nodes as close to maximum value `1` as possible. The value of node stake is composed of **delegations** (stake from others or self) and **bond** (tokens locked by the operator on top of the node when registering it to the network).

Constant **&alpha;** is a in place to increase rewards for nodes with higher bond. Minimum value of bond is 100 NYM. The higher bond an operator locks, the more skin in the game they have and therefore they receive a small premium.

Let's compare 3 nodes to see their rewards, for simplicity all of them having maximum performance and stake saturation, being active in the same epoch with reward budget of 5_000 NYM, stake saturation level is 1_000_000_000 NYM and node work fraction 1 / 240. The only variable is then the size of their bond. The formula will look like this:

```
node_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( node_bond_size / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
```

Bond size of our 3 example nodes:

```
node1_bond_size = 100 NYM
node2_bond_size = 250_000 NYM
node3_bond_size = 1_000_000 NYM
```
Rewards calculation:

```
node1_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( 100 / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
node2_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( 250_000 / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
node3_epoch_rewards = 5_000 * 1 * 1 * ( ( 1 / 240 ) + 0.3 * ( ( 1_000_000 / 1_000_000 ) / 240 ) ) * 1 / ( 1 + 0.3 )
```

The result:
```
node1_epoch_rewards = 16.0261 NYM
node2_epoch_rewards = 17.2275 NYM
node3_epoch_rewards = 20.8333 NYM
```

Difference between the smallest possible bond 100 NYM and a maximum bond 1mm NYM (equal full stake saturation point) is about 23% of increase in epoch rewards.
</ AccordionTemplate>

**Try to calculate rewards yourself**

> Nym documentation pages are rendered statically (like in Nextra or Next.js static export mode), that's why we don't fetch from APIs at runtime, therefore on chain data must be filled by the user at the moment to ensure they are up to date.

**Rewards are sent to the Nyx account used for bonding the node and each delegator automatically by the end of an epoch in which the node was part of the rewarded set,** following the logic [described below](#rewards-distribution).

Given that there is a highly unlikely chance of all nodes having maximum stake saturation and performance, in majority of cases there will be some part of the reward budget left undistributed. This "change" is then kept in the [Mixmining reserve](../tokenomics#tokenomics).

All parameters regarding node performance score can be browsed or pull live from:

`https://validator.nymtech.net/api/v1/nym-nodes/annotation/<NODE_ID>`

In case you don't know your nodes `NODE_ID`, it's easy to find as long as your node is bonded. Visit [validator.nymtech.net/api/v1/nym-nodes/bonded](https://validator.nymtech.net/api/v1/nym-nodes/bonded) and search your node using `identity_key` or bonding Nyx account address (denoted as `owner`).

### Rewards Distribution

Once the [rewards are assigned per each node](#rewards-calculation) they need to be distributed between the operator of the node and delegators (people who staked their NYM on that node). The distribution is pretty straightforward and it happens in the following order:

1. **Operators Cost (O.C.)**: How many NYM the operator requests to cover their costs per month, [divided by `720`](#nyx-epoch-vs-interval) (this value is set by the operator in the bonding wallet node settings)
2. **Profit Margin (P.M.)**: The extra % cut that the operator requests (this value is set by the operator in the bonding wallet node settings, smallest value is 20% to prevent race to bottom)
3. **Bond & Stake proportionally**: The remaining rewards are distributed proportionally to the weight of every stake (including self bond, self delegation and each delegation).

#### Nyx Epoch vs Interval

> **1 epoch = 60 min** <br />
> **1 interval = 720 epochs**
>
> The logic is that interval is 30 days: <br />
> 24 epochs * 30 days = 720
</ Callout>

The Operators Cost (O.C). is a value denominated in NYM, that a node operator requires to get paid before the rewards get distributed. The cost is estimated per one month. However, it's paid only in epochs when the node is active. To calculate how O.C. works, we use a value called `interval` which represents 30 days (approximate month), or more precisely 720 epochs. To get covered a full O.C, the node would have to be active for the entire month.

**O.C. real revenue formula**

Therefore every epoch a node is active, the operator gets:

> **epoch_operator_cost_revenue = operators_cost / epochs_per_interval**
>
> that is:
>
> **epoch_operator_cost_revenue = operators_cost / 720**
</ Callout>

To calculate O.C. per month, multiply it by number of active epochs:

> **monthly_operator_cost_revenue = ( operator_cost / 720 ) * active_epochs**

{/*
#### Final Layer Distribution (under development)

We are working on the final design with the ratio implementing a [decision made by the operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407) as follows:

>5-hop mixnet mode: <br />
> 16%; 16%; 16%; 16%; 36% <br/>
> <br/>
> 2-hop dVPN mode: <br />
> 33%; 67%

In real numbers: If hourly revenue to all 240 nodes is 6000 NYM, the layer compartmentalisation is 960 NYM for Entry Gateway layer and each Mixnode layer and 2160 NYM for Exit Gateway layer. The calculation is in the example below:

> Purple collapsible for examples.
5-hop mixnet mode:
$0.16 * 6000 = 960; 0.16 * 6000 = 960; 0.16 * 6000 = 960; 0.16 * 6000 = 960; 0.36 * 6000 2160$
2-hop wireguard mode:
$33\% - 67\%$

### Node Rewards within Same Layer

### Operation Cost, Profit Margin & Delegation

### APR Calculation
*/}

## Roadmap

We are working on the final architecture of [*Fair Mixnet*](#fair-mixnet) tokenomics implementation, following the [decision made by the node operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407). The current design is called [*Naive rewarding*](#naive-rewarding). This is an intermediate step, expecting operators to migrate to `nym-node` in Mixnet smart contract and be able to recieve delegations and earn rewards for any `nym-node` functionality, in opposite to the past system, where only Mixnodes were able to recieve delegations and rewards.

On November 5th 2024, we presented a release roadmap in live [Operators Townhall](https://www.youtube.com/watch?v=3G1pJqvO2VM) where we explained in detail the steps of Nym node and tokenomics development and the effect it will have on node operators and put it into a rough timeline.

### Naive Rewarding

***Naive rewarding* is the current tokenomics design.** The table below lists features and logic of this design.

![](/images/operators/tokenomics/roadmap_naive.png)

### Fair Mixnet

***Fair Mixnet* is the final architecture model that we work towards.** The table below lists features and logic of the design once implemented.

![](/images/operators/tokenomics/roadmap_fair.png)

{/*
## Stats

NYM token is capped at 1b. Below is a table with actual\* token supply distribution.

mdrun cd ../../../scripts/cdmrun && ./api_targets.py s --api mainnet --endpoint circulating-supply --format

ADD MIXNET STATS GRAPHS

DROPPING THIS FROM THE MAINTENANCE PAGE - NEEDS REWORK

## Mix Node Reward Estimation API endpoint

THIS NEEDS REDO

The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`.

> The `<MIX_ID>` can be found in the "Mix ID" column of the [Harbourmaster](https://harbourmaster/nymtech.net).

The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability.

We have available API endpoints which can be accessed via [Swagger UI page](https://validator.nymtech.net/api/swagger/index.html). Or by querying the endpoints directly:

```sh
curl -X 'GET' \
  'https://validator.nymtech.net/api/v1/status/mixnode/<MIX_ID>/reward-estimation' \
  -H 'accept: application/json'sh
```

Query response will look like this:

```sh
    "estimation": {
        "total_node_reward": "942035.916721770541325331",
        "operator": "161666.263307386408152071",
        "delegates": "780369.65341438413317326",
        "operating_cost": "54444.444444444444444443"
    },
```

> The unit of value is measured in `uNYM`.

$1 \ NYM = 1 \_ 000 \_ 000 \ uNYM$

- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix Node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix Nodes currently active in the network, and the amount of network traffic being processed by the Mix Node.

- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix Node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the operator's stake in the network.

- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix Node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the delegator's stake in the network.

- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix Node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch.

- `estimated_operator_cost` - An estimate of the total cost that a particular Mix Node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix Node, such as server hosting fees, and other expenses associated with operating the Mix Node.
*/}

{/*
?DROPPING THIS FROM THE OLD MAINTENANCE PAGE

### Mix Node Reward Estimation API endpoint

The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`.

> The `<MIX_ID>` can be found in the "Mix ID" column of the [Network Explorer](https://nym.com/explorer).

The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability.

Using this API endpoint returns information about the Reward Estimation:

```sh
/status/mixnode/<MIX_ID>/reward-estimation
```

Query Response:

```sh
    "estimation": {
        "total_node_reward": "942035.916721770541325331",
        "operator": "161666.263307386408152071",
        "delegates": "780369.65341438413317326",
        "operating_cost": "54444.444444444444444443"
    },
```

> The unit of value is measured in `uNYM`.

- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix Node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix Nodes currently active in the network, and the amount of network traffic being processed by the Mix Node.

- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix Node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the operator's stake in the network.

- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix Node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the delegator's stake in the network.

- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix Node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch.

- `estimated_operator_cost` - An estimate of the total cost that a particular Mix Node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix Node, such as server hosting fees, and other expenses associated with operating the Mix Node.

### Validator: Installing and configuring nginx for HTTPS
#### Setup
[Nginx](https://www.nginx.com/resources/glossary/nginx) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security.

Install `nginx` and allow the 'Nginx Full' rule in your firewall:

*/}

---
title: Nyx Validator Rewards
url: https://nym.com/docs/operators/tokenomics/validator-rewards
---

# Nyx Validator Rewards

## Summary

* Nyx Validators are rewarded in NYM tokens from the Nym mixmining pool and increasingly from apps that run on the Nym mixnet, the first of which is the NymVPN.
* Validators are rewarded for two different types of work: signing blocks in the Nyx chain and running the NymAPI to monitor mixnet routing and sign zk-nym credentials.
* New validators can join via a NYM-to-NYX swap contract after contacting us and getting whitelisted. The contract will not allow more than 1% of total stake increase per month to prevent sudden hostile takeovers. Current stake is <span style={{display: 'inline-block'}}><NyxTotalStake /></span> million Nyx. Rate: 1:4.8 ~ 288k NYX for 60k NYM \=\> <span style={{display: 'inline-block'}}><NyxPercentStake /></span> voting power
* NYX tokens serve no other purpose than self-delegation for voting power and governance. All rewards are in NYM and distributed directly to the validators self-delegation address and are not distributed to stakers.
* The contract will only allow swapping NYM to NYX and will **not** allow exchanging NYX back to NYM. A NYX holder who wishes to sell their NYX stake will have to do so via OTC trades.

## Validator Rewards

Nyx Validators perform two types of work for which they will be rewarded:

### 1. Signing blocks in the Nyx chain

A “block signing monitor" monitors blocks being produced on the Nyx chain and gathers the signatures present on every block. After an epoch ends, the monitor will assess performance of a validator and distribute tokens (to the self-delegation wallet) proportional to the voting period and uptime of the validator.

### 2. Running the NymAPI to monitor Mixnet routing and sign zk-nyms (Nym’s anonymous credentials)

Validator rewards initially come from the Nym mixmining pool with additional rewards increasingly coming from paid applications running on the Nym mixnet. The first paid application is the NymVPN. Nyx validators will be rewarded for their work directly in NYM tokens to their validator self-delegation address.

1. **From mixmining pool** - at a rate of 1000 NYM per hour, of which 2/3 are distributed for signing blocks and 1/3 for zk-nyms. These are stable in NYM, and therefore will fluctuate in their fiat value depending on exchange rate.

2. **From vpn user subscriptions** - the rate is tied to the growth of NymVPN subscriptions and will be stable in fiat, fluctuating in NYM depending on exchange rate. 1/3 will be distributed for signing blocks and 2/3 for zk-nyms.

| Source         | Signing blocks | Running NymAPI | Currency |
| :--            | --:           | --:    | :---:    |
| Mixmining pool | 2/3           | 1/3    | NYM      |
| NymVPN         | 1/3           | 2/3    | fiat     |

#### zk-nyms

The zk-nyms enable people to anonymously prove access rights to the upcoming NymVPN client without having to reveal payment details that might compromise their privacy. This is the first of what we imagine to be many possible use-cases for the zk-nym scheme.

### Allocation of Rewards from Nym mixmining pool

Rewards for validators will be distributed at an hourly rate from the mixmining pool. The amount is 1000 NYM per hour to be distributed among all validators. The fraction of mixmining rewards received by each individual validator is proportional to its contributions to the network.

Two thirds of the available rewards (670 NYM per hour) are distributed proportionally to each validator’s share when signing blocks in the chain, for which tx fees are also received in the same proportion; while the last third (330 NYM per hour) is allocated to validators running the NymAPI, proportionally to their contribution to signing zk-nym credentials.

The rewards are stable in NYM and fluctuate in their fiat value depending on the exchange rate of NYM tokens.

## Permissionless Nyx Chain

To allow new validators to join Nyx chain a new smart contract will be set up to release NYX in exchange for NYM. This contract allows a limited amount of NYM tokens to be deposited per month. The deposited NYM tokens are added to the mixmining pool and thus contribute to future rewards of all nodes and validators.

The smart contract will have two parameters:

1. the maximum amount of NYX available for purchase per month
2. the NYM-to-NYX exchange rate offered by the contract

### Maximum Amount of NYX Available for Purchase per Month

The contract will not allow more than 1% of total stake increase per month to prevent sudden hostile takeovers. Current stake level is <span style={{display: 'inline-block'}}><NyxTotalStake /></span> million Nyx.

---
title: Nym Node Operator FAQ: Questions Answered
description: Frequently asked questions about running Nym nodes. Covers VPS selection, staking requirements, node configuration, rewards, and community resources.
url: https://nym.com/docs/operators/faq/general-faq
---

# General Operators FAQ

## Nym Network

To see different stats about Nym Network live, we recommend you to visit [Nym Harbourmaster](https://harbourmaster.nymtech.net) and dynamic [Nym token page](https://nym.com/token).

### Is there an explorer for Nym Mixnet?

Yes, there are..

**Built by Nym**

* [Nym Explorer](https://nym.com/explorer)
* [Sandbox testnet](https://sandbox-explorer.nymtech.net/)
* [Nym Harbourmaster](https://harbourmaster.nymtech.net)

**Built by community**

* [SpectreDAO Explorer](https://explorer.nym.spectredao.net/dashboard)
* [Nymesis](https://nymesis.vercel.app)

### Which VPS providers would you recommend?

Consider in which jurisdiction you reside and where do you want to run a node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to choose smaller and decentralised VPS providers over the most known ones controlling a majority of the internet. Nym operators community started an ISP table called [*Where to host your nym node?*](../community-counsel/isp-list.mdx), check it out and add your findings!

### Why is a node setup on a self-hosted machine so tricky?

We don't recommend this setup because it's really difficult to get a static IP and route IPv6 traffic.

### What's the Sphinx packet size?

The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/develop/common/nymsphinx/params/src/packet_sizes.rs#L32) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/develop/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80).

### Why a Mix Node and a Gateway cannot be bonded with the same wallet?

Because of the way the smart contract works we keep it one-node one-address at the moment. This will change very soon as a `nym-node` will be run with multiple modes.

### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards?

At this point the most crucial component needed are [Exit Gateways](../nodes/nym-node/setup.mdx#initialise--run) routing wireguard.

### Are Nym Nodes whitelisted?

Nope, anyone can run a Nym Node. whether your node is chosen to mix is purely reliant on the node's performance and reputation (self stake + delegations).

---
title: Nym Nodes related Frequently Asked Questions
url: https://nym.com/docs/operators/faq/nym-nodes-faq
---

# Nym Nodes related Frequently Asked Questions

### What determines the rewards when running a `nym-node --mode mixnode`?

The stake required for a node (currently only mode `--mixnode`) to achieve maximum rewards is called Node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 40% of the staking supply locked in Mix Nodes.

The node stake saturation point, is given by the stake supply, target level of staking divided between all bonded nodes.

This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it secures a whale prevention and decentralization of staking, as any higher level of delegated NYM than Nsat per node results in worsening reward ratio. On the contrary, the more nodes are bonded in the mixnet, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the registered nodes and that's our basis for this incentive system.

- Nym mixnet active set - the mixing nodes rewarded - is currently 240 nodes. The selection and reward distribution happens every epoch (60 min) and the criteria for node to be chosen into the active set is:

> ACTIVE_SET_PROBABILITY = NODE_PERFORMANCE ^ 20 * STAKE_SATURATION

We are working on a new tokenomics and reward pages. Coming out soon.

---
title: nyx faq
url: https://nym.com/docs/operators/faq/nyx-faq
---

## Validators and Tokens

### What's the difference between NYM and uNYM?

> 1 NYM = 1 000 000 uNYM

### Why some Nyx blockchain operations take one hour and others are instant?

This is based on the definition in [Nym's CosmWasm](https://github.com/nymtech/nym/tree/develop/common/cosmwasm-smart-contracts) smart contracts code.

Whatever is defined as [a pending epoch event](https://github.com/nymtech/nym/blob/b07627d57e075b6de35b4b1a84927578c3172811/common/cosmwasm-smart-contracts/mixnet-contract/src/pending_events.rs#L35-L103) will get resolved at the end of the current epoch.

And whatever is defined as [a pending interval event](https://github.com/nymtech/nym/blob/b07627d57e075b6de35b4b1a84927578c3172811/common/cosmwasm-smart-contracts/mixnet-contract/src/pending_events.rs#L145-L172) will get resolved at the end of the current interval.

### Why is validator set entry whitelisted?

We understand that the early days of the Nyx blockchain will face possible vulnerabilities in terms of size - easy to disrupt or halt the chain if a malicious party entered with a large portion of stake. Besides that, there are some legal issues we need to address before we can distribute the validator set in a fully permissionless fashion.

---
title: Community Counsel
url: https://nym.com/docs/operators/community-counsel
---

# Community Counsel

**The entire content of this section is under [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/).**

Running an Exit Gateway is a commitment and as such is exposed to various challenges. Besides different legal regulations typical difficulties may be dealing with VPS or ISP providers. Our strength lies in decentralised community of squads and individuals supporting each other. Sharing examples of [landing pages](community-counsel/landing-pages), templates for communication and FAQs is a great way to empower other operators sharing the mission of liberating internet. Below is a simple way how to create a pull request directly to Nym Operator Guide docs.

## How to add content

Our aim is to establish a strong community network, sharing legal findings and other suggestions with each other. We would like to encourage all of the current and future operators to do research about the situation in the jurisdiction they operate in as well as solutions to any challenges when running an Exit Gateway and add those through a pull request (PR). Please check out the [steps to make a pull request](community-counsel/add-content).

---
title: Community Counsel: Running Exit Gateway
url: https://nym.com/docs/operators/community-counsel/exit-gateway
---

# Community Counsel: Running Exit Gateway

This page is a part of Nym Community Counsel (before Legal Forum) and its content is composed by shared advices in [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat) as well as though pull requests done by the node operators directly to our [repository](https://github.com/nymtech/nym/tree/develop/documentation/docs/pages/operators), reviewed by Nym DevRels.

This document presents an initiative to further support Nym’s mission of allowing privacy for everyone everywhere. This would be achieved with the support of Nym node operators operating Gateways and opening these to any online service. Such setup needs a **clear policy**, one which will remain the **same for all operators** running Nym nodes. [**Nym exit policy**](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) was inspired by (nowadays deprecated) Tor Null deny list and Tor reduced policy and created to meet the changes decided by Nym operators community through the governance (like in this [vote](https://forum.nym.com/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464)). This policy aims to find a healthy compromise between protecting the operators and NymVPN users against attacks while allowing for as wide experience when accessing the internet through Nym Network.

The following part is for informational purposes only. Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the [Node Operator](https://matrix.to/#/#operators:nymtech.chat) and [Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) channels on Element to share best practices and experiences.

## Summary

**Nym supports privacy for everyone, everywhere.**

To offer a better and more private everyday experience for its users, Nym would like them to use any online services they please, without limiting its access to a few messaging apps or crypto wallets.

To achieve this, operators running Exit Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt).

* Nym is committed to ensuring privacy for all users, regardless of their location and for the broadest possible range of online services. In order to achieve this aim, the Nym Mixnet needs to increase its usability across a broad range of apps and services.

* To decentralise and enable privacy for a broader range of services, Nym transitioned from allow list to a deny list - creating a new [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt).

* Future changes of the exit policy is done via an off-chain governance, like in this [vote](https://forum.nym.com/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464).

* This will enhance the usage and appeal of Nym products for end users. As a result, increased usage will ultimately lead to higher revenues for Nym operators.

* Nym core team cannot provide operators with definitive answers regarding the potential risks of operating open Gateways. However, there is online evidence of operating Tor exit relays:
	* From a technical perspective, Nym node operators may need to implement additional controls, such as dedicated hardware and IP usage, or setting up an HTML exit notice on port 80.
	* From an operational standpoint, node operators may be expected to actively manage their relationship with their ISP or VPS provider and respond to abuse requests using the proposed templates.
	* Legally, exit relays are typically considered "telecommunication networks" and are subject to intermediary liability protection. However, there may be exceptions, particularly in cases involving criminal law and copyright claims. Operators could seek advice from local privacy associations and may consider running nodes under an entity rather than as individuals.

* This document serves as the basis for a consultation with Nym node operators on any concerns or additional support and information you need for this change to be successful and ensure maximum availability, usability and adoption.

## Exit Gateways: New setup

In our previous technical setup, Network Requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network Requester operator.

This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of Network Requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts.

The principal change in the new configuration is to make this short allow list more permissive. Nym's [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app).

As of now the Gateways will be defaulted to a policy decided by Nym operators community through the governance (like in this [vote](https://forum.nymtech.net/t/poll-a-new-nym-exit-policy-for-exit-gateways-and-the-nym-mixnet-is-inbound/464)). This policy will remain the same for all the nodes, without any option to modify it by Nym node operators individually, to secure stable and reliable service for the end users.

The Exit Gateways will exhibit an HTML page (on port `80` and `443`) resembling the one proposed documented [here](landing-pages.mdx
). By doing so, the operator will be able to disclose details regarding their Gateway, including the currently configured exit policy, all without the need for direct correspondence with regulatory or law enforcement agencies. It also makes the behavior of Exit Gateways transparent and even computable (a possible feature would be to offer a machine readable form of the notice in JSON or YAML).

We also recommend operators to check the technical advice from [Tor](https://community.torproject.org/relay/setup/exit/).

## Community Counsel & Legal environment of Nym Exit Gateway

The Node Operators Community Counsel pages are divided according [jurisdictions](jurisdictions.mdx). Nym Node operators are invited to add their legal findings or helpful suggestions directly through [pull requests](add-content.mdx). This can be done as a new legal information (or entire new country) to the list of [jurisdictions](jurisdictions.mdx) or in a form of an advice to [Community counsel pages](../community-counsel.mdx), like sharing examples of Exit Gateway [landing pages](landing-pages.mdx), templates etcetra.

## How to add content

Our aim is to establish a strong community network, sharing legal findings and other suggestions with each other. We would like to encourage all of the current and future operators to do research about the situation in the jurisdiction they operate in as well as solutions to any challenges when running an Exit Gateway and add those through a pull request (PR). Please check out the [steps to make a pull request](add-content.mdx).

## Tor legal advice

Giving the legal similarity between Nym Exit Gateways and Tor Exit Relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page.

Note that Tor states:
> This FAQ is for informational purposes only and does not constitute legal advice.

*Check legal advice prior to running an exit relay*

* Understand the risks associated with running an exit relay; E.g., know legal paragraphs relevant in the country of operations:
    - US [DMCA 512](https://www.law.cornell.edu/uscode/text/17/512); see [EFF's Legal FAQ for Tor Operators](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq) (a very good and relevant read for other countries as well)
    - Germany’s [TeleMedienGesetz 8](https://www.gesetze-im-internet.de/tmg/__8.html) and 15](https://www.gesetze-im-internet.de/tmg/__15.html)
    - Netherlands: [Artikel 6:196c BW](http://wetten.overheid.nl/BWBR0005289/Boek6/Titel3/Afdeling4A/Artikel196c/)
    - Austria: [E-Commerce-Gesetz 13](http://www.ris.bka.gv.at/Dokument.wxe?Abfrage=Bundesnormen&Dokumentnummer=NOR40025809)
    - Sweden: [16-19 2002:562](https://lagen.nu/2002:562#P16S1)
* Top 3 advice
    - Have an abuse response letter
    - Run relay from a location that is not home
    - Read through the legal resources that Tor-supportive lawyers put together: [www.eff.org/pages/legal-faq-tor-relay-operators](https://www.eff.org/pages/legal-faq-tor-relay-operators) or [www.noisebridge.net/wiki/Noisebridge_Tor/FBI](https://www.noisebridge.net/wiki/Noisebridge_Tor/FBI)
* Consult a lawyer / local digital rights association / the EFF prior to operating an exit relay, especially in a place where exit relay operators have been harassed or not operating before. Note that Tor DOES NOT provide legal advice for specific countries. It only provides general advice (itself or in partnership), eventually skewed towards [US audiences](https://www.eff.org/pages/legal-faq-tor-relay-operators).

*Run an exit relay within an entity*

As an organisation - it might help from a liability perspective
* Within your university
* With a node operators’ association (e.g., a Torservers.net partner)
* Within a company

*Be ready to respond to abuse complaints*

* Make your contact details (email, phone, or even fax) available, instead of those of the ISP
* Reply in a timely manner (e.g., 24 hours) using the [provided templates](https://community.torproject.org/relay/community-resources/tor-abuse-templates)
* Note that Tor states: *“We are not aware of any case that made it near a court, and we will do everything in our power to support you if it does.”*
* Document experience with ISPs at [community.torproject.org/relay/community-resources/good-bad-isps](https://community.torproject.org/relay/community-resources/good-bad-isps/)

Useful links:

* Tor abuse templates:
    - [community.torproject.org/relay/community-resources/tor-abuse-templates/](https://community.torproject.org/relay/community-resources/tor-abuse-templates/)
    - [gitlab.torproject.org/legacy/trac/-/wikis/doc/TorAbuseTemplates](https://gitlab.torproject.org/legacy/trac/-/wikis/doc/TorAbuseTemplates) (from 2020)
    - [github.com/coldhakca/abuse-templates/blob/master/generic.template](https://github.com/coldhakca/abuse-templates/blob/master/generic.template)

* DMCA response templates:
    - [community.torproject.org/relay/community-resources/eff-tor-legal-faq/tor-dmca-response/](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq/tor-dmca-response/)
    - [2019.www.torproject.org/eff/tor-dmca-response.html](https://2019.www.torproject.org/eff/tor-dmca-response.html) (from 2011)
    - [github.com/coldhakca/abuse-templates/blob/master/dmca.template](https://github.com/coldhakca/abuse-templates/blob/master/dmca.template)

---
title: Legal Guide for Nym Exit Gateway Operators
description: Legal considerations for running a Nym exit gateway. Covers ISP communication templates, jurisdiction guidance, and abuse report response strategies.
url: https://nym.com/docs/operators/community-counsel/legal
---

# Community Counsel: General Legal Considerations

**This page contains some tips & tricks to support operators running Exit Gateway (`nym-node` in mode `exit-gateway`) gathered by the operators community. Have a look on the points below to strengthen your legal protection.**

## Useful Suggestions

#### Introduce Nym Node to your provider
Write a message to your provider telling them about your intention to run a `nym-node` on their infrastructure. You can use this template for it.

#### Join Operators Legal Forum
This [Matrix channel](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org&via=matrix.su4ka.icu) is the best place to ask questions and share your experience with others. You can share screen prints of abuse reports and ask for support.

#### Join Operators Legal Clinic
Do you have any questions directed for lawyers? Come and chat with Nym COO Alexis Roussel, every Wednesday 14:30 UTC for 60min in our [Operator Legal Forum channel on Matrix](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org&via=matrix.su4ka.icu).

#### Use a friendly provider
Nym operators community shares their experience with different ISPs on [this page](isp-list). At the same time, consider to move away from these provides:

- Servinga / VPS2day (AS39378)
- Frantech / Ponynet / BuyVM (AS53667)
- Online S.A.S. / Scaleway (AS12876)
- Hetzner Online GmbH (AS24940)
- 1337 Services GmbH / RDP.sh (AS210558)
- Stark Industries Solutions Ltd. / PQ.Hosting / The.Hosting / UFO-AS (AS44477 / ASN 33993)

#### Backup your nodes
Your only way to restore your node is when you have an access to `.nym` directory locally. Follow [node](../nodes/maintenance#backup-a-node) and [proxy configuration](../nodes/maintenance#backup-proxy-configuration) backup guides to be able to [restore your node](../nodes/maintenance#restoring-a-node) on another machine later on, without losing your delegation.

#### Use `nym-exit` prefix on your landing page URL
We would like to ask operators to use [reverse proxy](../nodes/nym-node/configuration/proxy-configuration) with a [landing page](landing-pages). When assigning a domain please use a common convention with `nym-exit` in the beginning of the the page URL as this will create a reputation and reference. The entire address should have this new format:
```
nym-exit.<CUSTOM>.<DOMAIN>.<TLD>
```

For example:

```
# for squads running multiple nodes a format can look like this:
nym-exit.ch-node1.mysquad.org

# or like this
nym-exit.3-jamaica.mysquad.org

# for operators having one node per location, the format can look like this:
nym-exit.brazil.mysquad.org

# or if operators decide to not have any custom, they can simply have this format:
nym-exit.mysquad.org
```

**The `NYM-EXIT` part in the beginning is what's important.**

#### Chose the right TLD
When registering a domain, check [Top Level Domain (TLD)](https://www.techopedia.com/definition/1348/top-level-domain-tld) terms and conditions. For example `.icu` is a no go. Having a wrong TLD may lead to your domain being taken away from you when facing a DMCA report.

#### Respond to abuse reports
Make sure to read notifications from your account provider and if you receive an abuse report, respond to it in time. Here is a template explaining the essential legal background of Nym Node Exit Gateway. Don't forget to adjust the variables.

#### Help us to improve these pages
Add your findings by opening a [Pull Request](add-content).

---
title: Email & Legal Templates for Nym Node Operators
description: Ready-to-use templates for communicating with VPS providers about running Nym nodes. Includes introduction emails and abuse report response templates.
url: https://nym.com/docs/operators/community-counsel/templates
---

# Templates for Providers

Communication with your provider is an essential part of legal defense, as more often than not, terminating a server is based on the lack of knowledge about Nym Node and it's legal bases. Use the following templates to introduce your intention to run a Nym Node or as a response to abuse report.

<VarInfo/ >

## Email Templates

### Introduction to server provider

### DMCA abuse report response

---
title: Exit Gateway - Jurisdictions
url: https://nym.com/docs/operators/community-counsel/jurisdictions
---

# Exit Gateway - Jurisdictions

The following part is for informational purposes only. Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the [Node Operator](https://matrix.to/#/#operators:nymtech.chat) and [Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) channels on Element to share best practices and experiences.

There is no one silver bullet covering the entire globe. Every jurisdiction has different set of laws and practices regarding internet traffic routing. Therefore the Node Operators Legal Forum pages are divided per region.

These are some findings from our legal team as an example:

- [Switzerland](jurisdictions/swiss.mdx)
- [United States](jurisdictions/united-states.mdx)

> Nym Node operators are invited to add their legal findings directly through [pull requests](add-content.mdx).

---
title: Legal environment: Switzerland
url: https://nym.com/docs/operators/community-counsel/jurisdictions/swiss
---

# Legal environment: Switzerland

The following part is for informational purposes only. Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the [Node Operator](https://matrix.to/#/#operators:nymtech.chat) and [Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) channels on Element to share best practices and experiences.

## Findings from our legal team

> **Note:** The information shared below is in the stage of conclusions upon final confirmation. The text is a not edited exert from a legal counsel. Nym core team is asking for more clarifications.

### Operators of Exit Nodes

#### Telecoms Law

As well as operators of normal mixnet nodes, operators of exit nodes might be considered telecommunications providers according to the broad term of the telecommunications act (TCA).
The regulatory consequences have already been laid out in section 5.1.2.2.1 above.

#### Telecoms Surveillance Law

Unlike normal mixnet nodes, exit nodes might have information about the communication party which uses the respective exit node (in particular its IP address). They might therefore be a target for surveillance authorities, at least at first glance.

However, as the IP address of the communications party is disguised on the other side of the communications through the Nym encryption infrastructure, the usual situation, where an IP address or another trace of an Internet user is found in the connection with a criminal activity (e.g., in a web server protocol), and then used in cooperation with the user’s provider to identify the user, is not going to take place.

The same is true for the opposite side: The node operator does not see the communication party of his user.

Experience has shown that Swiss investigative authorities are aware of these limitations and do not conduct investigations against individuals who operate TOR nodes, for example. In one specific case that I know of, the investigation was stopped by the police as soon as it was clear that a TOR node was being operated.

I therefore consider the risk for an exit node operator to become involved in a SPTA proceeding as low.

Nevertheless, in such a situation, exit node operators providers would have to provide the authorities with the information already available to them (Art. 22 Para. 3 SPTA), and they would have to tolerate monitoring by the authorities or by the persons commissioned by the service of the data which the monitored person transmits or stores using derived communications services (Art. 27 Para. 1 SPTA; see above, 5.1.1.2). There is no duty of data retention for providers of derived communication services, though.

The risk for exit node operators of being upgraded according to Art. 22 Para. 4 SPTA is low to non existent for the reasons mentioned above.

#### Intelligence Service Law

Operators of exit nodes do not provide wire-based telecommunications services either and therefore do not fall under the IntelSA.

### Nym as VPN provider

#### Telecoms Law

Nym as a VPN operator might be considered a telecommunication provider under the newly revised TCA, as the term now also covers operators of Over-the-Top services which are carried out over the internet.

However I consider possible administrative burdens arising from this qualification as negligible (see above, 5.1.2.1).

#### Telecoms Surveillance Law

VPN providers have information about the communication party which uses the respective exit node (in particular its IP address). They might therefore be a target for surveillance authorities, at least at first glance.

However, for the same reason I see a risk low for exit node operators to become involved in a SPTA proceeding (the IP address is not visible to the communication partner, which is exactly the reason the Nym VPN is being used at all), I also see a low risk for Nym itself to become involved in such a proceeding (see above, 5.1.3.2).

#### Intelligence Service Law

VPN operators do not provide wire-based telecommunications services and therefore do not fall under the IntelSA.

### EU chat control regulation in particular

According to a EU commission proposal for a regulation laying down rules to prevent and combat child sexual abuse (https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX: 52022PC0209) hosting providers and providers of so-called interpersonal communication services should be obliged to perform an assessment of risks of online child sexual abuse. Additionally an obligation for certain providers should be established to detect such abuse, to report it via the EU Centre, to remove or disable access to, or to block online child sexual abuse material when so ordered.

'Interpersonal communications service’ means a service normally provided for remuneration that enables direct interpersonal and interactive exchange of information via electronic communications networks between a finite number of persons, whereby the persons initiating or participating in the communication determine its recipient(s) and does not include services which enable interpersonal and interactive communication merely as a minor ancillary feature that is intrinsically linked to another service (Art. 2 Point 5 Directive (EU) 2018/1972, which is also relevant for the mentioned proposal).

Interpersonal communications services are services that enable interpersonal and interactive exchange of information. Interactive communication entails that the service allows the recipient of the information to respond. The proposal therefore only covers services like traditional voice calls between two individuals but also all types of emails, messaging services, or group chats. Examples for services which do not meet those requirements are linear broadcasting, video on demand, websites, social networks, blogs, or exchange of information between machines (Directive (EU) 2018/1972, Consideration 17).

Neither the Nym encryption infrastructure nor the NYM VPN are used as means for an interactive exchange of information in the aforementioned sense (of e-mail, messaging, chats or similar).

I therefore consider the risk arising from the mentioned proposal for Nym as low, be it as software developer or VPN operator.

However, an application provider which uses the Nym encryption infrastructure to provide encrypted chat services or similar could still fall under the proposal. This might pose a commercial risk for Nym as the provider of the basic infrastructure for such services, because such services might lose their commercial value for end customers.

Currently the EU decision on chat control has been postponed because there is a blocking minority which can prevent the adoption of the respective parts of the law. In addition, even EU internal lawyers held that the proposal was clearly in violation of the EU charter of fundamental rights and would therefore be nullified by the EU courts in case it would still be enacted by the parliament.

I therefore consider the risk that the mentioned proposal is enacted by the EU authorities and finally upheld by the courts in its planned form as low.

---
title: Legal environment: United States
url: https://nym.com/docs/operators/community-counsel/jurisdictions/united-states
---

# Legal environment: United States

The following part is for informational purposes only. Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the [Node Operator](https://matrix.to/#/#operators:nymtech.chat) and [Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) channels on Element to share best practices and experiences.

## Findings from our legal team

> **Note:** The information shared below is in the stage of conclusions upon final confirmation. The text is a not edited exert from a legal counsel. Nym core team is asking for more clarifications.

The US legal counsel have so far provided the following advice:

The legal risk faced by VPN operators subject to United States jurisdiction depends on various statutes and regulations related to privacy, anonymity, and electronic communications. The key areas to consider are: intermediary liability and exceptions, data protection, copyright infringement, export controls, criminal law, government requests for data and assistance, and third party liability.

As outlined in Part A, the United States treats VPNs as telecommunications networks subject to intermediary liability protection from wrongful conduct that occurs on its network. However, such protections do have exceptions including criminal law and copyright claims that are worth considering. In the United States, I am not aware of an individual ever being prosecuted or convicted for running a node for a dVPN or a Privacy Enhancing Network.

However, as discussed in Part B-C, VPN operators are subject to law enforcement requests for access or assistance in obtaining access to data relevant to an investigation into allegedly unlawful conduct that was facilitated by the network as an intermediary. As shown in Part C, governments may also request assistance from node operators for certain high-level and national security targets.

Finally, as outlined in Parts D-G, VPN operators may also be subject to non-criminal liability including (Part D) failing to respond to notices under the DMCA, (Part E) privacy and data protection law, (Part F) third party lawsuits stemming from wrongful acts committed using the network, and (G) export control violations.

---
title: Where to host your `nym-node`?
url: https://nym.com/docs/operators/community-counsel/isp-list
---

# Where to host your `nym-node`?

Inspired by a valuable resource, done by Tor community - [*Good Bad ISPs*](https://community.torproject.org/relay/community-resources/good-bad-isps/), LunarDAO squad initiated a table customised for Nym Exit Gateways operators.

This ISP list is fully managed by Nym operator community and it serves as a space to share their experience of running Exit Gateways on various Internet Service Providers (ISPs). The ISPs greatly differ in regards to services they offer as well as to their openess of hosting exit routing software.

Please share any experiences running a node like policies, complains, legal issues and solutions, discrepancy between offers and reality (bandwidth, IP range, locations) or anything regarding pricing or customer support.

If you came across any legal findings, please share them in our [list of jurisdictions](jurisdictions).

While we trust that Nym node operators are honest, we would like to ask everyone to do your own research.

To edit or add information to the ISP list, make changes to the csv file located [here](https://github.com/nymtech/nym/blob/develop/documentation/docs/data/csv/isp-sheet.csv) and submit your edits as a pull request according to [this guide](add-content.mdx).

---
title: Landing Pages
url: https://nym.com/docs/operators/community-counsel/landing-pages
---

# Landing Pages

The entire content of this page is under [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/).

> Nym Node operators are invited to add their legal findings and suggestions directly through [pull requests](add-content.mdx).

Exit Gateway landing page is a great and transparent way to prevent possible troubles by providing people with basic facts, links to laws and regulations on a given topic as well as operator's contact info. To inspire each other we share some examples how Nym community handled this issue below.

Initiated by an amazing pull request from Avril 14th we made a complete guide to setup landing page behind [reverse proxy and Web Secure Socket](../nodes/nym-node/configuration/proxy-configuration.mdx) for Nym Nodes.

---
title: Adding Content to Legal Forum
url: https://nym.com/docs/operators/community-counsel/add-content
---

# Adding Content to Legal Forum

Our aim is to establish a strong community network, sharing legal findings and other suggestions with each other. We would like to encourage all of the current and future operators to do research about the situation in the jurisdiction they operate in, to share solutions to the challenges they encountered when running Exit Gateway, and create a pull request (PR).

First of all, please join our [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat) and post any information or questions there.

To add your information to this book, you can create a PR directly to our [repository](https://github.com/nymtech/nym/tree/develop/documentation/operators/src/legal).

## Steps to make a pull request:

###### 1. Write down your legal findings, suggestions, communication templates, FAQ in a text editor

###### 2. Clone `nymtech/nym` repository or pull in case you already have it and switch to `develop` branch

- Clone the repository
```sh
git clone https://github.com/nymtech/nym.git
```

- Go to the directory nym
```sh
cd nym
```

- Switch to branch develop and update the branch
```sh
git checkout develop
git pull origin develop
```

###### 3. Make your own branch based off `develop` and switch to it

- Choose a descriptive and consise name without using `<>` brackets

```sh
git checkout -b operators/community-counsel/<NEW_BRANCH_NAME>

# example: git checkout -b operators/community-counsel/alice-vps-faq-template
```

- Verify that you are on the right branch
```sh
git branch
```

###### 4. Save your legal findings as `<JURISDICTION_NAME>.md` to `/nym/documentation/docs/pages/operators/community-counsel/jurisdictions` or add info to an existing page

###### 5. Add to git, commit and push your changes

```sh
cd documentation/docs/pages/operators/community-counsel/jurisdictions
git add <FILE_NAME>.md
git commit -am "<DESCRIBE YOUR CHANGES>"
git push origin operators/community-counsel/<NEW_BRANCH_NAME>
```
###### 6. Create a pull request

- Open the git generated link in your browser, fill the description and click on `Create a Pull Request` button
```sh
# the url will look like this
 https://github.com/nymtech/nym/pull/new/operators/community-counsel/<NEW_BRANCH_NAME>
```
###### 7. Notify others in the [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat) about the PR.

- Someone from the team will reach out to you, stay in touch to finalise the PR

---
title: Code of Conduct
url: https://nym.com/docs/operators/misc/coc
---

# Code of Conduct

We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.

Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all.

Please be kind and courteous. There’s no need to be mean or rude.

Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.

Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.

We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behaviour that excludes people in socially marginalized groups.

Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Rust moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.

Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.

---
title: Licensing
url: https://nym.com/docs/operators/misc/licensing
---

# Licensing

As a general approach, licensing is as follows this pattern:

* <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://nym.com">Nym Documentation</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://nym.com">Nym Technologies</a> is licensed under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></p>

* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)

* Used libraries and different components are [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) or [MIT](https://mit-license.org/)

For accurate information, please check individual files.

---
title: Terms and Conditions
url: https://nym.com/docs/operators/misc/toc
---

# Terms and Conditions

With `nym-node` version `1.1.3`, NymTech SA introduced [**Operators Terms & Conditions**](https://nymtech.net/terms-and-conditions/operators/v1.0.0) for operators who want their nodes to become a part of the active set of Nym Mixnet.

There has been a long ongoing discussion whether and how to apply Terms and Conditions for Nym network operators, with an aim to stay aligned with the philosophy of Free Software and provide legal defense for both node operators and Nym developers. To understand better the reasoning behind this decision, you can listen to the first [Nym Operator Town Hall](https://www.youtube.com/live/7hwb8bAZIuc?si=3mQ2ed7AyUA1SsCp&t=915) introducing the T&Cs or to [Operator AMA with CEO Harry Halpin](https://www.youtube.com/watch?v=yIN-zYQw0I0) from June 4th, 2024, explaining pros and cons of T&Cs implementation.

Accepting T&Cs is done via an explicit flag `--accept-operator-terms-and-conditions` added to `nym-node run` command.

More information on how to setup your node or check whether any node has T&C accepted can be found in [`nym-node` setup guide](/operators/nodes/nym-node/setup#terms--conditions).

---
title: Nym Network APIs Overview
description: Overview of Nym HTTP APIs for querying node performance, token supply, credential data, and blockchain state, with guidance on which API to use.
url: https://nym.com/docs/apis/introduction
---

# APIs

The Nym network exposes several HTTP APIs for querying network state, node performance, blockchain data, and credential information, with each API serving a different purpose.

## Which API should I use?

| I want to... | API |
|---|---|
| Query node performance, roles, and mixnet statistics | [Node Status API](/apis/ns-api) |
| Query circulating NYM supply or zk-nym credential data | [NymAPI](/apis/nym-api) |
| Query blockchain state, account balances, or transactions | [Validator REST API](/apis/cosmos-sdk-nyx) |
| Query legacy explorer data | [Explorer API](/apis/explorer-api) *(deprecated)* |

## Node Status API

The primary API for querying node information. It serves data about individual `nym-node` instances: roles, statistics, Network Requester services, and overall mixnet summaries. If you're building an explorer, analytics dashboard, or monitoring tool, start here.

If you're building a service that makes heavy use of the Node Status API, consider [running your own instance](/operators/performance-and-testing/ns-api-deployment) to distribute load across the network.

**Endpoints:** [OpenAPI spec](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json) · [Swagger](https://mainnet-node-status-api.nymtech.cc/swagger/)

## NymAPI

A sidecar binary operated by Nyx Validators. It caches smart contract data and exposes endpoints for circulating NYM supply, zk-nym credential data, and ticketbook information. Use this when you need token economics or credential data.

**Endpoints:** [OpenAPI spec](https://validator.nymtech.net/api-docs/openapi.json) · [Swagger](https://validator.nymtech.net/api/swagger/index.html)

Other NymAPI instances are listed at [cosmos.directory/nyx](https://cosmos.directory/nyx).

## Validator REST API

The standard Cosmos SDK REST API exposed by Nyx Validators. Use this for direct chain queries: account balances, transaction history, governance proposals, and staking information.

**Endpoints:** [OpenAPI spec](https://api.nymtech.net/swagger/swagger.yaml) · [Swagger](https://api.nymtech.net/swagger/)

Other validator endpoints are listed at [cosmos.directory/nyx](https://cosmos.directory/nyx).

## Explorer API

The Explorer API is deprecated. Use the [Node Status API](/apis/ns-api) instead.

The legacy backend for the [Mixnet Explorer](https://nym.com/explorer). This API is being replaced by the Node Status API, which provides the same data and more.

**Endpoints:** [OpenAPI spec](https://explorer.nymtech.net/api/v1/openapi.json) · [Swagger](https://explorer.nymtech.net/api/swagger/index.html)

---
title: Node Status API - Nym Node Performance and Mixnet Stats
description: Reference for the Node Status API, which provides nym-node identity, performance scores, role assignments, and mixnet health summaries.
url: https://nym.com/docs/apis/ns-api
---

# Node Status API

The Node Status API serves information about individual `nym-node` instances in the Nym network: which role they are operating in, performance statistics, Network Requester services, and summaries of the overall mixnet state. It is the primary API for anyone building explorers, analytics dashboards, or monitoring tools.

**Key endpoint categories:**
- **Node information**: identity, bonding status, declared roles, build version, host details
- **Performance scores**: routing reliability, configuration scores, probe results
- **Mixnet summaries**: active set composition, role distribution, network health

If you're building a service that makes heavy use of this API, consider [running your own instance](/operators/performance-and-testing/ns-api-deployment) to distribute load and promote a robust network of downstream services.

## Quick examples

**Get a summary of all gateways:**
```bash
curl https://mainnet-node-status-api.nymtech.cc/api/v1/gateways
```

**Get details for a specific node by identity key:**
```bash
curl https://mainnet-node-status-api.nymtech.cc/api/v1/gateways/23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb
```

## Mainnet endpoints

- **OpenAPI spec:** [mainnet-node-status-api.nymtech.cc/api-docs/openapi.json](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json)
- **Swagger UI:** [mainnet-node-status-api.nymtech.cc/swagger/](https://mainnet-node-status-api.nymtech.cc/swagger/)

## Full API reference

---
title: NymAPI - Token Supply and Credential Endpoints
description: Reference for the NymAPI, a validator sidecar that caches Nyx blockchain data and exposes endpoints for circulating NYM supply, zk-nym credentials, and network topology.
url: https://nym.com/docs/apis/nym-api
---

# NymAPI

The NymAPI is a sidecar binary operated by members of the Nyx Validator set that caches smart contract data from the Nyx blockchain and exposes it via HTTP endpoints, making queries faster and more scalable than querying the chain directly.

**Key endpoint categories:**
- **Token economics:** circulating NYM supply, staking information
- **Credential data:** zk-nym ticketbook information, global and per-ticketbook data
- **Network topology:** cached node and mixnet data from on-chain contracts

For operator setup instructions, see the [NymAPI Operator Guide](/operators/nodes/validator-setup/nym-api).

## Quick examples

**Get the circulating NYM supply:**
```bash
curl https://validator.nymtech.net/api/v1/circulating-supply
```

**Get the current network topology (Mix Nodes and gateways):**
```bash
curl https://validator.nymtech.net/api/v1/mixnodes/active
```

## Mainnet endpoints

- **OpenAPI spec:** [validator.nymtech.net/api-docs/openapi.json](https://validator.nymtech.net/api-docs/openapi.json)
- **Swagger UI:** [validator.nymtech.net/api/swagger/index.html](https://validator.nymtech.net/api/swagger/index.html)

Other NymAPI instances are available. You can find their Swagger endpoints here:

There is also an overview of endpoints at [cosmos.directory/nyx](https://cosmos.directory/nyx).

## Full API reference

---
title: Nyx Validator REST API - Cosmos SDK Endpoints
description: Reference for the Nyx Validator REST API, providing Cosmos SDK endpoints for account balances, staking, governance, and CosmWasm smart contract queries.
url: https://nym.com/docs/apis/cosmos-sdk-nyx
---

# Validator REST API

Nyx Validators are built with the [Cosmos SDK](https://docs.cosmos.network/) and expose a standard [REST API](https://docs.cosmos.network/api) for querying chain state directly.

**Key endpoint categories:**
- **Accounts**: balances, transaction history
- **Staking**: validators, delegations, rewards
- **Governance**: proposals, votes
- **CosmWasm**: smart contract queries

For validator setup instructions, see the [Nyx Validator Setup Guide](/operators/nodes/validator-setup).

Other validator endpoints are listed at [cosmos.directory/nyx](https://cosmos.directory/nyx).

## Quick examples

**Query an account balance:**
```bash
curl https://api.nymtech.net/cosmos/bank/v1beta1/balances/n1...
```

**List active validators:**
```bash
curl https://api.nymtech.net/cosmos/staking/v1beta1/validators?status=BOND_STATUS_BONDED
```

## Mainnet endpoints

- **OpenAPI spec:** [api.nymtech.net/swagger/swagger.yaml](https://api.nymtech.net/swagger/swagger.yaml)
- **Swagger UI:** [api.nymtech.net/swagger/](https://api.nymtech.net/swagger/)

## Full API reference

---
title: Explorer API (Deprecated)
description: Legacy Explorer API reference for the Nym Mixnet Explorer. Deprecated in favor of the Node Status API.
url: https://nym.com/docs/apis/explorer-api
---

# Explorer API

The Explorer API is deprecated. Use the [Node Status API](/apis/ns-api) instead, which provides the same data and more.

The Explorer API is the legacy backend for the [Mixnet Explorer](https://nym.com/explorer).

## Mainnet endpoints

- **OpenAPI spec:** [explorer.nymtech.net/api/v1/openapi.json](https://explorer.nymtech.net/api/v1/openapi.json)
- **Swagger UI:** [explorer.nymtech.net/api/swagger/index.html](https://explorer.nymtech.net/api/swagger/index.html)
