A one-command installer for the apt-based ROS 2 path

@solonovamax
Thanks for the pushback — these are the right questions to ask.

Two things on this.

First, I agree it’s an anti-pattern as a general rule. But look at what the current instructions already do: query api.github.com for a version string, download a .deb from GitHub Releases, and sudo dpkg -i it. That .deb is not verified by apt — it is the thing that installs the key. So the trust boundary today is “whatever HTTPS gives you from a project-controlled URL, run as root.” A script served from the same kind of URL doesn’t widen that. The only difference is whether the thing you fetch is a package or a script you can read before running.

Second, it matters what the script would actually do. Every ROS package would still come through apt, signed and verified. The script only automates the one step that is already outside apt today — fetching the .deb that configures the repository. Nothing moves out of the package manager.

The part of the anti-pattern argument I do agree with is the habit: teaching newcomers to pipe URLs into their shell as if that’s the normal way to install things. I’d want this presented not as “the” way to install ROS, but as the reference implementation of the documented steps, kept in sync with them.

For someone who has done it a few times on their own machine, sure, it’s not a big deal.

It’s a different story for beginners and for people maintaining Docker images or CI.

For beginners, the current procedure includes spells like $(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}}). These are the people who copy a command from a migration guide, miss one sudo, and end up with a broken system.

For Docker and CI it’s worse. Because there is no guarantee the procedure stays the same, everyone writes their own script that automates the same steps, and that script gets copied into every new CI config from then on. When the procedure changes, I doubt finding and updating all of those takes five minutes.

That’s a fair concern, but it’s a matter of script quality, not a reason to have no script. A script that stops on the first error and says which step failed — something like could not fetch ros2-apt-source release: <url> — is easier to debug than a raw apt error halfway through a manual sequence.

Last year’s migration thread has a concrete example of the manual version. The URL in the docs was pinned to 1.0.0, the package moved to 1.1.0 the next day, and two people following the official instructions hit a 404 and had to ask what was wrong (here and here). Following the steps by hand didn’t tell them which step was broken.

You may have seen some of these already, but counting only changes to the apt setup procedure itself:

  • 2019: key rotation after a security incident
  • 2021-04: docs moved from apt-key add to signed-by= keyrings
  • 2021-05-29: key expired; 42 replies, official Docker images and ros-tooling/setup-ros broken over a holiday weekend
  • 2025-06-01: key expired again, ros-apt-source introduced; the PMC announcement itself opens with “we are again upon the brink”

Both incident threads are full of people fixing their own copies: CI pipelines, GitHub Actions, Ansible roles, and the broken-system case above. Yes, my own CI was among the things that went red on June 1st.

I may be repeating myself, but that single point of failure already exists. packages.ros.org, the signing key, and the ros-apt-source package are all managed by the Infrastructure PMC, and when any of them changes, every Dockerfile and CI pipeline in the community breaks at the same time. 2021 and 2025 showed exactly that. The only question is whether the fix then lands upstream once, or in every copy separately.

That said, I don’t think curl | sh is the ideal shape either. What I want is a single, maintained entry point that the docs, Dockerfiles and CI can all point at — one where it’s clear who owns the procedure. Some shapes that would do that:

  • A stable, versionless URL for the ros2-apt-source .deb. @peci1 has already asked for this. That alone removes the api.github.com dependency and the version-pinned 404s, and gets the manual path down to curl -LO <url> && sudo dpkg -i followed by apt install.
  • Getting ros2-apt-source into the Ubuntu archive itself, so the whole thing becomes sudo apt install ros2-apt-source. The cleanest answer, and the most work.
  • A script hosted under the ros2 or ros-infrastructure org, documented as “download, read, run” and never as a one-liner. Same maintenance benefit, without teaching the habit.

Where I agree with you: a script that isn’t kept in sync with the docs would be worse than nothing. That’s exactly why I’m asking in this thread whether the PMC would be willing to own something like this.

5 Likes