Menu

Create a Haveno Network

Haveno Network Deployment and Management Guide (Haveno.com Edition)

This guide provides a comprehensive, step-by-step walkthrough for deploying and managing a Haveno network instance tailored to haveno.com’s modified core. We will cover setting up all key components with best practices for reliability (using systemd on VPS or Docker containers), integrating a Monero node, and configuring network-specific parameters. Each section below focuses on a particular stage or component of the deployment.

Table of Contents:

Service Setup on a VPS (Systemd vs. Docker)

For maximum reliability, run the Haveno network’s critical services (seed nodes, price nodes, Monero nodes, etc.) on a stable VPS and manage them as background system services. Using systemd is recommended for automatically starting and monitoring these components on boot:

  • Seed Nodes, Price Nodes, Monero Nodes: Install them as persistent systemd services for stability and automatic restarts. This ensures the network backbone is always available.
  • Arbitrator Nodes: Since arbitrators may require interactive monitoring (using the Haveno GUI for dispute resolution), it can be convenient to run arbitrator nodes in a detached terminal session (e.g. using screen or tmux) rather than as strict system services. This allows arbitrators to easily check the GUI while keeping the process running on the server.

Make sure your VPS is secure and hardened before deployment. Following Monero’s official server hardening guidelines for Linux servers is advisable. This includes steps like creating a dedicated haveno user for running services, enabling firewalls, and keeping system packages up to date.

Docker Alternative: If you prefer containerization, Haveno supports running services via Docker. Using Docker Compose can greatly simplify multi-service setup (Tor, DNS, seed node, etc.) and provides isolation. In fact, the Haveno team provides a dedicated guide and resources to build and manage a Haveno network using Docker. Docker can automate dependency setup and improve portability. In this guide, we will highlight Docker usage for various components (Monero node, Haveno daemon, etc.) alongside the manual setup instructions.

Installing Dependencies (Linux, macOS, Windows)

Before compiling or running Haveno services, ensure the required dependencies are installed on your system. Haveno is written in Java and uses Gradle for builds, so a compatible JDK and build toolchain are necessary.

For Linux and macOS

Install the Java Development Kit (JDK) 21. It’s recommended to use SDKMAN! for managing Java versions on Unix-like systems:

curl -s "https://get.sdkman.io" | bash    # install SDKMAN
sdk install java 21.0.2.fx-librca        # install JDK 21 via SDKMAN

On Ubuntu 22.04 or similar, you can alternatively install OpenJDK 21 via apt:

sudo apt-get update && sudo apt-get install openjdk-21-jdk

These steps ensure you have Java 21 available, which is required for Haveno’s build .

Other build tools on Linux/macOS (like GCC, Make, etc.) are not explicitly needed beyond what the Haveno build scripts handle, but ensure basic development tools are present. Git is needed to clone the repository.

For Windows

On Windows, the preferred approach is to use MSYS2 to provide a Unix-like environment and toolchain:

  1. Download and install MSYS2 from the official site. After installation, launch the MSYS2 MINGW64 (for 64-bit) or MINGW32 (for 32-bit) shell.
  2. Update the package database with pacman -Syy, then install build tools and Git. For 64-bit Windows, run:
    bash pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake git make
    For 32-bit, use the mingw-w64-i686-... equivalents .
  3. Install Java 21 inside MSYS2. You can use SDKMAN here as well:
    bash curl -s "https://get.sdkman.io" | bash sdk install java 21.0.2.fx-librca
    Ensure the JAVA_HOME is set appropriately if needed.

After these steps, whether on Linux, macOS, or Windows, you should have Java 21 and a C++ toolchain available, which are necessary for building Haveno (the Haveno build process will compile some native components and bundled Monero code).

Forking and Building the Haveno.com Core

Haveno.com’s network uses a modified core codebase (a fork of the official Haveno DEX). It’s recommended to fork the repository and build from source to incorporate haveno.com’s customizations (such as custom network parameters, removed binaries, etc.). A known fork used in haveno.com’s deployment is maintained by Kewbit, which incrementally removes bundled binaries for cleaner builds .

Steps to build Haveno:

  1. Clone the repository. For example, clone Kewbit’s Haveno fork (which reflects haveno.com’s latest core changes):
    bash git clone https://foss.haveno.com/haveno-network/haveno-core cd haveno-core
  2. Compile the project. Haveno uses Flutter but under the hood uses Java / Gradle and have an easy to use Makedilw. If you're compiling and have already setup
    bash make clean && skip-tests
    This will fetch dependencies and build all Haveno modules (including the desktop app, seed node, etc.). The first build may take some time as it downloads all requirements. If the build succeeds, you will have the Haveno binaries/artifacts in the project directory (look for haveno-daemon, haveno-seednode, etc., or .jar files under desktop/build).

Note: The haveno.com fork may update over time, ensure you keep your fork in sync with any upstream improvements. The build outputs will be used for setting up seed nodes, arbitrator app, and packaging the desktop application for users.

Monero Node Setup and Integration

