Przejdź do treści
Administracja·~13 min czytania

Priorytety APT: gdy pakiet jest i w dystrybucji, i w repozytorium zewnętrznym

Trzy źródła tego samego pakietu PHP, wszystkie z priorytetem 500. Kto wygrywa, dlaczego akurat on i co zmienia pin - na pomiarach z działającego systemu.

Autor: Zespół LinuxLab

W LinuxLab repozytoria zewnętrzne są codziennością - bez nich nie da się utrzymywać aplikacji wymagających starszego albo nowszego PHP niż to, które niesie dystrybucja. Cena za to jest jedna: od momentu ich dodania APT - czyli narzędzie, którym Debian instaluje i aktualizuje pakiety - ma do wyboru kilka wersji tego samego pakietu i trzeba wiedzieć, według jakiej reguły wybiera.

W tym artykule bierzemy konkretny przypadek: pakiety PHP dostarczane jednocześnie przez archiwum Debiana i przez zewnętrzne repozytorium Ondřeja Surego. Pokazujemy, dlaczego przy identycznych priorytetach wygrywa wersja z zewnątrz, jak napisać regułę zmieniającą ten wybór i dlaczego ta sama reguła zadziała na pakiecie jeszcze niezainstalowanym, a na już zainstalowanym nie zmieni nic. Wszystkie wydruki pochodzą z maszyny testowej, nie z dokumentacji.

Spis treści

  1. Co zmierzyliśmy
  2. Jeden pakiet, trzy źródła
  3. Priorytety i ich znaczenie
  4. Przy remisie decyduje wersja
  5. Dlaczego zewnętrzna wygrywa
  6. Jak napisać regułę
  7. Pułapka pakietu zainstalowanego
  8. Priorytet 1000 i degradacja
  9. Pakiet tylko z zewnątrz
  10. Wygrywa pierwszy wpis
  11. Weryfikacja
  12. Checklista

Co zmierzyliśmy

Wszystkie wydruki w tym artykule pochodzą z maszyny testowej z Debianem 12, na której obok archiwum dystrybucji skonfigurowane jest zewnętrzne repozytorium PHP. Stan z 11 września 2026.

SprawdzenieWynik
Ile źródeł dostarcza php8.2-clitrzy: repozytorium zewnętrzne, bookworm-security i bookworm
Priorytety tych źródełwszystkie 500 - żaden nie jest uprzywilejowany
Który wygrywazewnętrzny, mimo remisu priorytetów
Porównanie wersjidpkg --compare-versions potwierdza, że wersja zewnętrzna jest wyższa
Reguła obniżająca zewnętrzne do 100na pakiecie zainstalowanym nie zmienia kandydata
Reguła z priorytetem -1również nie zmienia kandydata pakietu zainstalowanego
Reguła z priorytetem 1001 na archiwum Debianazmienia kandydata; symulacja zgłasza 16 pakietów do degradacji
Ta sama reguła na pakiecie niezainstalowanymdziała od razu - kandydat przeskakuje na wersję z dystrybucji
php7.4-cli w Debianie 12nie istnieje; dostarcza go wyłącznie repozytorium zewnętrzne
Reguła z priorytetem -1 a jawna instalacjablokuje ją: Package ... has no installation candidate

Czego nie sprawdzaliśmy: zachowania przy trzech i więcej repozytoriach zewnętrznych naraz, ani tego, jak reguły zachowują się przy zmianie wydania dystrybucji. Wnioski dotyczą Debiana 12 i APT w wersji z tego wydania; mechanizm jest ten sam na Ubuntu, ale nazwy archiwów się różnią.

Jeden pakiet, trzy źródła

Zacznijmy od tego, co widać po dodaniu repozytorium zewnętrznego. Polecenie apt-cache policy pokazuje wszystkie znane wersje pakietu razem ze źródłem i priorytetem:

