OpenVPN berjalan di shell tetapi gagal di bawah cron: masalahnya PATH
Perintah yang terhubung dari shell bisa gagal di bawah cron atau subprocess sebelum tunnel mulai. Perbaiki path, direktori kerja, dan terminal.
Perintah yang sama terhubung dari shell dan mati di bawah cron, jadi kesimpulan alaminya adalah tunnel atau sertifikatnya yang bersalah. Lihat apa yang sama pada kedua jalankan sebelum mempercayainya: biner, konfigurasi, dan kredensialnya identik, dan hanya lingkungan proses yang berubah. Ketika programnya bahkan tidak ditemukan, tidak ada jumlah debug TLS yang membantu. Perbaikannya biasanya ada di path, direktori kerja, dan segenggam variabel lingkungan, bukan di VPN.
command -v openvpn di shell yang berfungsi mencetak jawabannya, dan sangat sering itu /usr/sbin/openvpn, direktori yang tidak dimasukkan cron ke jalur pencariannya.
Tunnel tidak pernah mulai, jadi tunnel bukan masalahnya
Tugas yang dijalankan cron mewarisi lingkungan minimal, biasanya PATH=/usr/bin:/bin, dan tanpa terminal pengendali. Apa pun yang dipasang di /usr/sbin atau /usr/local/sbin sama sekali tidak ada di daftar itu, dan baris log berbunyi openvpn: not found alih-alih galat TLS. subprocess milik Python gagal dengan cara lain: ia mewarisi lingkungan proses penerjemah, yang bisa lebih kaya daripada milik cron tetapi tetap tidak punya shell untuk memperluas tilde. Kedua kegagalan terjadi sebelum satu paket pun meninggalkan host.
Cara cepat membedakannya adalah membaca galat pertama alih-alih yang terakhir. Biner yang hilang menghasilkan pengecualian shell atau Python, konfigurasi buruk menghasilkan pesan penggunaan OpenVPN, dan kegagalan jabat tangan sungguhan menghasilkan stempel waktu dan alamat rekan. Hanya yang ketiga merupakan masalah tunnel.
Path absolut dan daftar argumen mengalahkan string shell
Berikan path yang sudah diresolusi secara eksplisit dan lewati shell sepenuhnya. subprocess.run(["/usr/sbin/openvpn", "--config", config, "--verb", "4"], capture_output=True, text=True, timeout=90) memberi Anda kode kembali, stdout, dan stderr tanpa meminta shell menafsirkan nama berkas. Bangun path konfigurasi dari os.environ["HOME"] atau pathlib.Path.home(), sehingga tilde tidak pernah perlu diperluas. Ketika benar-benar butuh sintaks shell, gunakan shlex.split, karena memecah string dengan .split() rusak pada path apa pun yang berisi spasi. Baca juga stderr, karena OpenVPN menulis sebagian besar kegagalan awalnya di sana.
Aturan yang sama berlaku untuk cron: baris tugas bukan shell login, jadi tidak ada yang memuat profil Anda dan tidak ada yang mendefinisikan alias Anda.
Apa yang sebenarnya diwarisi crontab
Entri crontab mendapat lingkungan yang dideklarasikan crontab plus beberapa default warisan, jadi tulis path lengkapnya atau bungkus panggilannya dalam skrip yang melakukannya. Baris seperti PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin di bagian atas berkas mencakup lokasi pemasangan yang biasa, dan pengalihan dengan >> cron.log 2>&1 itulah yang membuat kegagalan berikutnya terbaca. Profil yang dilindungi frasa sandi tidak punya cara meminta rahasianya di bawah cron, karena tidak ada terminal untuk bertanya. Koneksi seperti itu semestinya berada di unit systemd yang bisa membaca berkas kredensial, bukan di tugas yang berpura-pura interaktif.
Path relatif adalah jebakan kedua. Uji coba sering terjadi dari folder yang menyimpan profil, sedangkan tugas cron mulai di tempat yang sama sekali lain, jadi --config office.ovpn mengarah ke berkas yang tidak ada dan pesannya terbaca sebagai berkas hilang alih-alih tunnel hilang.
Buktikan dengan mengupas lingkungan
Reproduksi lingkungan minimal secara langsung: env -i PATH=/usr/bin:/bin /usr/sbin/openvpn --config office.ovpn --verb 4. Keluhan path atau terminal dari jalankan itu berarti masalahnya berada di atas VPN. Jika terhubung, tersangka yang tersisa adalah akun tempat ia berjalan, direktori tempat ia mulai, dan kredensial yang ia sajikan. Hasil mana pun dari keduanya lebih baik daripada satu putaran lagi pemeriksaan sertifikat.
Lalu buat pembungkusnya melaporkan dirinya sendiri. Keluar dengan status berbeda untuk setiap tahap yang dicapai, catat kedua aliran dengan stempel waktu, dan kegagalan berikutnya memberi tahu Anda apakah ia mati saat resolusi path, saat autentikasi, atau setelah tunnel sudah naik.
Unit juga perlu urutan yang benar: Wants=network-online.target plus After=network-online.target mencegah klien mulai sebelum ada alamat atau rute default, yang jika tidak muncul sebagai galat sertifikat atau TLS yang hilang saat restart manual.