Since Haveno is a Monero-centric exchange, a Monero daemon (monerod) is a critical part of the infrastructure. Every seed node and arbitrator node must have access to a local, unrestricted Monero node for performance and full functionality . This allows Haveno to verify transactions, create multi-signature wallets, and monitor the Monero blockchain privately. There are multiple ways to set up a Monero node:

  • Systemd Service on VPS: If deploying on Linux, you can run monerod as a system service. Haveno’s docs provide example .service and .conf files which you can customize with your preferred settings (data directory, RPC ports, etc.). For instance, you might create a /etc/systemd/system/monerod.service that runs monerod --rpc-bind-port 18081 --rpc-restricted-bind-ip 0.0.0.0 --no-igd --prune-blockchain (and any other desired flags) on startup. Ensure the Monero service runs as a non-root user (for security) and is set to restart on failure.
  • Manual Launch: If you built Haveno from source, you can use the convenience targets to launch Monero. For example, running make monerod in the Haveno project directory will start a mainnet Monero daemon, and make monerod-stagenet will start one on stagenet. This is useful for quick testing. In production, though, you’d likely prefer the daemon always running via systemd or Docker rather than a manual terminal.
  • Monero GUI/CLI (Desktop): On Windows or macOS, you might opt to run the official Monero GUI or CLI wallet which includes the daemon. Haveno.com also highlights a Monero Daemon GUI tool (created by community dev if-everoddandeven) for easier management of monerod on Windows. This can simplify running a node on a Windows server or even a desktop environment. The key is to run it in unrestricted mode (so that the Haveno processes can use the RPC).
  • Docker Container: A very convenient method is to use the official Haveno Docker image for Monero. Haveno’s Docker repository provides an image havenodex/monerod:latest which can be deployed in a Docker Compose setup . For example, a simple docker-compose.yml to run monerod might look like:

```yaml
version: '3'
services:
monerod:
image: havenodex/monerod:latest
restart: unless-stopped
volumes:

    - monero-data:/home/monero/.bitmonero
  ports:
    - "18080:18080"    # P2P port
    - "18081:18081"    # RPC (full access)
    - "18089:18089"    # RPC (restricted)
  command:
    - --rpc-bind-port=18081
    - --rpc-restricted-bind-ip=0.0.0.0
    - --rpc-restricted-bind-port=18089
    - --no-igd
    - --enable-dns-blocklist
    - --prune-blockchain

volumes:
monero-data:
```