$ apt-cache policy php8.2-cli
php8.2-cli:
  Installed: 8.2.33-1+0~20260730.92+debian12~1.gbp655644
  Candidate: 8.2.33-1+0~20260730.92+debian12~1.gbp655644
  Version table:
 *** 8.2.33-1+0~20260730.92+debian12~1.gbp655644 500
        500 https://packages.sury.org/php bookworm/main amd64 Packages
        100 /var/lib/dpkg/status
     8.2.33-1~deb12u1 500
        500 .../debian-security.list bookworm-security/main amd64 Packages
     8.2.32-1~deb12u1 500
        500 .../debian.list bookworm/main amd64 Packages

Ten wydruk warto umieć czytać, bo zawiera komplet informacji potrzebnych do zrozumienia decyzji APT:

  • Installed - wersja obecnie zainstalowana w systemie.
  • Candidate - wersja, którą APT zainstaluje przy najbliższej okazji. To ona jest przedmiotem całego sporu.
  • Gwiazdki *** - oznaczają wersję zainstalowaną.
  • Liczba przy wersji - priorytet, z jakim ta wersja jest brana pod uwagę.
  • Wpis /var/lib/dpkg/status z priorytetem 100 - to nie jest repozytorium, tylko sam fakt, że pakiet jest zainstalowany. Ten wpis pojawia się zawsze i odegra kluczową rolę w dalszej części artykułu.

Najważniejsza obserwacja: wszystkie trzy źródła mają priorytet 500. Repozytorium zewnętrzne nie jest w żaden sposób uprzywilejowane - dostało dokładnie tyle samo, co archiwum dystrybucji. A mimo to wygrywa.

Priorytety i ich znaczenie

Priorytet to liczba całkowita przypisana wersji pakietu. APT wybiera kandydata według prostej reguły: bierze wersję o najwyższym priorytecie, a przy remisie - najwyższą wersję. Pełna skala wygląda tak:

PriorytetZachowanie
< 0nigdy nie instaluj - wersja przestaje być brana pod uwagę
1 - 99instaluj tylko, jeśli pakietu nie ma w żadnej wersji
100priorytet wersji już zainstalowanej
101 - 499instaluj, o ile nie ma już zainstalowanej innej wersji
500 - 989wartość domyślna zwykłego repozytorium
990 - 999wydanie wskazane jako docelowe
>= 1000instaluj nawet kosztem obniżenia wersji

Dwa progi z tej tabeli decydują o wszystkim, co dzieje się dalej. Sto to priorytet wersji zainstalowanej - dlatego pakiet, który już jest w systemie, nie znika tak łatwo. Tysiąc to jedyny próg pozwalający APT cofnąć wersję; poniżej niego obniżenie nie nastąpi nawet wtedy, gdy wskazane źródło ma wyższy priorytet.

Przy remisie decyduje wersja

Skoro wszystkie trzy źródła mają po 500, priorytet nie rozstrzyga niczego. APT przechodzi wtedy do drugiego kryterium i wybiera najwyższą wersję. Sprawdziliśmy to wprost, narzędziem, które porównuje wersje dokładnie tak jak APT:

$ dpkg --compare-versions \
    "8.2.33-1+0~20260730.92+debian12~1.gbp655644" gt "8.2.33-1~deb12u1" \
    && echo "zewnetrzna wyzsza"
zewnetrzna wyzsza

Wersja z repozytorium zewnętrznego jest wyższa od tej z bookworm-security, mimo że obie noszą numer 8.2.33. Różnica siedzi w części po myślniku - i nie jest przypadkowa.

Dlaczego wersja z zewnątrz wygrywa

Porównywanie wersji w Debianie ma jedną regułę, która wygląda na drobiazg, a decyduje o całej sytuacji: znak tyldy sortuje się przed niczym, a znak plusa po niczym. Sprawdzone na prostych przykładach:

$ dpkg --compare-versions "1.0~rc1" lt "1.0"  && echo tak   # tak
$ dpkg --compare-versions "1.0"    lt "1.0+x" && echo tak   # tak
$ dpkg --compare-versions "1.0~x"  lt "1.0+x" && echo tak   # tak

