{"id":20492354,"url":"https://github.com/husarnet/husarnet-ros2router","last_synced_at":"2025-08-24T22:20:49.574Z","repository":{"id":113651502,"uuid":"467182071","full_name":"husarnet/husarnet-ros2router","owner":"husarnet","description":"Husarnet optimized DDS Router Docker image for connecting ROS 2 nodes over the Internet.","archived":false,"fork":false,"pushed_at":"2024-03-28T15:21:35.000Z","size":144,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-03-28T16:40:56.301Z","etag":null,"topics":["dds","docker","ros2"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/husarnet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-03-07T16:55:19.000Z","updated_at":"2024-03-19T18:39:29.000Z","dependencies_parsed_at":"2024-01-28T13:13:09.446Z","dependency_job_id":"0b9dc61d-b3f3-47fe-9f9c-57b7b0c2e100","html_url":"https://github.com/husarnet/husarnet-ros2router","commit_stats":null,"previous_names":["husarnet/husarnet-ros2router"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husarnet%2Fhusarnet-ros2router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husarnet%2Fhusarnet-ros2router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husarnet%2Fhusarnet-ros2router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/husarnet%2Fhusarnet-ros2router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/husarnet","download_url":"https://codeload.github.com/husarnet/husarnet-ros2router/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224819317,"owners_count":17375254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dds","docker","ros2"],"created_at":"2024-11-15T17:28:41.498Z","updated_at":"2025-07-07T04:08:32.981Z","avatar_url":"https://github.com/husarnet.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# husarnet-ros2router\n\n[![Build a Docker Image](https://github.com/husarnet/husarnet-ros2router/actions/workflows/build_push.yaml/badge.svg)](https://github.com/husarnet/husarnet-ros2router/actions/workflows/build_push.yaml)\n\nThe `husarnet/ros2router` Docker image is designed to effortlessly bridge local ROS 2 nodes, even those with standard DDS settings, to nodes on different machines across various networks. It runs seamlessly with the Husarnet VPN, ensuring that neither distance nor network differences become obstacles in your ROS 2 projects. \n\nCompatible with both natively-executed ROS 2 nodes and those operating within Docker.\n\nBased on [DDS Router](https://github.com/eProsima/DDS-Router) project by eProsima.\n\n## How it works?\n\n1. **Run ROS 2 Nodes on Two Machines:**\n\n   Whether they're in the same LAN or different ones, execute the following on your first machine:\n\n   ```bash\n   ROS_LOCALHOST_ONLY=1\n   ros2 run demo_nodes_cpp listener \n   ```\n   \n   And on your second machine:\n\n   ```bash\n   ROS_LOCALHOST_ONLY=1\n   ros2 run demo_nodes_cpp talker\n   ```\n\n2. **Husarnet Account Setup**\n\n- Register for a free account on [app.husarnet.com](https://app.husarnet.com/).\n- Establish a new Husarnet network in the Online Dashboard.\n- Click the **[Add element]** button and copy the code under the **Join Code** tab.\n\n3. **Connect Devices to Husarnet:**\n\n   If you're on Ubuntu, follow these steps:\n \n   - Install Husarnet:\n\n   ```bash\n   curl https://install.husarnet.com/install.sh | sudo bash\n   ```\n\n   - Connect to the Husarnet network:\n\n   ```bash\n   sudo husarnet join \u003cpaste-join-code-here\u003e\n   ```\n\n4. **Start the DDS Router Docker Image:**\n\n   Launch the following command on each host:\n\n   ```bash\n   docker run \\\n   --detach \\\n   --restart=unless-stopped \\\n   --network host \\\n   husarnet/ros2router:1.4.0\n   ```\n\n5. **Verify Connection:**\n\n   Open the terminal for the `listener`. You should start seeing incoming messages.\n\nThis guide provides a straightforward setup. Dive deeper and explore additional options and examples in the sections below.\n\n## General Example\n\nThe all-in-one example, that should be fine in most cases (both with ROS 2 nodes running on host and in Docker containers) is in the `demo/auto/general` directory.\n\n```yaml\nservices:\n  ros2router:\n    image: husarnet/ros2router:1.8.0\n    network_mode: host\n    ipc: shareable\n    volumes:\n      - ./filter.yaml:/filter.yaml\n    environment:\n      - DISCOVERY_SERVER_ID=2\n      - DISCOVERY_SERVER_LISTENING_PORT=8888\n      - PARTICIPANTS=husarnet,shm\n      - |\n        CONFIG_BASE=\n          version: v5.0\n          specs:\n            discovery-trigger: writer\n          participants:\n            - name: LocalParticipant\n              kind: local\n              domain: 0\n              transport: builtin\n      - ROS_DOMAIN_ID=123\n\n  talker:\n    image: husarion/ros2-demo-nodes:humble\n    ipc: service:ros2router\n    network_mode: service:ros2router\n    volumes:\n      - ./shm-only.xml:/shm-only.xml\n    environment:\n      - FASTRTPS_DEFAULT_PROFILES_FILE=/shm-only.xml\n      - ROS_DOMAIN_ID=123\n    command: ros2 run demo_nodes_cpp talker\n\n# On the same host to connect to LocalParticipant, just execute:\n# export ROS_LOCAHOST_ONLY=1\n# ros2 run demo_nodes_cpp talker\n\n# On the other host, to listen to /chatter topic:\n# \n# Option 1: ROS 2 Iron (assuming \"laptop\" is the husarnet hostname of the host running ros2router):\n# export ROS_DISCOVERY_SERVER=;;laptop:8888\n# ros2 run demo_nodes_cpp listener\n# \n# Option 2: ROS 2 Humble:\n# Modify superclient.xml to point to the host with ros2router (line 31)\n# export FASTRTPS_DEFAULT_PROFILES_FILE=${PWD}/superclient.xml\n# ros2 run demo_nodes_cpp listener\n```\n\n## Environment Variables\n\n### Husarnet VPN related\n\n| env | default value | description |\n| - | - | - |\n| `PARTICIPANTS` | `husarnet,shm,lo` | The coma separated list of paticipants in the ROS 2 Router configuration. Possible values are: `husarnet`, `shm`, `lo`, `lan`, `if-\u003cif-name-optional-wildcard\u003e`. If unset of empty you need to use a custom DDS router configuration file |\n| `ROS_DISCOVERY_SERVER` | | If set the `HusarnetParticipant` will work in the [Disocovery Server setup](https://eprosima-dds-router.readthedocs.io/en/latest/rst/user_manual/participants/local_discovery_server.html#user-manual-participants-local-discovery-server). Set it to one of the following formats: `\u003chusarnet-ipv6-addr\u003e:\u003cdiscovery-server-port\u003e` or `\u003chusarnet-hostname\u003e:\u003cdiscovery-server-port\u003e` to connect as the Client to the device acting as a Discovery Server. To specify multiple addresses, use semicolons as separators. The server's ID is determined by its position in the list (starting from `0`). If there's an empty space between semicolons, it indicates that the respective ID is available. Eg. `ROS_DISCOVERY_SERVER=\";;abc:123;;;def:456\"` means that the ID of `abc:123` is `2` and ID of `def` is `5`. If one of the addresses is the same as the hosts Husarnet IPv6 address, then the Discovery Server - Server config is launch on the host. |\n| `DISCOVERY_SERVER_ID` | `-1` | The ID of the local Discovery Server. If the server config is launched (one of the addresses specified in `ROS_DISCOVERY_SERVER` is the same as host's Husarnet address), the value of `DISCOVERY_SERVER_ID` env is ignored and the ID from `ROS_DISCOVERY_SERVER` env is used. If the value is outside of the `0-255` range, then the random value (from `10-255` range) is used instead |\n| `ROS_DOMAIN_ID` | | If set it changes the default `domain: 0` for all participants with `kind: local` (basically all instead of `HusarnetParticipant` working in the Discovery Server config)  |\n| `EXIT_IF_HOST_TABLE_CHANGED` | `FALSE` | Valid only if `ROS_DISCOVERY_SERVER` envs is unset and thus starting the **Initial Peers** config. This env is useful in connection with `restart: always` Docker policy - it restarts the DDS Router with a new Initial Peers list applied (the Initial Peers list is not updated by the DDS Router in runtime)  |\n| `USER` | `root` | Allowing you to run the DDS Router as a different user (useful to enable SHM communication between host and Docker container) |\n| `HUSARNET_API_HOST` | `127.0.0.1` | The IPv4 address where Husarnet Daemon is running (If using a different address than `127.0.0.1` remember also to run the Husarnet Daemon with a `HUSARNET_DAEMON_API_INTERFACE` env setup ) |\n| `CONFIG_BASE` | | providing some optional, extra config to the ROS 2 Router. Default config base is [here](./config.base.yaml). Find available config options in [the DDS Router documentation](https://eprosima-dds-router.readthedocs.io/en/latest/rst/user_manual/configuration.html#specs-configuration) |\n| `FILTER` |  |  It's alternative to providing `/filter.yaml` as a volume |\n\n## Topic Filtering\n\nThe Docker image for the Husarnet ROS 2 Router can accept a portion of the typical ROS 2 Router configuration `*.yaml` file. This segment only includes the `allowlist`, `blocklist`, and `builtin-topics` sections. The provided configuration is then integrated with the automatically generated config file content.\n\nHere's a sample of the `filter.yaml` file:\n\nExample of the `filter.yaml` file:\n\n```yaml\nallowlist:\n  - name: \"rt/camera/color/image_raw/theora\"\n    type: \"theora_image_transport::msg::dds_::Packet_\"\n  - name: \"rt/camera/color/image_raw/compressed\"\n    type: \"sensor_msgs::msg::dds_::CompressedImage_\"\n  - name: \"rt/cmd_vel\"\n    type: \"geometry_msgs::msg::dds_::Twist_\"\nblocklist: []\nbuiltin-topics: []\n```\n\nNote that each ROS 2 topic name is preceded with `rX/` prefix (more [here](https://design.ros2.org/articles/topic_and_service_names.html)):\n\n| **ROS Subsystem** | **Prefix** |\n| - | - |\n| ROS Topics | `rt` |\n| ROS Service Request | `rq` |\n| ROS Service Response | `rr` |\n| ROS Service | `rs` |\n| ROS Parameter | `rp` |\n| ROS Action | `ra` |\n \nThe repository includes the `create_filter.sh` script, which facilitates the automated creation of [DDS Router filter rules](https://eprosima-dds-router.readthedocs.io/en/latest/rst/user_manual/configuration.html#id1):\n\n```bash\ncurl -s https://raw.githubusercontent.com/husarnet/husarnet-ros2router/main/create_filter.sh \u003e create_filter.sh\nchmod +x create_filter.sh\n./create_filter.sh /chatter /cmd_vel \u003e filter.yaml\n```\n\nModify the `filter.yaml` file if needed and assign it as a bind mount volume:\n\n```bash\ndocker run \\\n--detach \\\n--restart=unless-stopped \\\n--network host \\\n-e ROS_DOMAIN_ID \\\n-v $(pwd)/filter.yaml:/filter.yaml \\\nhusarnet/ros2router:1.2.0\n```\n\n## Quick Start\n\n### Option 1: Initial Peers config\n\n1. Connect both hosts to the same Husarnet network (eg. named `host_a` and `host_b`).\n\n2. On both `host_a` and `host_b` execute:\n\n```bash\ndocker run \\\n--detach \\\n--restart=unless-stopped \\\n--network host \\\n-e ROS_DOMAIN_ID \\\nhusarnet/ros2router:1.2.0\n```\n\n3. Start a chatter demo:\n\n- on the `host_a`:\n\n```bash\nexport ROS_LOCALHOST_ONLY=1 # is required to connect with a LocalUdpParticipant\nros2 run demo_nodes_cpp talker\n```\n\n- on the `host_b`:\n\n```bash\nexport ROS_LOCALHOST_ONLY=1 # is required to connect with a LocalUdpParticipant\nros2 run demo_nodes_cpp listener\n```\n\n### Option 2: Discovery Server config\n\n1. Connect both hosts to the same Husarnet network (eg. named `host_a` and `host_b`).\n\n2. Execute on `host_a`:\n\n```bash\ndocker run \\\n--detach \\\n--restart=unless-stopped \\\n--network host \\\n-e DISCOVERY_SERVER_PORT=\"11888\" \\\nhusarnet/ros2router:1.2.0\n```\n\n3. Execute on `host_b`:\n\n```bash\ndocker run \\\n--detach \\\n--restart=unless-stopped \\\n--network host \\\n-e ROS_DISCOVERY_SERVER=\"host_a:11888\" \\\nhusarnet/ros2router:1.2.0\n```\n\n4. Start a chatter demo:\n\n- on the `host_a`:\n\n```bash\nexport ROS_LOCALHOST_ONLY=1 # is required to connect with a LocalUdpParticipant\nros2 run demo_nodes_cpp talker\n```\n\n- on the `host_b`:\n\n```bash\nexport ROS_LOCALHOST_ONLY=1 # is required to connect with a LocalUdpParticipant\nros2 run demo_nodes_cpp listener\n```\n\n### Option 3: custom config\n\n1. Connect both hosts to the same Husarnet network (eg. named `host_a` and `host_b`).\n\n2. Create a DDS Router config file on the `host_a`:\n\n```bash\nuser@host_a:~$ vim config.yaml\n```\n\nwith the following content:\n\n\n```yaml\nversion: v3.0\n\nallowlist:\n  - name: \"rt/chatter\"\n    type: \"std_msgs::msg::dds_::String_\"\n\nparticipants:\n\n  - name: SimpleParticipant\n    kind: local\n    domain: 0\n\n  - name: ServerDSParticipant\n    kind: local-discovery-server\n    discovery-server-guid:\n      id: 200\n    listening-addresses:\n      - domain: host_a\n        port: 11811\n        transport: udp\n```\n\n3. Create a DDS Router config file on the `host_b`:\n\n```bash\nuser@host_b:~$ vim config.yaml\n```\n\nwith the following content:\n\n\n```yaml\nversion: v3.0\n\nallowlist:\n  - name: \"rt/chatter\"\n    type: \"std_msgs::msg::dds_::String_\"\n\nparticipants:\n\n  - name: SimpleParticipant\n    kind: local\n    domain: 0\n\n  - name: ClientDSParticipant\n    kind: local-discovery-server\n    discovery-server-guid:\n      id: 202\n    connection-addresses:\n      - discovery-server-guid:\n          id: 200\n        addresses:\n          - domain: host_a \n            port: 11811\n            transport: udp\n```\n\n4. On both `host_a` and `host_b` execute (in the same folder as `config.yaml` file):\n\n```bash\ndocker run --name ros2router \\\n  --restart=unless-stopped \\\n  --network host \\\n  --ipc host \\\n  --user $(id -u):$(id -g) \\\n  -v $(pwd)/config.yaml:/config.yaml \\\n  -v /etc/group:/etc/group:ro \\\n  -v /etc/passwd:/etc/passwd:ro \\\n  -v /etc/shadow:/etc/shadow:ro \\\n  -e AUTO_CONFIG=FALSE \\\n  husarnet/ros2router:1.2.0 bash -c \"ddsrouter -c /config.yaml -r 10\"\n```\n\n5. Start a chatter demo:\n\n- on the `host_a`:\n\n```bash\nexport ROS_DOMAIN_ID=0\nros2 run demo_nodes_cpp talker\n```\n\n- on the `host_b`:\n\n```bash\nexport ROS_DOMAIN_ID=0\nros2 run demo_nodes_cpp listener\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhusarnet%2Fhusarnet-ros2router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhusarnet%2Fhusarnet-ros2router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhusarnet%2Fhusarnet-ros2router/lists"}