DEV Community

Cover image for Running ROS 1 GUI Applications on macOS with Docker and XQuartz
Haruki Niwa
Haruki Niwa

Posted on Edited on AI-assisted

Running ROS 1 GUI Applications on macOS with Docker and XQuartz

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
Enter fullscreen mode Exit fullscreen mode

Install XQuartz

Install XQuartz:

brew install --cask xquartz
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}'
Enter fullscreen mode Exit fullscreen mode

This retrieves the IPv4 address of the en0 network interface.

For example:

192.168.1.10
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Start the ROS Noetic container:

docker run -it \
  -e DISPLAY="192.168.1.10:0" \
  nha6ki/ros-gui:noetic
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Find the container running nha6ki/ros-gui:noetic, then open a shell inside it:

docker exec -it <container_id> bash
Enter fullscreen mode Exit fullscreen mode

Replace <container_id> with the container ID shown by docker ps.

Start turtlesim:

rosrun turtlesim turtlesim_node
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Launch the keyboard controller:

rosrun turtlesim turtle_teleop_key
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Run:

rosrun rqt_graph rqt_graph
Enter fullscreen mode Exit fullscreen mode

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:

TurtleSim, keyboard teleoperation, and rqt_graph 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
Enter fullscreen mode Exit fullscreen mode

another process may already be listening on port 6000.

Identify it with:

lsof -nP -iTCP:6000 -sTCP:LISTEN
Enter fullscreen mode Exit fullscreen mode

Once you have confirmed which process is using the port, terminate it gracefully:

kill -TERM <PID>
Enter fullscreen mode Exit fullscreen mode

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:

  1. XQuartz is running.
  2. Allow connections from network clients is enabled.
  3. The host IP address is correct.
  4. The container's DISPLAY variable points to the host on display :0.
  5. socat is running with a valid XQuartz socket path in its $DISPLAY variable.
  6. TCP port 6000 is reachable from the container.

You can inspect the container's display setting with:

echo "$DISPLAY"
Enter fullscreen mode Exit fullscreen mode

For the example above, it should be:

192.168.1.10:0
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)