Tylda istnieje po to, żeby oznaczać wersje przedpremierowe: 1.0~rc1 ma być niższe od 1.0, bo to kandydat wydany przed finalną wersją. Debian używa jej także w oznaczeniach poprawek dla stabilnego wydania - stąd 8.2.33-1~deb12u1.

Teraz zestawmy obie wersje obok siebie:

ŹródłoWersjaZnak po -1
Debian, bookworm-security8.2.33-1~deb12u1~ - sortuje w dół
Repozytorium zewnętrzne8.2.33-1+0~20260730...+ - sortuje w górę

Wniosek jest jednoznaczny: schemat numerowania w repozytorium zewnętrznym jest tak zbudowany, żeby jego pakiety wygrywały z dystrybucyjnymi przy tym samym numerze wersji. To nie jest przypadek ani złośliwość - to celowa decyzja, żeby po dodaniu repozytorium jego pakiety faktycznie były używane. Ale konsekwencja jest taka, że od momentu dodania takiego repozytorium poprawki bezpieczeństwa dla PHP przychodzą od jego opiekuna, a nie od zespołu bezpieczeństwa dystrybucji. To warto wiedzieć, zanim się je doda.

To dotyczy nie tylko PHP. Ta sama mechanika działa dla każdego repozytorium zewnętrznego, które wydaje pakiety o nazwach obecnych w dystrybucji - repozytoriów baz danych, serwerów WWW, języków programowania. Za każdym razem, gdy dodajesz takie źródło, sprawdź przez apt-cache policy, ile pakietów właśnie przeszło pod jego opiekę. Bywa ich więcej, niż zakładałeś.

Jak napisać regułę

Reguły priorytetów zapisuje się w plikach w katalogu /etc/apt/preferences.d/. Wpis ma trzy pola:

Package: *                          # nazwa pakietu albo wzorzec
Pin: origin packages.sury.org       # czego dotyczy
Pin-Priority: 100                   # jaki priorytet nadac

Pole Pin ma kilka wariantów i wybór między nimi ma znaczenie praktyczne:

ZapisDopasowujeKiedy używać
origin nazwa.serwerapakiety pobrane z danego serweragdy chcesz objąć całe repozytorium zewnętrzne
release o=Debianpakiety z archiwum o danym pochodzeniugdy chcesz wyróżnić dystrybucję
release a=bookworm-backportskonkretne archiwumprzy backportach
version 8.2.*konkretne wersjegdy zależy Ci na jednej linii wydań

Wartości do tych pól nie trzeba zgadywać - podaje je samo apt-cache policy uruchomione bez nazwy pakietu:

$ apt-cache policy
 500 https://packages.sury.org/php bookworm/main amd64 Packages
     release o=deb.sury.org,a=bookworm,n=bookworm,c=main,b=amd64
     origin packages.sury.org
 500 .../debian.list bookworm/main amd64 Packages
     release v=12.15,o=Debian,a=oldstable,n=bookworm,l=Debian,c=main,b=amd64

W linii release widać wszystkie pola, po których można dopasowywać: o to pochodzenie, a archiwum, n nazwa wydania, l etykieta. Linia origin podaje nazwę serwera - i to jej używa zapis Pin: origin.

Uwaga na dwa różne znaczenia słowa „origin”. W zapisie Pin: origin packages.sury.org chodzi o nazwę serwera, bez cudzysłowów i bez protokołu. W zapisie Pin: release o=deb.sury.org chodzi natomiast o pole pochodzenia z metadanych repozytorium, które bywa zupełnie inne niż nazwa serwera - tutaj deb.sury.org kontra packages.sury.org. Pomylenie ich kończy się regułą, która nie dopasowuje niczego i po cichu nie działa.

Pułapka pakietu zainstalowanego

Tu zaczyna się część, która najczęściej zaskakuje. Załóżmy, że PHP przyszło już z repozytorium zewnętrznego i chcemy wrócić do wersji dystrybucyjnej. Zakładamy regułę obniżającą repozytorium zewnętrzne do priorytetu 100:

Package: *
Pin: origin packages.sury.org
Pin-Priority: 100