In this setup, port 18081 is the unrestricted RPC accessible (bound to all interfaces for convenience) and 18089 is a restricted RPC port for less trusted access . Haveno seed nodes and arbitrators should use the full RPC (http://localhost:18081 inside the container, or the container’s host IP) for complete access to wallet creation and transaction signing. The restricted RPC (which limits sensitive commands) can be exposed if you need external light wallets to connect. Always secure these ports behind a firewall or run on localhost if possible.

Regardless of how you deploy the Monero node, sync it fully to the Monero blockchain before enabling trading on Haveno. Use --prune-blockchain if disk space is a concern (pruned nodes are supported). Additionally, configure monerod for reliability: enable it to start on boot (via systemd or Docker), and consider using --db-sync-mode safe or fast as needed for your environment. For security, never use a remote third-party Monero node for seed/arbitrator roles, doing so could degrade performance and leak privacy. A local node is strongly recommended for all critical Haveno roles .

Optional: Haveno’s documentation references a Monero Suite tool that generates a Docker deployment based on a simple form. This could be useful if you want a quick way to get a preconfigured monerod container (with settings for remote access, etc.) without writing the compose file manually.

Deploying Price Nodes

Price nodes are auxiliary services that fetch and serve market price data (exchange rates) to Haveno clients. They provide reference prices for XMR vs other currencies, which traders use when creating offers. In Haveno’s architecture, price nodes run independently (outside of the main Haveno daemon) and can operate on clearnet or as Tor hidden services. While not strictly required for the network to function, having at least one price node is important so that users can see price feeds and the app can compute suggested fiat/XMR conversion rates .

To set up a price node:

  1. Install/Build the Price Node Service: Follow the instructions in the official Haveno Price Node repository. The price node has its own codebase (likely a smaller service). You may need to clone a repo (for example, haveno-pricenode) and build or run a Docker image if provided. This service will typically fetch prices from external APIs (like Binance, CoinGecko, etc.) and serve them via a simple HTTP API.
  2. Run the Price Node (systemd or Docker): Once configured, run the price node on a server. You can run multiple instances (onion service and clearnet) for redundancy. It’s wise to run it as a systemd service if on a VPS. For example, create a haveno-pricenode.service that executes the price node jar or binary and keep it running. If Docker is preferred, run the price node inside a container (check if an official image is available, or build one from the repo).
  3. Register the Price Node in Haveno clients: The Haveno desktop application needs to know the URL of your price node(s). In the Haveno code, update the DEFAULT_NODES list in ProvidersRepository.java to include the address of your new price node. This could be an onion address (http://<price_node_onion>.onion:port) or a clearnet URL. After adding it, recompile or distribute this updated client so that all users will use your price node by default. Alternatively, users can manually add a price node in their app settings, but having it in the defaults is easier.
  4. Environment Configuration: Haveno’s documentation mentions a haveno-pricenode.env configuration file. Use this to set any needed environment variables, like API keys for data sources or listening port. Ensure the price node uses a stable port and, if running on Tor, has a persistent hidden service address.

Once running, test that the price node is reachable. You can use a web browser or curl to GET the price endpoint (the specific path will be in the price node docs, e.g. something like /prices returning JSON). Haveno clients periodically poll these nodes to update the market price display.

Tip: Price nodes do not require access to the P2P network or Monero node, they are HTTP services. But to preserve privacy, it’s good practice to run price fetches through Tor or use privacy-respecting APIs. If running a clearnet price node, consider using a separate server from your seed nodes for better isolation.

Configuring Seed Nodes (With and Without PoW)

Seed nodes form the backbone of the Haveno P2P network. They introduce peers to each other, track the network’s offer board, and distribute critical info like trade fees and arbitrator lists. In Haveno (like Bisq, on which it’s based), seed nodes are often run as Tor hidden services whose addresses are hardcoded into client binaries for bootstrapping. You should plan to run multiple seed nodes (for redundancy) and keep them online 24/7.

Haveno supports two modes for seed nodes:

Seed Nodes Without Proof-of-Work (Basic Seed Nodes)

This is the simpler configuration where clients can connect to the seed node without performing any extra handshake proof-of-work (PoW). The setup steps are:

  1. Compile Haveno and Run a Monero Node: Ensure you have built the Haveno project (as above) and have a Monero daemon running locally. The seed node process will connect to monerod via RPC, so the Monero node must be running on the same machine and listening (e.g., on http://localhost:18081 for mainnet) .
  2. Create a Systemd Service for the Seed Node: Haveno’s source includes an executable or script for the seed node (often named haveno-seednode). You can run this directly, but it’s best to set it up as a service. Customize the provided haveno-seednode.service template to your environment. Important settings include:
  3. Network: Set the base currency network to mainnet (e.g., --baseCurrencyNetwork=XMR_MAINNET) unless you are doing a stagenet/testnet.
  4. Ports: Specify the P2P port (e.g., --nodePort=2002 for a seed node, 2002 is a common default for one seed, you can use different ports for others) .
  5. Tor integration: By default, if no special Tor config is provided, the seed node will start its own Tor hidden service for the P2P node. This requires Tor to be installed. If Tor is running locally (e.g., tor daemon on port 9050), the seed node will create an onion address automatically. You’ll see this in logs after startup (look for a line like “Hidden Service
    .onion has been announced to the Tor network” in the output). Copy that onion address, as it is the identifier for your seed node.
  6. Monero RPC URL: Include the --xmrNode=http://... option pointing to your Monero node’s RPC (e.g., --xmrNode=http://127.0.0.1:18081 for mainnet). This must be an unrestricted RPC.
  7. Other options: --useLocalhostForP2P=false (so it binds to all interfaces or to Tor, not just localhost) , and --appName=<name> to set a unique application data directory for the seed (to avoid conflicts with client app data) .
  8. Start the Seed Node Service: Enable and start the service:
    bash sudo systemctl enable haveno-seednode.service sudo systemctl start haveno-seednode.service
    Monitor its output with journalctl -u haveno-seednode.service -f to ensure it’s running. When it fully starts, note the Tor onion address it prints (as mentioned above) .
  9. Hardcode/Distribute the Seed Node Address: For your Haveno network, you need to inform all clients of the seed nodes. Usually, this means updating the list in the code or config that contains seed node addresses (e.g., a property xmr_mainnet.seedNodes or a constant array in the code). Haveno’s documentation suggests adding the onion to xmr_<network>.seednodes list. If you have multiple seed nodes, add all of them. Then recompile the Haveno client so that the default seed list includes your nodes. If you prefer not to hardcode, you can also manually give users the seed node addresses (via a config file or command-line), but hardcoding in the custom build is easiest for a controlled network.
  10. Run Multiple Seeds: Repeat the above for additional seed nodes (ideally on different servers). Each will have its own onion address and port. Ensure each is listed in the clients’ config. If any seed node address changes, you must notify users (or update the app) to maintain connectivity .

With basic seed nodes configured, new Haveno clients will connect through Tor to one of the seed onions and sync the network data (offers, etc.). Always keep your seed nodes online and monitor their logs for any issues.

Seed Nodes With Proof-of-Work (Anti-DoS Protected Seed Nodes)

Proof-of-Work enabled seed nodes require connecting peers to perform a lightweight computational puzzle to get service. This is a mechanism to mitigate DoS attacks on the seed node by malicious spam. Setting this up is a bit more involved, because Tor does not natively require PoW for hidden service client connections, it’s achieved via a Tor patch or addon.

To deploy a PoW-protected seed node, follow these additional steps (on top of the basic setup):

  1. Install a PoW-capable Tor: Use the Tor Project’s repository to get the latest Tor (which may include anti-DoS features) rather than the system default. For Debian/Ubuntu, add Tor’s official apt repo and GPG key, then install Tor from there. For example:
    bash sudo apt install tor deb.torproject.org-keyring
    (Refer to Tor docs for the specific repository lines for your distro.) Confirm that tor is installed and updated to a version supporting anti-rendezvous DOS mitigation.
  2. Configure Tor for PoW: Replace the default torrc configuration with the one provided by Haveno (in the seednode/torrc file of the Haveno repo). The provided torrc is tuned for Haveno seed nodes. For instance, it likely sets HiddenServiceEnableIntroDoSDefense or similar options if available, and configures the SocksPort and onion service. Haveno’s example torrc also locks down Tor to only allow onion traffic on the Socks port and includes other hardening (like SocksPort 9050 OnionTrafficOnly, access policies, etc.) . Copy these settings to your Tor config (often in /etc/tor/torrc on Linux) and restart the tor service.
  3. Run the Seed Node with External Tor: In the seed node’s systemd service or startup script, you might need to tell Haveno to use the external Tor rather than spawning its own. In recent updates, if Tor is running and listening on port 9050, Haveno will utilize it. Ensure the haveno-seednode process is not launching an internal Tor (you might see an option like --useDevPrivilegeKeys=false which in older versions prevented some built-in Tor control, but primarily, running the tor daemon separately is the goal). If Haveno allows specifying the hidden service address manually (via --hiddenServiceAddress=<onion>), you could use that, but typically letting it register via Tor control is fine.
  4. Verify PoW Functionality: Once the seed node is up, test connecting a Haveno client to it. The client’s logs should show if it’s performing any proof-of-work to connect. The Tor instance protecting the hidden service will challenge clients automatically if it detects heavy load. As an operator, your setup mostly ensures the Tor service is configured correctly; the clients handle the PoW response.

PoW seed nodes are more resilient under potential denial-of-service floods but introduce a slight delay for first-time connections. Haveno’s documentation provides the necessary Tor configuration to enable this defense. It’s recommended to run at least one seed with PoW and perhaps one without (so new clients that don’t support the PoW protocol can still connect, if applicable).

Note: Setting up PoW on Tor can be complex. Haveno recommends using their Docker deployment for ease if you are not comfortable managing Tor configs. The Docker approach in the Haveno guide includes a custom Tor (or hardened torproxy) container with PoW defense enabled, simplifying this process.

(Optional) Docker Deployment of Seed Nodes

Instead of manually installing Tor and configuring systemd, you can run seed nodes via Docker as well. Haveno’s repository includes a Dockerfile and instructions for seed nodes. In summary: build the haveno-seednode image from the repo’s docker/ folder, then run a container mapping the necessary ports. For example:

docker build -t haveno-seednode ./docker
docker run -d --name seed1 --restart unless-stopped -p 9050:9050 -p 2002:2002 haveno-seednode

Here port 2002 is the Haveno P2P port and 9050 is Tor’s SOCKS port. This assumes Tor is running in the container or the host. If using host Tor, you might not need to expose 9050. The container logs will show the onion address on startup , which you can then use as described earlier. Using Docker ensures the environment (Java version, Tor version, etc.) is consistent and easily replicable.

Registering Developer and Alert Keypairs

Haveno networks have special privilege keys for developers and admins that allow certain actions like setting network-wide parameters and sending alerts. Since you are launching your own Haveno network (not using the default haveno.exchange keys), you must generate and register new keys for the developer and alert roles in your custom build.

Haveno provides a Gradle task to generate new cryptographic keypairs:

  1. Generate Keypairs: In the Haveno project directory, run the Gradle task:
    bash ./gradlew generateKeypairs
    This will output a set of keys (likely printed to console or saved in a file). It typically generates a public/private keypair for each role (developer, alert, etc.) or a generic keypair which you will assign to roles as needed. Save the output, especially the public keys and private keys for each role. Keep the private keys secret, treat them like root passwords, as they control critical network functions.
  2. Register the Developer Key: Open the Haveno source code and locate FilterManager.java. Insert the developer public key you generated into the list of recognized developer keys. (The code likely has a static list or array for developer pubkeys that are allowed to, say, set filters or perform certain moderation tasks.) If there were existing keys (from the original project), remove or disable them for your network, you want only your keys to have dev privileges on haveno.com’s network.
  3. Register Alert (and Notification) Keys: Similarly, take the alert key’s public key and add it to AlertManager.java, and add the private notification key’s public key to PrivateNotificationManager.java. The “alert” key is used to broadcast system-wide alerts (messages that appear in all users’ apps in case of critical updates or warnings). The “private notification” key might be used for certain special messages or features (specific to Haveno’s design for sending encrypted notifications).
  4. Rebuild and Deploy: After inserting these keys, recompile the Haveno code. All network participants (seed nodes, arbitrators, and user clients) should use this updated build so that they recognize the new developer and alert keys. Essentially, the public keys are baked into the application as the authorities for certain actions.

Going forward, use the corresponding private keys when you need to perform the privileged actions (discussed in later sections like setting filters or sending alerts). It’s wise to back up these keys securely (offline). Only the network operator or trusted admin should hold the developer and alert private keys, as their misuse could compromise the network (e.g., a malicious “developer” could set harmful trade filters or an attacker with the alert key could send false alarm messages).

Arbitrator Node Setup and Management

Arbitrators are the dispute resolvers and referees of the Haveno network. They operate special Haveno nodes with the authority to mediate trades and, if necessary, co-sign transactions in the 2-of-3 multisig escrow (the arbitrator holds the third key to adjudicate disputes). On a new Haveno network, you (as the operator) will designate one or more arbitrators. This involves generating arbitrator keys, running the arbitrator application, and informing the network of the arbitrators’ presence. Proper management of arbitrators includes their registration, operations, and possible removal.

Registering an Arbitrator

  1. Generate Arbitrator Keypair: Similar to developer keys, generate a keypair for each arbitrator. You can reuse the Gradle task (generateKeypairs) to produce a new pair (or generate multiple at once). If you have already run it, you may have a set of keys ready. Each arbitrator needs a unique keypair. Record the arbitrator public key and private key securely.
  2. Authorize the Arbitrator in Code: In the Haveno source, find the ArbitratorManager.java (or equivalent) and add the new arbitrator public key to the list of recognized arbitrators. Haveno’s code likely maintains an allowed list of arbitrator pubkeys to prevent unauthorized nodes from claiming to be arbitrators. By inserting the pubkey here, you indicate this key belongs to a valid arbitrator on your network. (Remove any default arbitrator keys that might have been there from testing networks.)
  3. Build and Deploy to Seed Nodes: Recompile and update your seed nodes (and any already-deployed nodes) with this change so the network knows about the arbitrator. Seed nodes, in particular, need the updated list, since they “advertise” arbitrators to clients and enforce their privileges .
  4. Launch the Arbitrator Application: Start the Haveno desktop application in arbitrator mode. If you built from source, there may be a convenient way to launch an arbitrator GUI. For example, the build might produce an arbitrator-desktop binary or you might run make arbitrator-desktop-mainnet to launch it. You can also start the normal Haveno GUI and choose to operate as arbitrator (depending on UI options). When the app opens, go to the Account tab (or a dedicated arbitrator console) and register the arbitrator:
  5. Press the shortcut Ctrl + R in the Account view, which should bring up a prompt to enter an arbitrator key .
  6. Enter the arbitrator’s private key that you generated for this node. This action effectively registers the node on the network as an arbitrator, broadcasting its presence (including its Tor onion address and pubkey) to the seed nodes so clients can discover it. The private key never leaves the app, but the corresponding pubkey is announced (which matches what you added to the code).
  7. Verify Arbitrator Status: Once done, your seed node logs or the arbitrator app logs should indicate a successful registration. The arbitrator’s onion address should now be known to the network (seed nodes will include it in messages to clients). On the arbitrator app, you might see a status that it is recognized as an arbitrator. At this point, users can select this arbitrator in their trades (or it will be auto-assigned by the network if it’s the only one).

Operational notes: An arbitrator node, like seed nodes, must have a local Monero node with unrestricted RPC access. The arbitrator will actually construct and sign transactions during dispute resolution, which requires direct Monero wallet operations. In the arbitrator app settings, ensure it’s pointed to http://localhost:18081 (or wherever your monerod is) and fully synced. Also, run the arbitrator on a server or machine that is online as much as possible. Traders rely on arbitrators being available especially when a dispute arises. It’s acceptable to run an arbitrator on a VPS with a desktop environment (or use X forwarding) since it needs the GUI. Some operators run the arbitrator app in a VNC/XRDP session on a server so it stays running continuously.

If you plan to have multiple arbitrators, repeat the above for each (generate keys, add to code, run app). The network can support several arbitrators, possibly each handling different trades or serving as backup.

Arbitrator Privileges and Fees

Arbitrators typically earn the trading fees or a portion of them as compensation for their service (similar to Bisq’s old model). In Haveno’s configuration, you can choose whether trade fees are “arbitrator-assigned” (i.e., go to the arbitrator) or go to a global address/fund. We will discuss how to configure this in the Trade Fees section, but keep in mind how you want to incentivize arbitrators.

Arbitrators on haveno.com’s network have special UI access as well: they can see open disputes, chat with traders, and ultimately unlock the multisig if needed. Ensure anyone acting as an arbitrator is trustworthy.

Unregistering an Arbitrator

If an arbitrator needs to step down (or you need to remove one):

  1. Resolve Ongoing Disputes: Make sure the arbitrator isn’t in the middle of any active dispute. All disputes should be closed out or assigned to another arbitrator if possible. This prevents traders from being left without a mediator.
  2. Unregister via the App: On the arbitrator’s Haveno app, navigate to the Account (or arbitrator management) section. There should be an option to unregister. In the desktop app, you can press Ctrl + U or simply find a button that says “Unregister Arbitrator” (the exact UI might vary). Confirm the action, and the arbitrator will broadcast a message that it’s leaving. Seed nodes will then update the network state, so new trades won’t use that arbitrator. (In Haveno’s current UI, unregistering might be done by the dev via network command, but the docs indicate the arbitrator can do it themselves via the Account tab.)
  3. Update Code (optional): It’s a good practice to remove the arbitrator’s pubkey from the ArbitratorManager.java list in the next release of your client, so it’s no longer advertised as available. This prevents new clients from seeing a defunct arbitrator.

After unregistering, traders will not be able to pick that arbitrator for new trades. If you had only one arbitrator and you remove it, your network will effectively pause trading that requires arbitration (since Haveno’s trade protocol typically requires an arbitrator). So ensure you have a replacement ready or plan a network shutdown.

P2P Network Configuration (Filters, Versions, Fees)

Now that the core components are running, you should configure network-wide parameters to tailor the Haveno network to your needs. Haveno allows developers (with the dev key) to set certain network filters, define a custom network version (so that your forked network doesn’t accidentally mix with others), and adjust trade fee settings.

Setting Network Filters

Network filters control what types of offers and data are allowed on your Haveno network. For example, you might want to restrict certain fiat currencies or payment methods, or set limits like minimum reputation, etc. Using your developer privileges, you can set these via the GUI:

  • Open the Haveno app (as a developer or with dev key access) and press Ctrl + F to open the Filter window. (If there’s a menu, it might be under a “Network” or “Filters” section.)
  • In the filter interface, you can specify rules. For instance, you could disable trading of a particular asset, or disallow offers above/below certain price ranges, etc. This feature is similar to Bisq’s filter system. It’s enforced by seed nodes to prevent forbidden offers from propagating.
  • When prompted, use a developer key to authorize setting the filter. This means you might have to input the developer private key or have it loaded in your app. Only the holder of the developer key can change these global filters.
  • Once set, the filter rules broadcast through the network (likely via seed nodes) and all clients will apply them (offers not meeting criteria will be rejected).

For example, you might set a filter to ban certain payment methods that you consider high-risk, or to temporarily pause trading of an asset by filter. Use this capability cautiously, as it affects all users’ ability to create or take offers.

Customizing Network Name and Version

To ensure your custom Haveno network is isolated, update the network identifiers in the code before distributing your client:

  • Data Directory Name: Change the default application name used for the data directory. In the source, find DEFAULT_APP_NAME in HavenoExecutable.java (or similar) and set it to something unique (e.g., "haveno-reto" or "haveno-com" instead of the default). This prevents collisions with any other Haveno installations and clearly separates user data for your network.
  • P2P Network Version: Update the P2P network protocol version constant so that only clients of your network communicate with each other. Locate P2P_NETWORK_VERSION in Version.java and assign a new number or identifier. This version is used in handshake between nodes; by using a unique one, you avoid any chance of cross-talk between, say, haveno.com’s network and haveno.exchange’s test network (they will reject each other’s messages due to version mismatch). It’s good to increment from the base or use an unused high number for a private network.
  • Network ID (if any): Haveno might also have a network name or ID (perhaps NETWORK_NAME environment variable as seen in the Docker config ). Ensure any configs or environment defaults reflect your network’s name (for example, if using Docker, set NETWORK_NAME=HavenoReto or similar).

After changing these, rebuild all components. Distribute this updated version to everyone. This way, your network is distinctly identified — clients will show a custom app name and only connect to peers with matching version.

Setting Trade Fees

Haveno supports configuring trade fees (the fee a user pays per trade). Fees can either go to the arbitrator or to a specified address, depending on the model:

  • Open HavenoUtils.java (or a similar config class) in the code. There will be parameters for fees, possibly a percentage or a flat amount, and an option for fee recipient .
  • Adjust the fee rate as desired. For instance, you could set a 0.2% fee per trade or a flat 0.001 XMR. Keep in mind that if fees are too high, it discourages usage; too low and arbitrators might not be incentivized.
  • Decide on fee distribution:
  • Arbitrator-assigned fees: If this mode is enabled, whichever arbitrator mediates a trade will receive the fee. This was the default in early Bisq models and likely in Haveno. It rewards arbitrators for being available. To use this, ensure the code is set to give fees to arbitrators (toggle the setting in code if present) .
  • Global fee address: Alternatively, you can set a specific address (e.g., a Monero wallet you control or a community fund) to receive all fees. This might be useful if you want to fund development or some treasury. In Haveno, this could be indicated by specifying a global payout address in the config and turning off arbitrator-specific fees .
  • Once configured, rebuild and distribute the client. The fee settings will then be in effect for all new trades.

Note: As of late 2024, the RetoSwap network had trade fees technically enabled in code but set effectively to zero or not applied in practice , meaning traders only paid Monero network fees. You can choose to start with zero fees to encourage adoption, then later enable fees via an update. If you change fees or fee distribution later, it likely requires a client update or at least a network alert to inform users.

Finally, keep all these config changes documented. If you ever update the network (new versions), increment the version constants again to force upgrades or maintain compatibility. Also, if you introduce a new filter or fee change on the fly, use the developer key to announce it or require an update (more on that below).

User Testing and Simulated Trades

Before launching publicly, perform thorough user acceptance testing on your Haveno network:

  • Local Test Instances: You can simulate trading by running multiple Haveno clients yourself. The Haveno build comes with convenient shortcuts to launch test users. For example, you can run:
    bash make user1-desktop-mainnet make user2-desktop-mainnet
    This will launch two separate Haveno GUI instances on mainnet (likely with separate data directories). They will both connect to your seed nodes. You can create an offer on one (User1) and then take it with the other (User2) to simulate a trade.
  • Test Different Scenarios: Try various flows: XMR->Fiat trades, XMR->BTC trades, dispute cases, canceling offers, etc. This will ensure that your seed nodes properly relay messages and that your arbitrator can see and resolve disputes. It’s also a good way to make sure your Monero node is functioning in concert with Haveno (check that transactions for deposits are created and that wallets sync).
  • Stagenet Testing: If you prefer not to use real XMR for tests, you can run everything on Monero stagenet or testnet. Compile/run Haveno in stagenet mode (e.g., via make user1-desktop-stagenet) and run a Monero stagenet node (make monerod-stagenet). This way, XMR transactions are just test coins. (Note: ensure your seed nodes/arbitrator are also on stagenet mode if you do this.)
  • Peer Connectivity: During testing, verify that new clients can successfully discover peers solely via your seed node list. If a client fails to find seed nodes (“No seed nodes available” error), double-check that the seed onion addresses are correct in the client build and that the seed nodes are online. Sometimes firewall or port issues can block Tor, ensure Tor ports (default 9050 for your Tor client and whatever SocksPort your seed’s Tor might be using) are not being filtered.
  • Trade Completion: Do a full happy-path trade: have one user offer to sell XMR for some currency, the other take it, then mark payment sent/received, and complete the trade. See that deposits are refunded and trade details show up in history. This tests the multisig and timing.
  • Dispute Flow: Initiate a dispute deliberately (e.g., mark not received on one side). Ensure the arbitrator sees the dispute in their arbitrator app, can chat, and can unlock funds properly. This tests your arbitrator setup and keys thoroughly. Use small amounts of XMR since this is just testing.

By running these tests, you not only gain confidence in the system, but you’ll also generate signed payment accounts and other data that you can use to test the account signing feature (next sections). It’s also an opportunity to tweak any parameters (like timeouts or trade limits) before real users join.

Finally, recruit a few beta testers if possible. Share your custom Haveno installer with trusted community members to install on their machines and attempt trades with each other. External testers might discover issues you didn’t see (such as UI glitches or connectivity from different countries). Address any problems before public launch.

Building and Distributing Client Installers

When you are satisfied with the network’s performance, you’ll need to distribute the Haveno desktop application to end users so they can start trading on your network. Haveno is cross-platform (Linux, macOS, Windows), and the build system can produce packaged installers for each.

Prepare the Build for Mainnet Release:

  • In the Gradle build scripts, ensure that you are building in mainnet mode (not using any development flags or connecting to test seeds). Check package.gradle or similar build config file to adjust any branding or network URLs. For example, update any download links or version strings that will be shown to users .
  • Set the correct seed node addresses and price node URLs in the code (which we did in previous steps). Also, double-check that auto-update URLs (if any) point to your own infrastructure (some Haveno builds have an auto-update feature where the app checks a URL for new versions).

Build the installers:

Haveno’s documentation refers to a packaging guide for building distribution files. Typically, you would run Gradle tasks to create installers. Possible tasks (to guess) might be: ./gradlew packager:assemble or similar, which would produce:

  • A .deb or AppImage for Linux
  • A signed DMG or .app for macOS
  • An EXE or MSI for Windows

Check Haveno’s repository (perhaps the desktop/package/README.md) for exact instructions on packaging for each OS. According to community discussions, pre-built binaries are often provided, but since you have a custom network, you’ll build your own. Common tools used might include jpackage or Install4j.

If the build process is complex, consider providing a ZIP or portable version as well (especially for advanced Windows users who may just want a portable .jar or folder).

Distribute the application:

  • Website or Download Server: Host the installer files on a reliable server (e.g., your haveno.com website’s downloads section). Ensure the links are easily accessible. You might have a structure like https://haveno.com/downloads/Haveno-1.0.0-Windows.exe etc.
  • Sign the binaries: If possible, code-sign the installers (particularly for Windows and macOS) to prevent OS warnings. This might require obtaining a code-signing certificate. At minimum, provide checksums (SHA256) for the files so users can verify integrity.
  • Versioning: Name the release clearly and keep track of version numbers (e.g., 1.0.0, 1.0.1, etc.). This will be important when issuing updates.

Before broad release, do one more smoke test using these actual packaged installers on each OS to ensure they run and connect to your network (for example, install the Windows .exe on a fresh Windows machine and verify it launches and connects to your seed node).

Deploying Updates and Network Alerts

Maintaining the network means you’ll eventually release updates (bug fixes, new features) and you may need to communicate with all users for important announcements. Haveno includes mechanisms for both automatic updates and network-wide alerts, which leverage the keys we set up earlier.

Software Updates (Version Control)

If you have set up an auto-update URL in the app (Haveno may allow the client to check a URL for new versions), make sure to host the update files and update manifest. For example, you might have an endpoint that the client queries to see the latest version and download URL.

When a new version is ready:

  1. Upload New Installers: Place the new binaries (for each OS) on your download server or site, typically in the same location as the previous ones (or an “updates” directory). Ensure the filenames or an update JSON file is updated to reflect the latest version available .
  2. Set Minimum Required Version: Using your developer privileges, you can force users to upgrade by setting a minimum version for trading. In the Haveno app, press Ctrl + F to open the filter (developer filter dialog), and there should be an option to specify a minimum client version. Enter the new version number as required. Once set, the seed nodes will propagate this requirement. This means any client below that version will be prevented from posting or taking offers (often they’ll see a message like “Please upgrade to continue trading”). This is a crucial step to ensure everyone moves to the version that perhaps contains important fixes.
  3. Announce the Update: It’s good practice to send a network alert about the new release. See below for using the alert key. The auto-update might notify users, but an explicit alert can highlight the importance (especially if it’s a critical security update).

Sending Network Alerts

To broadcast a message to all online users (and those who come online soon), use the alert system:

  • On a Haveno client (with the alert key loaded, typically the developer instance or a special admin console), press Ctrl + M to open the Alert Message dialog. (If there is a menu, it might be “Send Alert”.)
  • Enter the text of your alert. Keep it brief and clear. For example: “Network Update: Please upgrade Haveno to version 1.0.1 to fix a critical bug. Old versions will not be able to trade after Jan 1.” You can also use alerts for other announcements (maintenance downtime, etc.).
  • You will be prompted to sign it with the alert key. Provide the alert private key (or it may use the one in your keyring if you’ve added it). Only a message signed by the recognized alert key will be accepted by seed nodes and relayed .
  • Broadcast the alert. The seed nodes will distribute this alert to all connected clients, and it will pop up (usually as a modal or banner) in the Haveno GUI for users.

Alert messages are useful for urgent communications because they appear directly in the app. Use them sparingly and only for important matters, to avoid users tuning them out.

After sending, check on a client that the alert indeed appears. Alerts may also get logged on the console of clients as confirmation.

Tip: If you need to test alerts, you could do so on stagenet or with a dummy message. But avoid sending test alerts on mainnet as they reach real users.

With updates and alerts combined, you have control to ensure the network stays on the latest safe version and that users are informed of anything affecting their trading experience.

Signing User Payment Accounts

Haveno (like Bisq) implements a reputation system for payment accounts to enhance security in fiat trades. When a new user adds a payment account (e.g., a bank account, PayPal, Revolut, etc.), that account is initially “unsigned”, meaning it has no history of successful trades. Arbitrators can sign payment accounts after a successful trade or a resolved dispute, indicating that the account has been used legitimately in the network. A signed account is more trusted, which can allow higher trading limits or simply give other traders confidence.

As a network operator or arbitrator, you should understand how to sign accounts:

  • From Trade History (successful trade): When a trade completes successfully between two parties, the arbitrator can sign the accounts involved. In the arbitrator app, go to Portfolio > History, find the completed trade, and view its details. Copy the account witness and public key hash (the client should display this as something like <witness_hash>,<pubkey_hash> for the payment account). Then use the shortcut Ctrl + I (to open the “Insert Key” dialog) followed by Ctrl + P (to sign the payment account). You will paste the hashes and apply your arbitrator signature. This attaches your arbitrator’s approval to that account.
  • From Disputes: If a trade went through a dispute but eventually the payment was made and confirmed, you can still sign the accounts to mark them as valid. In the arbitrator app, navigate to Account (or a section where you manage accounts) and press Ctrl + I then Ctrl + S to open the signing interface for accounts involved in past disputes. You will see a list of unsigned accounts (or accounts awaiting arbitrator confirmation). Select the accounts you want to sign and confirm. This will similarly add your signature to those accounts.
  • Signing Unsigned Keys (general): There may be a case where an account wasn’t signed at trade time. Haveno provides a way to sign any account if you have its details. By pressing Ctrl + I then Ctrl + O, you can manually input an account’s public data and sign it. This is advanced and typically not needed unless recovering or manually verifying accounts.

When you sign an account, what’s happening under the hood is that your arbitrator node’s private key is used to sign the account’s unique identifier. That signature is distributed and any user’s client can verify it against your arbitrator’s public key (which is known to the network). Thus, any user can see “Account XYZ is signed by arbitrator Alice (on date D)”, meaning it has been used in a real trade mediated by Alice.

Manage arbitrator signing responsibly: Only sign accounts for which you have reasonable assurance that the owner followed through with payment. Do not sign if an account was involved in fraud or if a user failed to pay, those accounts should remain untrusted. If an account is tied to a scam, obviously do not sign it (and perhaps you’d even blacklist it outside of this system).

Over time, accounts with more signatures (or from long-time arbitrators) gain reputation, which can be used to increase trading limits or auto-complete trades faster. Haveno’s implementation is evolving, but as an arbitrator you play a key role in bootstrapping trust.

Conclusion and Additional Tips

By following this guide, you will have a fully functional Haveno exchange network, customized for haveno.com’s deployment. You set up robust backend services (seed nodes, price nodes, Monero nodes) on servers, established security through custom keys, and provided the client software for end users. Here are a few final best practices and tips to keep your Haveno network running smoothly:

  • Monitoring: Keep an eye on your VPS logs. Use journalctl for systemd services and docker-compose logs for Docker services to spot any errors (e.g., if a seed node crashes or Tor connection issues). Set up alerts if services go down.
  • Arbitrator Availability: Make sure at least one arbitrator is always online. If you have multiple arbitrators, consider scheduling coverage or running them in geographically diverse locations for resilience.
  • Periodic Updates: The crypto landscape changes, and Haveno code will improve. Plan to pull in upstream updates from Haveno’s project (or Kewbit’s fork) and merge them into your network’s codebase. Always communicate and roll out these updates as described (with version bumps and alerts).
  • Security: Protect your private keys (developer, alert, arbitrator) offline. If an attacker gains the dev key, they could set harmful filters; if they gain an arbitrator key, they could steal trade funds. Consider using hardware encryption or storing keys on an offline machine, coming online only to sign necessary messages.
  • Network Growth: Encourage users to run their own Monero nodes (for privacy) and perhaps even become peer nodes (every user is effectively a peer node). The more distributed, the better for decentralization. However, seed nodes and arbitrators will likely remain relatively centralized (operated by you or trusted partners) in this early phase, which is okay, as long as they are secure and reliable .
  • Support: Provide a way for users to get help (perhaps a Telegram/Matrix channel or an email support). New users might need guidance installing or using Haveno, and trust in the network will grow if they know the operators are responsive.

With creating a new work as long as you fork any of the main repositories you will be added to the haveno networks page on the website, when you're up and running, you are contributing to the Monero ecosystem by offering a private, peer-to-peer trading platform. Happy trading, and stay safe!


MongoDB Logo MongoDB