Та сама команда підключається з оболонки й умирає під cron, тому природний висновок — винні тунель або сертифікат. Перш ніж у це повірити, подивіться, що спільного в двох запусків: бінарник, конфігурація й облікові дані однакові, а змінилося лише середовище процесу. Коли програму навіть не знаходять, жодне налагодження TLS не допомагає. Виправлення зазвичай лежить у шляху, робочому каталозі та жмені змінних середовища, а не у VPN.

command -v openvpn у робочій оболонці друкує відповідь, і дуже часто це /usr/sbin/openvpn, каталог, який cron не додає до свого шляху пошуку.

Тунель так і не запустився, тож проблема не в тунелі

Завдання, запущені cron, успадковують мінімальне середовище, зазвичай PATH=/usr/bin:/bin, і не отримують керуючого термінала. Усе, що встановлено в /usr/sbin або /usr/local/sbin, просто відсутнє в цьому списку, і рядок журналу каже openvpn: not found замість помилки TLS. Python-івський subprocess падає інакше: він успадковує середовище процесу інтерпретатора, яке може бути багатшим за cron-івське, але досі не має оболонки, щоб розгорнути тильду. Обидві невдачі трапляються до того, як хоч один пакет залишить хост.

Швидкий спосіб їх розрізнити — читати першу помилку, а не останню. Відсутній бінарник дає виняток оболонки або Python, погана конфігурація дає повідомлення про використання OpenVPN, а справжня невдача рукостискання дає позначки часу й адреси партнерів. Лише третя — проблема тунелю.

Абсолютні шляхи й списки аргументів перемагають рядки оболонки

Передайте розв'язаний шлях явно й повністю оминіть оболонку. subprocess.run(["/usr/sbin/openvpn", "--config", config, "--verb", "4"], capture_output=True, text=True, timeout=90) дає код повернення, stdout і stderr, не просячи оболонку інтерпретувати ім'я файлу. Будуйте шлях до конфігурації з os.environ["HOME"] або pathlib.Path.home(), щоб тильду ніколи не доводилося розгортати. Коли справді потрібен синтаксис оболонки, використовуйте shlex.split, бо розбиття рядка через .split() ламається на будь-якому шляху з пробілом. Читайте й stderr, оскільки OpenVPN пише туди більшість своїх ранніх невдач.

Те саме правило стосується cron: рядок завдання — не вхідна оболонка, тож ніщо не завантажує ваш профіль і ніщо не визначає ваші псевдоніми.

Що насправді успадковує crontab

Запис у crontab отримує середовище, яке оголошує crontab, плюс кілька успадкованих типових значень, тож пропишіть шлях повністю або обгорніть виклик у скрипт, який це робить. Рядок на кшталт PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin на початку файлу покриває звичайні місця встановлення, і перенаправлення через >> cron.log 2>&1 — це те, що робить наступну невдачу читабельною. Профіль, захищений парольною фразою, під cron не може попросити свій секрет, бо термінала для запиту немає. Таке з'єднання належить модулю systemd, який уміє читати файл облікових даних, а не завданню, яке вдає інтерактивність.

Відносні шляхи — друга пастка. Тестовий запуск часто відбувається з папки з профілем, а завдання cron стартує зовсім в іншому місці, тож --config office.ovpn розв'язується у файл, якого там немає, і повідомлення читається як відсутній файл, а не відсутній тунель.

Доведіть це, знявши середовище

Відтворіть мінімальне середовище безпосередньо: env -i PATH=/usr/bin:/bin /usr/sbin/openvpn --config office.ovpn --verb 4. Скарга на шлях або термінал із цього запуску означає, що проблема вище за VPN. Якщо він підключається, залишкові підозрювані — це обліковий запис, під яким він працює, каталог, з якого стартує, і облікові дані, які він подає. Кожен із двох результатів кращий за чергове коло перевірки сертифікатів.

Далі зробіть обгортку самостійно звітувальною. Виходьте з окремим статусом для кожного досягнутого етапу, записуйте обидва потоки з позначкою часу, і наступна невдача скаже вам, чи він помер на розв'язанні шляху, на автентифікації чи після того, як тунель уже був піднятий.

Модулю потрібен і правильний порядок: Wants=network-online.target разом з After=network-online.target не дають клієнту стартувати раніше, ніж з'явиться адреса або маршрут за замовчуванням, що інакше проявляється як помилки сертифіката або TLS, які зникають під час ручного перезапуску.

Схожі статті