Aspic

A signed package repository. Add it once with the snippet for your system, then install and update everything on it through your normal package manager.

One repository, not one per project. Adding aspic gives you every project published here, and a new one needs no second sources entry — just install its name. Each project has its own page explaining what it is and how to run it; this page is only about getting the repository in place.
Nothing is signed on this host. Packages and indexes are signed on a workstation and pushed here as static files, so a compromise of this box can serve you something stale or missing but cannot forge a package your package manager will accept. That is what the key in every snippet below is for.

Breeze Core

breeze-core — self-hosted, LAN-first control for Midea air conditioners: REST API, web panel, schedules and temperature curves.

Breeze

.apk — the Android app for Breeze Core: one air conditioner per screen, widgets and schedules. Android 7.0+.

Debian family

Debian · Ubuntu · Mint · Pop!_OS · Raspberry Pi OS · Devuan — apt
# the key gets its own keyring, named by the sources entry that uses it
curl -fsSL https://aspic.salataputarica.hr.eu.org/aspic.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/aspic.gpg
echo "deb [signed-by=/usr/share/keyrings/aspic.gpg] https://aspic.salataputarica.hr.eu.org/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/aspic.list
sudo apt update

amd64 · arm64 · armhf (every Raspberry Pi, the Zero included) · i386 · riscv64 · ppc64el · s390x · loong64.

Fedora / RHEL family

Fedora · RHEL · AlmaLinux · Rocky · CentOS Stream — dnf
# import the key first: dnf 5 will not fetch it from gpgkey= on its own
sudo rpm --import https://aspic.salataputarica.hr.eu.org/aspic.asc
sudo curl -fsSL -o /etc/yum.repos.d/aspic.repo \
  https://aspic.salataputarica.hr.eu.org/rpm/aspic.repo
sudo dnf makecache
Why the repo file is downloaded rather than typed. It carries repo_gpgcheck=1, so the metadata is verified and not only the packages, and metadata_expire=1h. dnf's default is 48 hours: once it has refreshed it will not look here again for two days, so a release published inside that window stays invisible and the only apparent cure is dnf clean all.

x86_64 · aarch64 · armv7hl · riscv64 · ppc64le · s390x · loongarch64 (openEuler).

openSUSE / SLE

Leap · Tumbleweed · SLES — zypper
sudo rpm --import https://aspic.salataputarica.hr.eu.org/aspic.asc
# swap x86_64 for your architecture
sudo zypper addrepo --refresh --gpgcheck \
  https://aspic.salataputarica.hr.eu.org/rpm/x86_64/ aspic
sudo zypper --gpg-auto-import-keys refresh

The same rpms as the section above — zypper just adds and refreshes repositories its own way.

Arch family

Arch · Manjaro · Artix · EndeavourOS — pacman
# fetch once, then add and locally sign the key by its fingerprint
curl -fsSL -o /tmp/aspic.asc https://aspic.salataputarica.hr.eu.org/aspic.asc
sudo pacman-key --add /tmp/aspic.asc
sudo pacman-key --lsign-key "$(gpg --show-keys --with-colons /tmp/aspic.asc \
  | awk -F: '/^fpr/{print $10; exit}')"
sudo tee -a /etc/pacman.conf <<'EOF'

[aspic]
SigLevel = Required
Server = https://aspic.salataputarica.hr.eu.org/arch/$arch
EOF
sudo pacman -Sy

x86_64 · aarch64 · armv7h. SigLevel = Required makes pacman refuse both an unsigned database and an unsigned package, which is the point of adding the key at all.

Alpine

Alpine Linux, and anything else using apk
# apk needs RSA — it has no ed25519 option, so this key is its own
sudo curl -fsSL -o /etc/apk/keys/aspic-alpine.rsa.pub \
  https://aspic.salataputarica.hr.eu.org/aspic-alpine.rsa.pub
# no architecture in the URL: apk appends it itself
echo "https://aspic.salataputarica.hr.eu.org/alpine" \
  | sudo tee -a /etc/apk/repositories