Wynik jest taki, jakby reguła nie istniała:

$ apt-cache policy php8.2-cli
  Installed: 8.2.33-1+0~20260730.92+debian12~1.gbp655644
  Candidate: 8.2.33-1+0~20260730.92+debian12~1.gbp655644    <- bez zmian
 *** 8.2.33-1+0~20260730.92+debian12~1.gbp655644 100
        100 https://packages.sury.org/php bookworm/main amd64 Packages
        100 /var/lib/dpkg/status
     8.2.33-1~deb12u1 500
        500 .../debian-security bookworm-security/main amd64 Packages

Wersja z dystrybucji ma teraz priorytet 500, a zewnętrzna tylko 100 - i mimo to kandydatem pozostaje ta zewnętrzna. Powód: przejście na wersję dystrybucyjną byłoby obniżeniem wersji, a tego APT nie zrobi poniżej progu tysiąca. Reguła nie ma tu nic do rzeczy.

Można pomyśleć, że mocniejszy zapis pomoże. Sprawdziliśmy i priorytet ujemny:

Pin-Priority: -1
$ apt-cache policy php8.2-cli
  Candidate: 8.2.33-1+0~20260730.92+debian12~1.gbp655644    <- nadal bez zmian
 *** 8.2.33-1+0~20260730.92+debian12~1.gbp655644 100
         -1 https://packages.sury.org/php bookworm/main amd64 Packages
        100 /var/lib/dpkg/status

Zwróć uwagę na te dwie linie pod wersją. Repozytorium dostało -1, ale wersja jako taka ma nadal 100 - bo jest zainstalowana, a zainstalowane wersje zawsze mają ten priorytet z wpisu /var/lib/dpkg/status. Blokada wycięła źródło, nie pakiet.

Reguła priorytetu nie odinstalowuje niczego. Działa na to, co APT może zainstalować, a nie na to, co już jest w systemie. Jeżeli chcesz się pozbyć pakietu z niewłaściwego źródła, reguła sama tego nie zrobi - trzeba osobno wymusić zmianę wersji albo usunąć pakiet i zainstalować go ponownie przy działającej już regule. Kolejność ma znaczenie: reguła założona przed instalacją jest skuteczna, założona po - najczęściej nie zmienia nic.

Priorytet 1000 i degradacja

Jedynym progiem, który przełamuje opisaną wyżej blokadę, jest tysiąc. Zamiast obniżać repozytorium zewnętrzne, podnosimy archiwum dystrybucji:

Package: *
Pin: release o=Debian
Pin-Priority: 1001

Teraz kandydat faktycznie się zmienia:

$ apt-cache policy php8.2-cli
  Installed: 8.2.33-1+0~20260730.92+debian12~1.gbp655644
  Candidate: 8.2.33-1~deb12u1                              <- wersja z dystrybucji
     8.2.33-1~deb12u1 1001

Zanim jednak uznasz to za rozwiązanie, zobacz, co taka zmiana pociąga. Symulacja instalacji - która niczego nie zmienia w systemie - pokazuje skalę:

$ sudo apt-get -s install php8.2-cli
The following packages will be DOWNGRADED:
  ...
0 upgraded, 0 newly installed, 16 downgraded, 0 to remove and 0 not upgraded.

Szesnaście pakietów do obniżenia z jednego polecenia dotyczącego jednego pakietu. Tak wygląda w praktyce zależność między modułami PHP: pociągają się nawzajem i schodzą razem. Obniżanie wersji jest przy tym operacją, której opiekunowie pakietów nie testują - przejście w dół bywa nieobsługiwane przez skrypty instalacyjne i potrafi zostawić konfigurację w stanie pośrednim.

Dlatego priorytet tysiąca traktujemy jako narzędzie do świadomej, jednorazowej migracji, wykonywanej w oknie serwisowym i z kopią zapasową - a nie jako stałą politykę w pliku, o którym za pół roku nikt nie będzie pamiętał.

Pakiet tylko z zewnątrz

