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
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.
| Sprawdzenie | Wynik |
|---|---|
Ile źródeł dostarcza php8.2-cli | trzy: repozytorium zewnętrzne, bookworm-security i bookworm |
| Priorytety tych źródeł | wszystkie 500 - żaden nie jest uprzywilejowany |
| Który wygrywa | zewnętrzny, mimo remisu priorytetów |
| Porównanie wersji | dpkg --compare-versions potwierdza, że wersja zewnętrzna jest wyższa |
| Reguła obniżająca zewnętrzne do 100 | na pakiecie zainstalowanym nie zmienia kandydata |
| Reguła z priorytetem -1 | również nie zmienia kandydata pakietu zainstalowanego |
| Reguła z priorytetem 1001 na archiwum Debiana | zmienia kandydata; symulacja zgłasza 16 pakietów do degradacji |
| Ta sama reguła na pakiecie niezainstalowanym | działa od razu - kandydat przeskakuje na wersję z dystrybucji |
php7.4-cli w Debianie 12 | nie istnieje; dostarcza go wyłącznie repozytorium zewnętrzne |
| Reguła z priorytetem -1 a jawna instalacja | blokuje 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/statusz 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:
| Priorytet | Zachowanie |
|---|---|
< 0 | nigdy nie instaluj - wersja przestaje być brana pod uwagę |
1 - 99 | instaluj tylko, jeśli pakietu nie ma w żadnej wersji |
100 | priorytet wersji już zainstalowanej |
101 - 499 | instaluj, o ile nie ma już zainstalowanej innej wersji |
500 - 989 | wartość domyślna zwykłego repozytorium |
990 - 999 | wydanie wskazane jako docelowe |
>= 1000 | instaluj 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ło | Wersja | Znak po -1 |
|---|---|---|
Debian, bookworm-security | 8.2.33-1~deb12u1 | ~ - sortuje w dół |
| Repozytorium zewnętrzne | 8.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:
| Zapis | Dopasowuje | Kiedy używać |
|---|---|---|
origin nazwa.serwera | pakiety pobrane z danego serwera | gdy chcesz objąć całe repozytorium zewnętrzne |
release o=Debian | pakiety z archiwum o danym pochodzeniu | gdy chcesz wyróżnić dystrybucję |
release a=bookworm-backports | konkretne archiwum | przy backportach |
version 8.2.* | konkretne wersje | gdy 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
- 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ś.
- Wiesz, że od tego momentu poprawki bezpieczeństwa dla tych pakietów przychodzą od opiekuna repozytorium, nie od zespołu dystrybucji.
- Reguły priorytetów zakładasz przed instalacją pakietu, nie po - po instalacji najczęściej nie zmienią nic.
- Plik, który ma blokować, ma nazwę sortującą się wcześnie.
- Wartości do pól
Pinwziąłeś zapt-cache policy, a nie z pamięci - nazwa serwera i pole pochodzenia to dwie różne rzeczy. - Każdą regułę zweryfikowałeś przez
apt-cache policyna pakiecie, którego dotyczy. - Przed zastosowaniem uruchomiłeś symulację i przeczytałeś, ile pakietów zostanie ruszonych.
- Priorytet tysiąca i wyższy stosujesz świadomie, w oknie serwisowym, a nie jako stałą politykę.
- Wiesz, które pakiety mają tylko jedno źródło - dla nich blokada oznacza brak możliwości instalacji, a nie przełączenie.
- 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
- apt_preferences(5) - pełny opis priorytetów i składni pinów
- deb-version(7) - zasady porównywania wersji, w tym rola tyldy
- apt-cache(8) - polecenia
policyimadison - deb.sury.org - repozytorium PHP użyte w przykładach
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.
Powiązany artykuł
Dlaczego aktualizacje trzeba testować: przypadek Debiana 12.3
Co automatyczne aktualizacje instalują domyślnie i dlaczego to ma związek z priorytetami.
Zobacz też