Automating OpenOCD Distribution with a Private Gitea Package Registry

Turn your OpenOCD updates from a manual chore into a one-click process. Learn how to set up a private Gitea Package Registry, upload .deb files, and install them effortlessly on any Debian-based machine. Automation made simple.

Andre Leppik

In previous parts, we cross-compiled and built a Debian package for OpenOCD. We then manually copied these files to our target machines. The problem with that setup is the manual labor, every time we update the package or want to use it on a new machine, we have to find the .deb file and transfer it.

In this part, we will solve this by uploading our built packages to a private Gitea Package Registry. This transforms our workflow into a complete DevOps setup, allowing us to manage versions and install packages via apt.

Before we dive into the details, let’s look at the high-level overview of our deployment pipeline:

Architecture diagram showing a DevOps cycle for OpenOCD: Builder machine compiles .deb packages, uploads to Gitea Registry via cURL, and target devices install via apt.

As shown in the overview above, Gitea acts as the central hub for our packages. Before we can push our first .deb file, we must configure the Gitea environment to support the Debian repository format.

Setting up Gitea for Package Management

Note

This guide expects you to have access to Gitea, either setup yourself or using external ones with packages support.

First of all, to use Gitea as a Debian repository, we must ensure the package registry feature is enabled. This involves tweaking the app.ini configuration file. If you’re running Gitea in Docker, you’ll find this file in a volume:

sudo nano /var/lib/docker/volumes/gitea_gitea_data/_data/gitea/conf/app.ini

For a direct Linux install, check /etc/gitea/conf/app.ini. Open the this file and add or update the [package] section:

[package]
ENABLED = true
STORAGE_TYPE = local
STORAGE_PATH = packages
Note

Ensure the STORAGE_PATH is a valid directory where Gitea has write permissions. Save the file and restart Gitea for the changes to take effect.

Creating an Organization for Packages

Instead of tossing packages into your personal account, let’s create a dedicated organization. This keeps things clean and makes it easy to share access with teammates or automated scripts.

Start by creating a new organization from "Create... > New Organization". Give it a name (e.g., Vault) and set it to public. Once it is created you can add a cool display name, description or even an avatar.

Overview of newly created Gitea organization

Creating a Builder User and Access Token

Automation needs a user account to do its thing. Let’s create a builder user (I named mine machine) and add it to your new organization.

Next, we’ll generate an access token for this user. Think of it as a restricted key, it lets the builder authenticate with Gitea, but only for the exact tasks we allow. Unlike a password, which grants full access to the account, this token is locked down to just package uploads. If it ever leaks, the risk is minimal: no account takeover, no unauthorized changes, just a limited window for one job. It’s security with precision.

Navigate to "User Settings > Applications" and generate a new access token, add Read and Write permissions to packages.

Gitea User Settings interface showing the Applications tab where a new personal access token is being generated with specific read and write permissions for the Package Registry.
Important

Keep this token safe. It’s the key to your automated workflow.

Publishing Debian Packages

Now for the fun part, uploading teb .deb file. Log in to the cross-compilation machine and let’s get started. In this example we will build and publish the .deb package of OpenOCD for the ARM architecture. Refer to the Cross-Compiling and the Debian Package post for more info.

  • Build your package if you haven’t already. For ARM architecture, your package structure might be in /arm64/pxg-openocd. Run:
dpkg-deb --root-owner-group --build arm64/pxg-openocd
  • Upload it to Gitea using curl. The URL structure for an APT repository looks like this [base_url]/[distribution]/[component], where distribution refers to the OS release (e.g., bookworm for Debian 12) and component categorizes software by license and dependencies. We’ll use main for simplicity.
curl --user USER:TOKEN -X PUT --upload arm64/pxg-openocd.deb https://gitea.local/api/packages/vault/debian/pool/bookworm/main/
Note

Replace TOKEN with your access token and USER with your builder username.

  • Check your work. Your package should now appear under the Packages tab in your Gitea organization.
The Gitea Packages interface displaying a published Debian package for pxg-openocd.

Installing OpenOCD on Our Raspberry Pi

Now that our package is in the registry, let’s install it on a Raspberry Pi. Before we can do that, we need to tell apt where to find our new registry.

  • Add the Gitea Repository Key:
sudo curl https://gitea.local/api/packages/Vault/debian/repository.key -o /etc/apt/keyrings/gitea-Vault.asc
  • Add the source to your list:
echo "deb [signed-by=/etc/apt/keyrings/gitea-Vault.asc] https://gitea.local/api/packages/Vault/debian bookworm main" | sudo tee -a /etc/apt/sources.list.d/gitea.list
  • Update the system for the source list update to take effect:
sudo apt update
  • Now we are ready to install pxg-openocd:
$ sudo apt install pxg-openocd
Get:1 https://gitea.local/api/packages/Vault/debian bookworm/main amd64 pxg-openocd amd64 0.12.0+dev-g66ea46184 [1,628 kB]
Fetched 1,628 kB in 0s (5,208 kB/s)   
Selecting previously unselected package pxg-openocd.
(Reading database ... 243552 files and directories currently installed.)
Preparing to unpack .../pxg-openocd_0.12.0+dev-g66ea46184_amd64.deb ...
Unpacking pxg-openocd (0.12.0+dev-g66ea46184) ...
Setting up pxg-openocd (0.12.0+dev-g66ea46184) ...
  • Test it out:
$ openocd -v
Open On-Chip Debugger 0.12.0+dev-02117-g66ea46184 (2026-01-02-10:37)

Managing the Package

When we release a new version of OpenOCD, we just update the version number in the control file, rebuild, and upload. On our Raspberry Pi, run:

sudo apt update
sudo apt --only-upgrade install pxg-openocd

To remove the package:

sudo apt remove pxg-openocd

To remove everything:

sudo apt purge pxg-openocd

What´s Next?

We have successfully moved from manual file transfers to a professional, centralized distribution system. By hosting our own Gitea Package Registry, we can now manage OpenOCD updates across an entire fleet of devices with a simple apt update.

However, traditional installations have their limits. If you build a tool for Debian Bookworm, it will likely break on Bullseye or Trixie due to library mismatches. Furthermore, installing everything directly onto your OS risks library conflicts and "configuration drift" often requiring a full OS re-image just to start fresh.

In the next post, Running OpenOCD in Docker: A "Tools as Code" Approach to Embedded DevOps, we solve this by moving our entire embedded stack into Docker.

Need help with embedded systems development?

Whether you're building something new, fixing stability issues, or automating what slows your team down — we can help.