sudo apk update

x86_64 · x86 · aarch64 · armv7 · armhf · riscv64 · ppc64le · s390x, and big-endian ppc64 for Adélie Linux, which uses the same apk. Without that key in /etc/apk/keys, apk refuses the index rather than asking you about it.

OpenWrt

Two feeds, because OpenWrt 25.12 replaced opkg with apk-tools 3 — each signed with OpenWrt's own kind of key
# OpenWrt 25.12 and later: apk
. /etc/openwrt_release
wget -qO /etc/apk/keys/aspic-openwrt.pem https://aspic.salataputarica.hr.eu.org/aspic-openwrt.pem
echo "https://aspic.salataputarica.hr.eu.org/openwrt-apk/$DISTRIB_ARCH/packages.adb" \
  >> /etc/apk/repositories.d/customfeeds.list
apk update && apk add breeze-core

# OpenWrt 24.10 and older: opkg
. /etc/openwrt_release
wget -qO /tmp/aspic-usign.pub https://aspic.salataputarica.hr.eu.org/aspic-usign.pub
cp /tmp/aspic-usign.pub /etc/opkg/keys/$(usign -F -p /tmp/aspic-usign.pub)
echo "src/gz aspic https://aspic.salataputarica.hr.eu.org/openwrt/$DISTRIB_ARCH" \
  >> /etc/opkg/customfeeds.conf
opkg update && opkg install breeze-core

x86_64 · aarch64_generic · aarch64_cortex-a53 · aarch64_cortex-a72 · arm_cortex-a7_neon-vfpv4 · arm_arm1176jzf-s_vfp (Raspberry Pi Zero and 1) · i386_pentium4 · riscv64_riscv64 · loongarch64_generic · mipsel_24kc (MediaTek: MT7621, MT76x8) · mips_24kc (Atheros: ath79) · mips64_octeonplus (Cavium Octeon: EdgeRouter) — the MIPS ones being what most routers are. $DISTRIB_ARCH is your router's exact package architecture, which is what both feeds are laid out by. For opkg, the key file has to be named after its own fingerprint: opkg looks it up by that name, so a sensible filename silently fails to verify. apk does not care what the key file is called.

Termux

Android, inside the Termux app — Termux's own apt, the same key as Debian
# no sudo: everything belongs to the Termux app, under $PREFIX
mkdir -p $PREFIX/etc/apt/keyrings $PREFIX/etc/apt/sources.list.d
curl -fsSL https://aspic.salataputarica.hr.eu.org/aspic.asc \
  -o $PREFIX/etc/apt/keyrings/aspic.asc
echo "deb [signed-by=$PREFIX/etc/apt/keyrings/aspic.asc] https://aspic.salataputarica.hr.eu.org/termux stable main" \
  > $PREFIX/etc/apt/sources.list.d/aspic.list
pkg update && pkg install breeze-core

aarch64 · arm · x86_64. A real Android build rather than the static Linux one, so it reads the phone's own timezone and schedules fire at the right hour. It runs under termux-services and is installed switched off: pair a unit, then sv-enable breeze-core.

Android stops background apps. Run termux-wake-lock so it keeps running with the screen off, and add the Termux:Boot add-on to start it after a reboot.

FreeBSD

A real RSA-signed pkg repository — amd64, built and verified on FreeBSD 15.1
sudo mkdir -p /usr/local/etc/pkg/keys /usr/local/etc/pkg/repos
sudo fetch -o /usr/local/etc/pkg/keys/aspic.pub \
  https://aspic.salataputarica.hr.eu.org/freebsd/aspic-freebsd.pub
sudo tee /usr/local/etc/pkg/repos/aspic.conf <<'EOF'
aspic: {
  url: "https://aspic.salataputarica.hr.eu.org/freebsd",
  signature_type: "pubkey",
  pubkey: "/usr/local/etc/pkg/keys/aspic.pub",
  enabled: yes
}
EOF
sudo pkg update && sudo pkg install breeze-core

# then enable and start it
sudo sysrc breeze_core_enable=YES
sudo service breeze_core start

