FreeBind проти After=: прив'язка сокета systemd до адреси VPN
FreeBind дозволяє systemd володіти слухачем ще до появи адреси VPN; After= лише впорядковує завдання. Порівняйте їх і перевірте порядок та готовність.
Під час завантаження сокет-юніт, що прив'язує фіксовану адресу VPN, може зазнати невдачі ще до того, як тунель призначить її, і служба за ним так і не запуститься. Два перемикачі виглядають як виправлення і вирішують різні половини цієї проблеми. FreeBind дозволяє systemd створити слухач, поки адреса ще відсутня. After= лише впорядковує завдання, тому змінює, коли що запускається, але не наближає появу адреси.
Дві різні проблеми, два різні перемикачі
Перша проблема — збій прив'язки: ядро відмовляє в прослуховуванні адреси, якою хост не володіє, тому сокет-юніт одразу зазнає невдачі, а служба ніколи не активується. Друга проблема — збій готовності: адреса зрештою існує, але щось намагається використати її до того, як тунель почне передавати трафік. FreeBind вирішує першу і нічого не робить для другої. Директиви порядку не вирішують жодну напряму, бо вони лише визначають, що і в якій послідовності запускається. Назвати збій, який у вас справді є, — це і є все рішення.
Переконайтеся, який із двох у вас, за журналом, а не за описом служби. Збій прив'язки називає адресу і повідомляє, що її не можна призначити. Збій готовності зазвичай з'являється пізніше — як тайм-аут або відхилене з'єднання, побачене з іншого боку, при цілком здоровому сокет-юніті в журналах.
FreeBind: слухач існує до адреси
FreeBind каже ядру дозволити прив'язку до нелокальної адреси, тож systemd може створити слухаючий сокет під час завантаження і передати його застосунку, коли б застосунок не запустився. У цьому сенс активації через сокет і причина, чому сокет може пережити службу за ним.
[Socket]
ListenStream=
ListenStream=10.8.0.1:8443
FreeBind=yes
Порожнє призначення очищає записи прослуховування, успадковані від юніта постачальника, перш ніж додати новий, що не дає залишковому слухачу wildcard відповідати на кожному інтерфейсі. Замініть адресу й порт своїми і перевірте чинний юніт, а не лише файл drop-in. Використовуйте drop-in під іменем юніта замість редагування файлу пакета на місці, бо наступне оновлення пакета перезапише правку і не залишить жодного сліду про намір. Потім застосуйте його через процедуру перезавантаження й перезапуску, якої очікує сокет-юніт.
Довідник із сокетів systemd описує поведінку IPv4 та IPv6 за цією опцією, і важлива деталь у тому, що вона стосується прив'язки, а не маршрутизації. Ніщо в ньому не призначає адресу і не запускає VPN. FreeBind — це дозвіл, наданий слухачу, а не заміна інтерфейсу.
After= і Wants=: порядок — це не готовність
Порядок і вимога — різні осі, і їх змішування дає юніти, які запускаються в правильному порядку і все одно зазнають невдачі. After=vpn-client.service означає лише те, що якщо обидва завдання запущено, це чекає на запуск іншого. Він не притягує VPN і не чекає, поки VPN завершить підключення.
Директиви вимоги, як-от Wants= і Requires=, опікуються активацією і різняться тим, що відбувається, коли залежність зазнає невдачі: одна продовжує, інша зупиняється. Жодна з них не знає, що означає підключений тунель. Процес VPN може бути активним без призначеної адреси або з призначеною адресою і без маршруту до партнера, і обидва стани задовольняють залежність. Якщо застосунку потрібне існування адреси, моделюйте цю умову явно, а не вважайте запуск процесу доказом готовності.
Перевірте, що юніт насправді оголошує, за допомогою systemctl cat і systemctl show -p After -p Wants -p Requires. Drop-in з трьох різних каталогів можуть додати директиви, яких ви ніколи не писали, а systemd читає лише чинний юніт.
Чого network-online.target не робить
Юніт, упорядкований після network-online.target, чекає, поки менеджер мережі оголосить мережу придатною, а це точка синхронізації під час завантаження, а не постійна умова. Він нічого не каже про те, чи піднято конкретний тунель, і не спрацює знову, коли VPN перепідключиться після обіду. Вважати його монітором перепідключення — найпоширеніше хибне прочитання цієї цілі.
Проєкт systemd прямо документує цю різницю, і практичний наслідок у тому, що все, чому потрібна адреса тунелю, має саме володіти залежністю. Юніт, який чекає на network-online, а потім прив'язує адресу тунелю, правильний лише тоді, коли тунель випадково піднімається першим, а це збіг, а не проєкт.
Перевірте життєвий цикл, який ви насправді обрали
Перевірте чисте завантаження, запит після появи адреси і поведінку після падіння та повернення VPN. Ці три випадки відділяють робочий слухач від робочої служби.
systemd-analyze verify myapp.socket
systemctl cat myapp.socket
ss -ltn "sport = :8443"
Перша команда ловить помилки файлу юніта до перезавантаження, друга показує об'єднаний юніт, а третя доводить, чи існує слухач і на якій адресі. Слухач на адресі wildcard там, де ви чекали адресу тунелю, — це саме той залишок, який порожній ListenStream мав прибрати. Повторіть третю команду після перепідключення VPN, щоб побачити, чи змістилася адреса.
Виберіть життєвий цикл свідомо: або вільно прив'язаний слухач, який чекає на повернення стабільної адреси, або служба, яка зупиняється разом із тунелем і знову запускається під час відновлення. Це різні проєкти, і вони зазнають невдачі по-різному. Потім тримайте політику доступу прив'язаною до тих джерел і шляхів, які ви задумали, бо прив'язка адреси призначення не вимагає, щоб прийняті пакети надійшли через довірений інтерфейс.