OpenVPN در شل کار میکند اما زیر cron شکست میخورد: مشکل PATH است
فرمانی که از شل وصل میشود میتواند زیر cron یا subprocess پیش از آغاز تونل شکست بخورد. مسیر، پوشه کاری و ترمینال را درست کنید.
همان فرمان از شل وصل میشود و زیر cron میمیرد، پس نتیجه طبیعی این است که تونل یا گواهی مقصر است. پیش از باور کردن این، ببینید دو اجرا چه اشتراکی دارند: فایل اجرایی، پیکربندی و اعتبارنامهها یکساناند و تنها محیط فرایند تغییر کرده است. وقتی برنامه حتی پیدا نمیشود، هیچ مقدار اشکالزدایی TLS کمکی نمیکند. اصلاح معمولاً در یک مسیر، یک پوشه کاری و مشتی متغیر محیطی است، نه در VPN.
command -v openvpn در شلی که کار میکند پاسخ را چاپ میکند، و بسیار اوقات /usr/sbin/openvpn است، پوشهای که cron آن را در مسیر جستوجوی خود نمیگذارد.
تونل هرگز آغاز نشد، پس تونل مشکل نیست
کارهایی که cron آغاز میکند محیطی کمینه به ارث میبرند، بهطور متعارف PATH=/usr/bin:/bin، و هیچ ترمینال کنترلی ندارند. هر چیزی که در /usr/sbin یا /usr/local/sbin نصب شده باشد بهسادگی از آن فهرست غایب است، و سطر گزارش بهجای خطای TLS عبارت openvpn: not found را میخواند. subprocess پایتون بهگونهای دیگر شکست میخورد: محیط فرایند مفسر را به ارث میبرد که ممکن است از محیط cron غنیتر باشد اما هنوز شلی برای بازکردن تیلدا ندارد. هر دو شکست پیش از آن رخ میدهند که یک بسته میزبان را ترک کند.
راه سریع تشخیص آنها خواندن نخستین خطا بهجای آخرین است. فایل اجرایی گمشده استثنایی در شل یا پایتون تولید میکند، پیکربندی بد پیام راهنمای 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 ظاهر میشود و با راهاندازی مجدد دستی ناپدید میگردد.