Dotąd mówiliśmy o pakiecie dostępnym z obu stron. Zupełnie inaczej wygląda sytuacja, gdy repozytorium zewnętrzne jest jedynym źródłem. Porównajmy dwa pakiety tym samym poleceniem:

$ apt-cache madison php8.2-cli
php8.2-cli | 8.2.33-1+0~20260730... | https://packages.sury.org/php bookworm/main
php8.2-cli | 8.2.33-1~deb12u1       | .../debian-security bookworm-security/main
php8.2-cli | 8.2.32-1~deb12u1       | .../debian.list bookworm/main

$ apt-cache madison php7.4-cli
php7.4-cli | 1:7.4.33-30+0~2026...  | https://packages.sury.org/php bookworm/main

PHP w wersji 8.2 to linia, którą Debian 12 niesie sam - stąd trzy wpisy. PHP 7.4 nie istnieje w archiwum tej dystrybucji w żadnej wersji; dostarcza go wyłącznie repozytorium zewnętrzne, stąd jeden wpis.

Różnica ma bardzo praktyczne konsekwencje dla reguł. Blokada repozytorium zewnętrznego przy pakiecie z dwoma źródłami jedynie przełącza na wersję dystrybucyjną. Przy pakiecie z jednym źródłem usuwa go z dostępnych całkowicie - nie ma na co przełączyć.

Widać to na pakiecie, którego w systemie jeszcze nie ma. Przed regułą:

$ apt-cache policy php8.2-redis
  Installed: (none)
  Candidate: 6.3.0-2+0~20260711.69+debian12~1.gbpd148c3     <- z zewnatrz

Po założeniu reguły blokującej repozytorium zewnętrzne:

$ apt-cache policy php8.2-redis
  Installed: (none)
  Candidate: 5.3.7+4.3.0-3                                  <- z dystrybucji
     6.3.0-2+0~20260711.69+debian12~1.gbpd148c3 -1
     5.3.7+4.3.0-3 500

Tu reguła zadziałała natychmiast i dokładnie tak, jak się spodziewamy - bo nie ma zainstalowanej wersji, która broniłaby pozycji. To jest ta sama reguła, która chwilę wcześniej nie zrobiła nic; różnica leży wyłącznie w tym, czy pakiet był już w systemie.

Gdyby ten sam zapis objął php7.4-cli, efektem nie byłoby przełączenie na starszą wersję, tylko komunikat o braku kandydata do instalacji.

Wygrywa pierwszy wpis, nie najwyższy priorytet

To jest najmniej oczywista część mechanizmu i warto ją znać, zanim w katalogu uzbiera się kilka plików. Gdy do tego samego pakietu pasuje więcej niż jeden wpis, APT bierze pierwszy napotkany, a nie ten o najwyższym priorytecie. Pliki czytane są w kolejności alfabetycznej nazw, a wewnątrz pliku od góry.

Konsekwencja jest prosta i praktyczna: plik, który ma blokować, musi sortować się wcześnie. Stąd konwencja nazywania z liczbą na początku - 00-blokada.pref zadziała, 99-blokada.pref obok 10-zezwolenie.pref już nie.

Oto autentyczny przykład takiej reguły, działającej na naszych maszynach testowych:

# /etc/apt/preferences.d/00-bez-automatycznych-aktualizacji.pref
Package: unattended-upgrades
Pin: release *
Pin-Priority: -1

Efekt jest całkowity - pakiet przestaje istnieć z punktu widzenia APT:

$ apt-cache policy unattended-upgrades
  Installed: (none)
  Candidate: (none)
     2.9.1+nmu3 -1
        500 .../debian.list bookworm/main amd64 Packages

$ sudo apt-get install unattended-upgrades
E: Package 'unattended-upgrades' has no installation candidate

Zwróć uwagę na dwie rzeczy. Po pierwsze, blokada działa nawet przy jawnym poleceniu instalacji - to nie jest tylko preferencja, to odcięcie. Po drugie, nazwa pliku zaczyna się od zera, więc sortuje się przed wszystkim innym, co ktoś mógłby dopisać później.