The package declares no dependencies — the Python line needed python312 and a wheel for every extension — and keeps /usr/local/etc/breeze-core on deinstall, so an upgrade over 3.2.0 leaves your config and device tokens alone. This repository is the only one here whose catalogue is signed on the machine that builds it, because pkg repo signs locally; the key goes there, gets used, and is destroyed with rm -P.

NetBSD

A pkgin feed — amd64, built on a real NetBSD machine because nothing cross-builds for it
echo "https://aspic.salataputarica.hr.eu.org/netbsd/All" \
  > /usr/pkg/etc/pkgin/repositories.conf
pkgin -y update && pkgin -y install breeze-core

# or, without pkgin:
pkg_add https://aspic.salataputarica.hr.eu.org/netbsd/All/breeze-core-4.3.2.tgz
This is the one feed here that is not signed. pkgin has no signature verification to offer, and pkg_add's GPG support wants a signed-package format this does not use — so what you get is HTTPS and nothing more. Every other section on this page verifies a signature made off this host; this one does not, and it would be dishonest to imply otherwise.

The package declares no dependencies at all — where the Python line needed python312 — and installs over it in place with pkg_add -U, keeping /usr/pkg/etc/breeze-core.

OpenBSD

A signify-signed package — amd64, built and verified on OpenBSD 7.9
# the key's filename is not cosmetic - see below
doas ftp -o /etc/signify/aspic-pkg.pub \
  https://aspic.salataputarica.hr.eu.org/openbsd/aspic-pkg.pub

doas pkg_add https://aspic.salataputarica.hr.eu.org/openbsd/7.9/packages/amd64/breeze-core-4.3.2.tgz
doas rcctl enable breeze_core && doas rcctl start breeze_core

# optional: let `pkg_add -u` find this repository too
export PKG_PATH="https://aspic.salataputarica.hr.eu.org/openbsd/%c/packages/%a/:$(cat /etc/installurl)/%c/packages/%a/"
The filename is load-bearing. pkg_add reads the signing key's name out of the package's signature and then opens /etc/signify/<that name>.pub. Save it as anything else and every install fails with signify: can't open /etc/signify/aspic-pkg.pub — which is also exactly what you get if you skip the key, so the refusal is the feature.

Release-specific on purpose: OpenBSD moves its libc every six months, so the path carries 7.9 rather than pretending one build serves every release. The service account comes from the packing list (@newuser), so pkg_delete takes it away again, and /etc/breeze-core is a @sample — an edited config is never overwritten and never removed. This is the first OpenBSD package the project has had: the Python line could only manage a source install here, because a virtualenv full of absolute paths is not something you can hand to pkg_add.

Void Linux

xbps, glibc and musl alike
echo "repository=https://aspic.salataputarica.hr.eu.org/xbps"   | sudo tee /etc/xbps.d/20-aspic.conf
sudo xbps-install -S breeze-core

x86_64 · aarch64 · armv7l · armv6l · riscv64 · ppc64le, each in both glibc and musl flavours, and i686 — thirteen packages holding the same bytes per architecture, because the binary is static and does not care which libc you run, but xbps keeps separate repodata per architecture and would otherwise show the package to only half of Void. No dependencies at all.

The package ships the runit service disabled, which is what Void expects. Enabling it is one symlink, and the breeze-core page has that plus the other twelve init systems.

xbps asks about the key the first time. Unlike apt, apk and opkg there is nothing to install beforehand: the public key travels inside the signed index, and xbps shows you its fingerprint and asks once. It should read 0a:9c:c0:1b:79:2c:eb:7a:97:70:3d:a3:f0:4b:db:22 — also published at /aspic-xbps.fingerprint, so you can compare rather than accept it blind.

Gentoo

An overlay, app-misc/breeze-core-bin
# needs app-eselect/eselect-repository
sudo eselect repository add aspic git \
  https://aspic.salataputarica.hr.eu.org/portage/breeze.git
sudo emerge --sync aspic
sudo emerge -av app-misc/breeze-core-bin

