_____ _   _ _    _    ___      _
 / ____| \ | | |  | |  / / |    (_)
| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
 \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\

Uruchominie skryptu podczas ładowania systemu - jednostka systemd

Wykonanie skryptu w trakcie uruchamiania systemu, do bardzo stary problem wielu administratorów oraz entuzjastów systemu Linuks. Wraz ze zmianianą mainstreamowego programu typu init problem ten stał się wręcz trywialny, bo można użyć jednostki systemd, jednak nie którzy nie więdzą jak się do tego zabrać.

Każda jednostka systemd to plik tekstowy składający się z minimum dwóch sekcji. Pierwszą z nich jest sekcja Unit opisująca jednostkę. W wewnątrz niej mogą znajdować się takie informacje jak opis, kiedy ma zostać uruchomiona oraz jej ewentualne zależności. Druga sekcja jest już zależna od jednostki. Wśród jedenastu typów jednostek najbardziej odpowiednim jest jednostka usługi, ponieważ odpowiada ona poniękąd za uruchomienie programu, a tym w mniejszym lub większym stopniu jest nasz skrypt. W sekcji jednostki znajdują się dyrektywy są specyficzne dla tego typu jednostki. Opcjonalnie w pliku jednostki może znaleźć się sekcja Install, w której deklaruje się zależności wsteczne (inna jednostka może wymagać lub chcieć aktywacji tej jednostki podczas swojej aktywacji). Zależności wsteczne pozwalają na włączenie lub wyłączenie aktywacji jednostki w systemie.

Po scharakteryzowaniu pliku jednostki możemy przejść ustalania potrzebnych dyrektyw budując pliki jednostki. W sekcji Unit na pewno powinna znaleźć się dyrektywa Description, w której zawierany jest krótki opis jednostki. Jest on wyświetlany podczas uruchamiania jednostki w trakcie uruchamiania systemu. Za pewne chcielibyśmy aby skrypt był uruchamiany w takim samym środowisku jak byś uruchamiali go z poziomu wiersza polecenia, zatem należy opóźnić aktywacje jak tylko się da. Do tego posłuży nam dyrektywa After, która wskazuje systemd aby aktywował jednostkę po aktywacji jednostki zapisanej w tej dyrektywie. Najpóźniej aktywowaną jednostką w dystrybucjach Linuksa opartych o systemd jest default.target, po aktywacji której zazwyczaj uznaje się, że system jest już gotowy do pracy. Ta jednostka jest dowiązaniem symbolicznym do innej właściwej dla konfiguracji systemu jednostki. Następnie już w sekcji Service, za pomocą dyrektywy ExecStart wskazujemy ścieżkę do pliku skryptu, w tym przypadku jest to jedyna dyrektywa w tej sekcji. Abyśmy mogli włączać i wyłączać jednostkę powinniśmy dodać także sekcje Install a wewntąrz niej zależność zwrotną typu WantedBy wskazującą również na default.target. Spowoduje to automatyczne uruchomienie tej jednostki w momencie uruchomienia celu default.target, z opóźnieniem wynikającym z dyrektywy After. Zależność typu WantedBy, nie spowoduje problemów z jednostką default.target gdy uruchomienie jednostki ze skryptem nie powiedzie się. Zawartość pliku jednostki powinna wyglądać mniej więcej jak na poniższym przykładzie.

xf0r3m@wyse3040:~$ cat /etc/systemd/system/ssh_tunnel.service 
[Unit]
Description=SSH Tunnel for remote access
After=default.target
[Service]
ExecStart=/home/xf0r3m/tunnel.sh
[Install]
WantedBy=default.target

W moim przypadku jest to skrypt który uruchamia tunel SSH z przekazywaniem portów oraz zajmuję się jego utrzymaniem. Zwróćmy uwagę na lokalizacje pliku jednostki. Jest ona jak najbardziej odpowiednia. Po utworzeniu pliku możemy, przystąpić do włączenia jednostki w celu default.target.

xf0r3m@wyse3040:~$ sudo systemctl enable ssh_tunnel.service

Po jej włączeniu możemy ją aktywować.

xf0r3m@wyse3040:~$ sudo systemctl start ssh_tunnel.service

Za pomocą podpolecenia status polecenia systemctl możemy sprawdzić stan uruchomionej jednostki.

      xf0r3m@wyse3040:~$ sudo systemctl status ssh_tunnel.service 
● ssh_tunnel.service - SSH Tunnel for remote access
     Loaded: loaded (/etc/systemd/system/ssh_tunnel.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-07-24 10:12:42 CEST; 2s ago
   Main PID: 1246 (tunnel.sh)
      Tasks: 2 (limit: 2235)
     Memory: 1.2M
        CPU: 164ms
     CGroup: /system.slice/ssh_tunnel.service
             ├─1246 /bin/bash /home/xf0r3m/tunnel.sh
             └─1247 ssh -p 2022 -i /home/xf0r3m/.ssh/id_rsa -o StrictHostKeyChecking=no xf0r3m@... -R ...:127.0.0.1:22 while [ true ...

lip 24 10:12:42 wyse3040 systemd[1]: Started SSH Tunnel for remote access.

Oczywiście statusy nie wszystkich jednostek, które uruchamiają skrypty będą wyglądać tak samo, nie które z nich mogą się dezaktywować się po zakończeniu działania skryptu. Moj skrypt działa ponieważ jego trzonem jest nieskończona pętla, która sprawia, że jeśli dojdzie do zerwania tunelu, zostanie on za 30 sekund zestawiony ponownie.

Źródła:

  1. How to Run Script on Boot Up in Debian 11

~xf0r3m