Ta reguła pokazuje przy okazji, dlaczego użyto tu priorytetu, a nie zamrożenia wersji. Zamrożenie działa na pakiet już zainstalowany - nie zapobiega instalacji czegoś, czego jeszcze nie ma. Priorytet ujemny blokuje instalację w ogóle, także wtedy, gdy pakiet miałby wejść jako zależność miękka czegoś innego. Więcej o tym rozróżnieniu piszemy w artykule o testowaniu aktualizacji.

Weryfikacja

Reguły priorytetów mają nieprzyjemną właściwość: błędnie napisana reguła nie zgłasza błędu. Po prostu nie dopasowuje niczego, a system zachowuje się tak, jakby jej nie było. Dlatego każdą zmianę sprawdzamy trzema poleceniami.

1. Co APT uważa za kandydata - jedyne pytanie, które naprawdę się liczy:

apt-cache policy NAZWA_PAKIETU

2. Skąd pochodzą wszystkie znane wersje - przydatne, gdy chcesz zobaczyć, czy pakiet ma jedno źródło, czy kilka:

apt-cache madison NAZWA_PAKIETU

3. Co się faktycznie wydarzy - bez wykonywania zmiany. To jest krok, który wyłapuje niespodzianki w rodzaju szesnastu pakietów do obniżenia:

sudo apt-get -s install NAZWA_PAKIETU

Do tego jedno polecenie, które wypisuje, jak APT rozumie Twoje reguły - przydatne przy podejrzeniu, że wpis nie dopasowuje:

apt-cache policy | head -30

Sprawdzać trzeba na maszynie takiej samej jak docelowa. Te same reguły na Debianie i na Ubuntu dopasowują inaczej, bo nazwy archiwów i pola pochodzenia są inne - zapis działający na jednym systemie potrafi po cichu nie dopasować niczego na drugim.

Checklista

  1. Po dodaniu repozytorium zewnętrznego sprawdziłeś, ile pakietów przeszło pod jego opiekę, a nie tylko ten jeden, dla którego je dodawałeś.
  2. Wiesz, że od tego momentu poprawki bezpieczeństwa dla tych pakietów przychodzą od opiekuna repozytorium, nie od zespołu dystrybucji.
  3. Reguły priorytetów zakładasz przed instalacją pakietu, nie po - po instalacji najczęściej nie zmienią nic.
  4. Plik, który ma blokować, ma nazwę sortującą się wcześnie.
  5. Wartości do pól Pin wziąłeś z apt-cache policy, a nie z pamięci - nazwa serwera i pole pochodzenia to dwie różne rzeczy.
  6. Każdą regułę zweryfikowałeś przez apt-cache policy na pakiecie, którego dotyczy.
  7. Przed zastosowaniem uruchomiłeś symulację i przeczytałeś, ile pakietów zostanie ruszonych.
  8. Priorytet tysiąca i wyższy stosujesz świadomie, w oknie serwisowym, a nie jako stałą politykę.
  9. Wiesz, które pakiety mają tylko jedno źródło - dla nich blokada oznacza brak możliwości instalacji, a nie przełączenie.
  10. Reguły sprawdziłeś na systemie takim samym jak docelowy.

Repozytoria zewnętrzne są narzędziem, bez którego wielu aplikacji po prostu nie da się utrzymać - i nie ma powodu ich unikać. Warto tylko pamiętać, że dodanie takiego źródła to nie jest rozszerzenie wyboru, tylko zmiana tego, kto wydaje pakiety na Twoim serwerze. Priorytety są mechanizmem, który pozwala tę decyzję świadomie kształtować, zamiast przyjmować ją jako skutek uboczny jednej linijki w konfiguracji.

Dokumentacja

Nie wiesz, skąd pochodzą pakiety na Twoim serwerze?

Porządkujemy źródła pakietów i politykę aktualizacji: co ma przychodzić z dystrybucji, co z repozytorium zewnętrznego, a czego nie wolno ruszać bez decyzji człowieka.