Getting ROS 1 GUI applications to run on macOS is not as straightforward as running them on Ubuntu. Docker can provide the Linux environment, but applications such as turtlesim and rqt_graph still need a way to display their windows on the Mac.
I used Docker, XQuartz, and socat to make this work. This article documents the setup I tested in October 2020, including the commands I used and the results.
With this configuration, I was able to run:
-
turtlesim— a simple ROS simulator -
turtle_teleop_key— keyboard control for the simulated turtle -
rqt_graph— visualization of ROS nodes and topics
Compatibility note: This is a historical ROS 1 setup, not a currently validated installation guide. ROS Melodic reached end of life in June 2023, and ROS Noetic reached end of life on May 31, 2025. I have not retested these instructions with recent versions of macOS, Docker Desktop, or XQuartz. For new projects, use a supported ROS 2 distribution.
1. Prerequisites
The setup uses the following software:
| Software | Purpose |
|---|---|
| Docker Desktop | Run ROS in an Ubuntu-based container |
| XQuartz | Display X11 applications on macOS |
| socat | Forward TCP connections to the XQuartz Unix-domain socket |
| Homebrew | Install the required utilities |
Docker Desktop and Homebrew should already be installed.
ROS Docker images
I built Docker images for ROS Noetic and Melodic and published them on Docker Hub.
| ROS distribution | Base image | Docker image |
|---|---|---|
| Noetic | Ubuntu 20.04 | nha6ki/ros-gui:noetic |
| Melodic | Ubuntu 18.04 | nha6ki/ros-gui:melodic |
The following demonstration uses ROS Noetic.
The availability and compatibility of these older Docker images have not been revalidated.
2. Install and Configure XQuartz
Install socat
Install socat with Homebrew:
brew install socat Install XQuartz
Install XQuartz:
brew install --cask xquartz The command used in the original environment was brew cask install xquartz. The syntax above reflects newer Homebrew versions.
Enable network connections
Launch XQuartz:
open -a XQuartz Open XQuartz → Preferences → Security and enable:
Allow connections from network clients
Restart XQuartz after changing this setting.
This option is required for the TCP-based forwarding approach used here.
Security note: The following configuration exposes an unencrypted X11 service through TCP port 6000. Use it only in an isolated, trusted environment. Do not expose the listener to untrusted networks.
Optional: Three-button mouse emulation
Under XQuartz → Preferences → Input, enable Emulate three-button mouse if needed.
In my setup, this allowed me to use Option + Click to paste text in X11 applications.
3. Configure X11 Forwarding
Open the first terminal on macOS.
The goal is to forward connections from the Docker container to the XQuartz display server.
Terminal 1: Find the host IP address
Run:
ifconfig en0 | grep inet | awk '$1=="inet" {print $2}' This retrieves the IPv4 address of the en0 network interface.
For example:
192.168.1.10 The command assumes that en0 is the interface being used. Replace it with the appropriate interface if your Mac uses a different one.
Use the resulting address in the following commands.
Allow access to XQuartz
Add the host address to the X11 access control list:
xhost +192.168.1.10 Replace 192.168.1.10 with your actual IP address.
This grants access to the specified host. Avoid using xhost + without a hostname or address, as that disables X11 access control.
Start socat
Run:
socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:"$DISPLAY" This starts a TCP listener on port 6000 and forwards incoming connections to the Unix-domain socket identified by $DISPLAY.
The relevant options are:
-
TCP-LISTEN:6000— listen for incoming TCP connections on port 6000 -
reuseaddr— allow reuse of the local socket address -
fork— handle connections using child processes -
UNIX-CLIENT:"$DISPLAY"— connect to the XQuartz Unix-domain socket
Before starting socat, check the display variable:
echo "$DISPLAY" It must contain a valid path to the XQuartz display socket. If it is empty or points elsewhere, run the forwarding command from a shell with the correct XQuartz environment.
Leave this terminal open while using ROS.
4. Start ROS in Docker
Terminal 2: Launch the container
Open a second terminal.
Make sure XQuartz is running:
open -a XQuartz Start the ROS Noetic container:
docker run -it \ -e DISPLAY="192.168.1.10:0" \ nha6ki/ros-gui:noetic Replace 192.168.1.10 with your Mac's IP address.
The DISPLAY environment variable tells GUI applications inside the container where to send their X11 output.
Once inside the container, start the ROS master:
roscore Keep this terminal open. Other ROS nodes will connect to the master running here.
5. Run turtlesim
Terminal 3: Start the simulator
Open a third terminal on macOS.
List the running containers:
docker ps Find the container running nha6ki/ros-gui:noetic, then open a shell inside it:
docker exec -it <container_id> bash Replace <container_id> with the container ID shown by docker ps.
Start turtlesim:
rosrun turtlesim turtlesim_node If X11 forwarding is working, the TurtleSim window should appear on the Mac.
Terminal 4: Control the turtle
Open a fourth terminal and enter the same container:
docker exec -it <container_id> bash Launch the keyboard controller:
rosrun turtlesim turtle_teleop_key Use the arrow keys while this terminal is focused to move the turtle.
The controller publishes velocity commands on /turtle1/cmd_vel, and the turtlesim node receives them.
6. Visualize ROS Nodes with rqt_graph
Terminal 5: Launch rqt_graph
Open a fifth terminal and enter the container:
docker exec -it <container_id> bash Run:
rosrun rqt_graph rqt_graph The rqt_graph window should appear on macOS.
In this demonstration, it shows the connection between:
-
/teleop_turtle— the keyboard controller -
/turtlesim— the simulator -
/turtle1/cmd_vel— the velocity command topic
This makes it easy to see how the two ROS nodes communicate.
7. Result
Here is a screenshot of the setup running on macOS:
The screenshot shows the turtlesim window, the keyboard controller running in a terminal, and rqt_graph visualizing the communication between the nodes.
Both turtlesim and rqt_graph worked through XQuartz while ROS was running inside Docker.
I also tried RViz and Gazebo, but could not get them running with this configuration. Unlike the lightweight applications demonstrated here, they have additional graphics requirements.
8. Troubleshooting
socat: Address already in use
If socat reports:
Address already in use another process may already be listening on port 6000.
Identify it with:
lsof -nP -iTCP:6000 -sTCP:LISTEN Once you have confirmed which process is using the port, terminate it gracefully:
kill -TERM <PID> Replace <PID> with the actual process ID.
If the process cannot be stopped normally, kill -9 is a last resort. Avoid using it without first identifying the process.
Then restart socat.
XQuartz windows do not appear
If a ROS GUI application starts but no window appears, check the following:
- XQuartz is running.
- Allow connections from network clients is enabled.
- The host IP address is correct.
- The container's
DISPLAYvariable points to the host on display:0. -
socatis running with a valid XQuartz socket path in its$DISPLAYvariable. - TCP port 6000 is reachable from the container.
You can inspect the container's display setting with:
echo "$DISPLAY" For the example above, it should be:
192.168.1.10:0 Note that current Docker Desktop networking may behave differently from the environment used for this demonstration.
Homebrew installation problems
If Homebrew reports a repository update problem while installing XQuartz, inspect the error before attempting recovery.
One recovery command used with older Homebrew installations was:
brew update-reset && brew update Caution: brew update-reset can discard local changes in Homebrew-managed Git repositories. It should not be used as a general installation fix.
9. Clean Up
When finished, stop the ROS processes and exit the container.
Stop socat with Ctrl + C in the first terminal.
Remove the temporary X11 access permission:
xhost -192.168.1.10 Replace the IP address with the one you added earlier.
Finally, disable Allow connections from network clients in XQuartz if it is no longer required.
Conclusion
Using Docker, XQuartz, and socat, I was able to run turtlesim and rqt_graph on macOS while keeping ROS Noetic inside an Ubuntu-based container.
The setup worked for these lightweight GUI tools, although I could not run RViz or Gazebo.
This was a useful way to experiment with ROS 1 on a Mac in 2020. Today, the ROS 1 distributions used here are no longer supported, and the configuration has not been tested against modern macOS and Docker Desktop releases.
References
AI disclosure: This article documents my own technical setup and results. An LLM was used to help draft, organize, and edit the English text. I remain responsible for its technical accuracy.