A -bin package, which on Gentoo usually needs an apology and here does not: the binary is statically linked, so it is independent of your USE flags, your CHOST and your libc, and there is nothing a local build could specialise. Ships both an OpenRC service and a systemd unit, plus acct-user/breeze and acct-group/breeze so the account is managed the Gentoo way rather than by a script.

On Gentoo the settings live in /etc/conf.d/breeze-core, not in breeze-core.env. Enabling and starting it: the breeze-core page.

Without eselect-repository, add it by hand: drop a file at /etc/portage/repos.conf/aspic.conf holding [aspic], location = /var/db/repos/aspic, sync-type = git and sync-uri = https://aspic.salataputarica.hr.eu.org/portage/breeze.git. There is no git server here — it is a plain static tree, which git clones and pulls from perfectly well.
arm is keyworded but guarded. Gentoo's arm keyword covers armv4 through armv7 and both float ABIs, while the prebuilt binary is ARMv6 hard-float (which every ARMv7 hard-float machine also runs). The ebuild checks your CHOST and refuses soft-float and older ARM with an explanation rather than installing something that cannot run. ppc64 covers both endiannesses, and both binaries exist: it picks the one your CHOST is. x86 needs SSE2.

Homebrew

macOS, Apple silicon and Intel · Linux, x86-64 and ARM64 — brew
brew tap aspic/breeze https://aspic.salataputarica.hr.eu.org/homebrew/breeze.git
brew trust aspic/breeze
brew install breeze-core

brew trust is Homebrew's own step for any tap outside its core, asked once: it loads no formula from a tap you have not trusted.

One formula for both systems, installing a prebuilt binary: on a Mac one built for macOS 13 or newer, on Linux the same static binary the packages above carry, so any distribution will do. The formula pins each download by its SHA-256 and itself comes over this site's HTTPS, and brew upgrade picks up each release.

Its files live in $(brew --prefix)/etc/breeze-core, and brew services start breeze-core runs it while you are logged in. Setting it up: the breeze-core page. Like the Gentoo overlay, the tap is a plain static git repository; there is no git server here.

OPNsense

A GUI plugin, os-breeze-core — one package, installed by hand
pkg add https://aspic.salataputarica.hr.eu.org/opnsense/os-breeze-core-4.3.2.pkg
# then: Services > Breeze Core - set the listen address, then enable

Not a repository, deliberately: your firewall already has pkg pointed at its own mirrors with its own ABI and its own trust, and adding a third-party repository to a firewall is a much bigger ask than fetching one file. Built on FreeBSD 14 and installs on both OPNsense 26.1 (FreeBSD 14) and 26.7 (FreeBSD 15) — the ordinary FreeBSD package above is built on 15, and FreeBSD binaries run forward, not backward. No dependencies, where the Python plugin vendored an entire interpreter, so nothing is ever compiled on the firewall and nothing breaks when OPNsense changes its Python.

Tested on OPNsense 26.7; on 26.1, only the package. The GUI page — settings, the service buttons, the paired units and the enrolled clients — has been installed and driven on OPNsense 26.7 (FreeBSD 15.1). On 26.1 (FreeBSD 14) the binary runs and the package installs, but the page itself has not been driven there.

About this host

aspic.salataputarica.hr.eu.org — a small server on a domestic connection, so be kind to it
servesstatic files over HTTPS, GET and HEAD only; every other method is refused
holdsno key, no account, no database — verification happens on your machine, against the keys above
deploysas a timestamped release with an atomically swapped current symlink, so a push is never half-visible and rolling back is one symlink
logsrequest lines, for rate limiting and for spotting scanners. Nothing else is collected, and there is nothing here to collect it with
indexingasked off, site-wide. Links are how anyone gets here
aria2every file you would download by hand — an installer, an APK, a tarball — has a Metalink beside it, the same name plus .meta4. aria2c given one fetches from aspic and the project's GitHub release at once, and checks every megabyte against its SHA-256 as it arrives. Range requests are served, up to 24 connections at a time