Jak zamknąć serwer Linux po uruchomieniu przez 60 minut?

18

Mam serwer, który normalnie jest wyłączony ze względów bezpieczeństwa. Kiedy chcę nad tym popracować, włączam go, wykonuję zadania i zamykam ponownie. Moje zadania zwykle nie trwają dłużej niż 15 minut. Chciałbym wdrożyć mechanizm automatycznego wyłączania po 60 minutach.

Zbadałem, jak to zrobić z cronem, ale nie sądzę, że jest to właściwy sposób, ponieważ cron nie bierze pod uwagę, kiedy serwer był ostatnio włączony. Mogę ustawić tylko okresowe wzorce, ale nie uwzględniają tych danych.

Jak mogę to zrobić?

jmhostalet
źródło
4
Spójrz na at(wykonanie jednorazowe).
dirkt
14
Nie zrobiłem tego, ale skrypt logowania może uruchomić sudo shutdown -h +60odliczanie, które uruchomi 60-minutowy licznik dla procesu zamykania (-halt). Jeśli chcesz to anulować, możesz sudo shutdown -c (to nie używa crona)
guiverc
7
W zależności od charakteru twoich zadań może warto je uruchomić w kontenerze dokera, więc nie musisz się martwić o wyłączenie serwera. Kontener jest tworzony, uruchamia twoje zadania, a następnie jest niszczony.
Vicente Olivert Riera
6
Nie oczekuj z tego żadnej realnej korzyści dla bezpieczeństwa. Większość luk można wykorzystać w niecałą sekundę, więc wyłączenie zasilania po godzinie nie zapobiegnie wykorzystaniu. Atakujący, który odkryje lukę, może poczekać, aż włączysz maszynę w celu przeprowadzenia ataku.
kasperd
2
Re: Komentarz @kasperd, chciałbym przeformułować, że potrzebujesz dokładnie takiej samej ochrony na swoim serwerze, niezależnie od tego, ile w rzeczywistości jest w sieci. Uwaga: jest to serwer, więc jest podłączony do czegoś , co oznacza, że coś się dowie, kiedy zostanie włączone - automatyczne zamiatanie nie jest tym, o co się martwisz, są to wszelkiego rodzaju połączenia i nie możesz tego uniknąć, więc maksymalne bezpieczeństwo jest cały czas jedyny sposób.
StephenG,

Odpowiedzi:

23

Jeśli wykonujesz zadania jako ten sam użytkownik za każdym razem, możesz po prostu dodać polecenie zamykania, opcjonalnie z opcją -P, do swojego profilu. Liczba oznacza liczbę minut, po których polecenie zamknięcia jest opóźnione. Upewnij się, że użytkownik ma możliwość wykonania polecenia zamknięcia za pośrednictwem sudo bez hasła.

echo "sudo shutdown -P +60" >> ~/.profile
Dirk Krijgsman
źródło
11
Czas jest w minutach, a nie sekundach. Spróbuj shutdown -k -P 3600vs shutdown -k -P 60( -kdrukuje wiadomość na ścianie, ale nie ma innego efektu)
sebasth
12
Ale wypróbuj polecenie za pierwszym razem, nie chcesz, aby natychmiastowe wyłączenie było powiązane z Twoim profilem!
Fabian Röling,
17
Wyobrażam sobie, że każde logowanie ssh spowodowałoby nowe wezwanie do zamknięcia. Czy licznik zresetowałby się wtedy?
JoL
4
Warto również wspomnieć, że logowanie nie będzie dozwolone w ciągu ostatnich 5 minut, jak wspomniano na stronie zamykania systemu.
JoL
6
Pamiętaj, że 60 minut po zalogowaniu to nie to samo, co 60 minut po uruchomieniu. Co się stanie, jeśli uruchomisz komputer, a następnie zapomnisz się zalogować?
Hagen von Eitzen
69

Istnieje kilka opcji.

  • Zapewnij czas bezpośrednio na shutdown -P:

    shutdown -P +60
    

    Zauważ, że shutdown strona podręcznika wskazuje również:

    Jeśli użyto argumentu czasu, na 5 minut przed awarią systemu tworzony jest plik / run / nologin, aby zapewnić, że dalsze logowanie nie będzie dozwolone.

  • Użyj atpolecenia.

  • Utwórz plik jednostki systemowej lub skrypt inicjujący, który będzie uruchamiany shutdown -P 60podczas uruchamiania.

  • Użyj crona, @rebootaby uruchomić polecenie po uruchomieniu.

    Dodaj do (root) crontab:

    @reboot shutdown -P +60
    

W przypadku dwóch ostatnich metod można również użyć sleep 3600 && shutdown -P nowzamiast argumentu czasu, shutdownaby opóźnić zamknięcie systemu o 60 minut. W ten sposób logowanie jest możliwe do ostatniej chwili przed zamknięciem systemu.

sebasth
źródło
2
Myślę, że za pomocą sleeppolecenia nadal musisz określić czas shutdown- chcielibyśmy użyć nowtego argumentu, jeśli już zrobiliśmy czekanie (ale pamiętaj, że nie dostaniesz zbyt wiele ostrzeżenia, aby zapisać swoją pracę przed nim znika spod ciebie!).
Toby Speight
1
Chociaż shutdown -P 60działa, nie jest to sposób, w jaki należy wywoływać polecenie. Według strony podręcznika, której powinieneś użyć shutdown -P +60. --- Również zamknięcie bez argumentu czasowego (w tym przykładzie sleep 3600 && shutdown -P) zostanie opóźnione o jedną minutę (jak shutdown -P +1). Jak napisał Toby Speight, prawdopodobnie będziesz chciał użyć shutdown -P now.
pabouk
33

To wygląda na problem XY .

Moje zadania zwykle trwają nie dłużej niż 15 minut. Chciałbym wdrożyć mechanizm automatycznego wyłączania go po 60 minutach.

Jeśli zamkniesz się po 60 minutach, ryzykujesz, że masz szczególnie skomplikowany problem i potrzebujesz więcej czasu. Wiele wcześniejszych rozwiązań nie ułatwiłoby opóźnienia wyłączenia.

Jeśli zadanie nie jest zadaniem interaktywnym, ale jest zadaniem skryptowym, które jest automatycznie uruchamiane z innej maszyny, @sdkks daje świetne rozwiązanie tego problemu ; naprawdę powinieneś po prostu zlecić maszynie wyłączenie zasilania, gdy tylko skrypt i wszystkie jego zadania zakończą się.

Jeśli jednak twoje zadanie jest zadaniem interaktywnym, sugeruję zamiast tego wykonać wykrywanie bezczynności.

Jeśli wykonujesz swoje zadanie w GUI (X11), możesz wykryć bezczynne sesje GUI, korzystając z opisanego tutaj podejścia: Uruchom polecenie, gdy system jest w stanie bezczynności i gdy jest ponownie aktywny

Jeśli wykonasz zadanie za pośrednictwem terminala, możesz wykryć zalogowanych użytkowników za pomocą whopolecenia. Możesz skonfigurować cronjob, który wyłącza maszynę, jeśli whozwróci pusty wynik. Zauważ, że będzie to dość konserwatywne podejście; nie zamknie systemu, jeśli konsola pozostanie podłączona, ale pozostanie bezczynna.

Jeśli chcesz być nieco bardziej agresywny i rozłączać bezczynne sesje terminali, możesz połączyć poprzednie podejście z automatycznym rozłączaniem bezczynnych sesji SSH ClientAliveInterval i ClientAliveCountMax. Innym podejściem w tym przypadku, jeśli nie masz SSH, ale masz lokalną sesję terminala, jest użycie czasu bezczynności terminala zwróconego przez wpolecenie.

Lie Ryan
źródło
2
To bardzo ważny punkt. Cokolwiek zastosujesz - w twoim interesie jest upewnienie się, że możesz również anulować zamknięcie.
Shadow
1
Coś poszło nie tak, jeśli nadal działa na 60 m, więc może zacznij od nowa. Może to być bardzo kosztowne w chmurze. Nie zapewnianie zamknięcia za jednym razem przywróciło mi ponad 4000 $.
mckenzm,
8

Chociaż wszystkie poprzednie odpowiedzi tutaj spełniają wymóg doskonałości, możesz również wyłączyć maszynę, gdy tylko zadania zostaną wykonane.

bashskrypty mogą być trapped, co oznacza, że ​​niektóre sygnały mogą być przechwytywane, a niektóre zadania mogą być wykonywane w razie potrzeby. EXITjest jednym z sygnałów, które mogą zostać uwięzione.

Byłbyś w stanie:

  1. Ustaw a trapdla EXITswoich automatycznych skryptów powłoki, co oznacza zakończenie automatycznych zadań
  2. Ustaw trapdla swojego .bashrc EXIT, co oznacza, że ​​za każdym razem, gdy wylogujesz się z tego urządzenia, wyłącz je.

Opcja nr 1 byłaby idealnym rozwiązaniem, pod warunkiem, że twoje zadania nie wymagają kontroli adhoc i ręcznej oceny.

Opcja nr 2 obejmowałaby przypadki, w których zapomniałbyś wyjść z terminala bez wyłączania zasilania. Jest jednak zastrzeżenie; jeśli masz wiele otwartych terminali na tym samym komputerze i wyjdziesz z jednego z nich, nadal będzie ono wyłączać urządzenie. (Można tego użyć w skryptach, aby tego uniknąć, ale nie skomplikuję rozwiązania).

cleanup(){
    # Do some tasks before terminating
    echo oh la la, cleaning is so nice
    echo "See you later, world"
    sudo poweroff & # finally shutdown
}
trap cleanup EXIT

Może to być na końcu .bashrcopcji nr 2, gdzieś na górze skryptu dla opcji nr 1.

Dlaczego nie użyć poweroffna końcu skryptu?

Wolę używać set -eo pipefailna górze moich skryptów. Jeśli wystąpi jakikolwiek błąd, nie po cichu zawiedzie; przestanie wykonywać więcej poleceń. trapz EXITsygnałem powinno obejmować przypadki, gdy skrypt kończy się przedwcześnie z powodu błędów.

Jednak w przypadku zadań może to również oznaczać, że urządzenie zostanie zamknięte przed ich zakończeniem.

Mam prosty bashszablon, którego używam, aby ułatwić debugowanie skryptów; może to może się przydać. Zobacz tę treść .

sdkks
źródło
Zgodziłem się, a na pewno być może pora na zamknięcie od crona. To hamulec umarlaka.
mckenzm,
@Abigail dla skryptu, musi być powyżej, ponieważ .bashrcwolałbym dół, na wypadek gdyby coś innego go nadpisało . Twoje obawy nie wydają się jasne, czy możesz udostępnić przykładowy fragment na repl.it?
sdkks,
@mckenzm Nie rozumiem. Czy możesz udostępnić przykładowy kod lub więcej wyjaśnień?
sdkks,
5

Opracowanie na @dirkt komentarza można wstawić atpolecenia na swój .bashrclub .profilelub inny plik twoi zastosowania powłoki przy logowaniu, aby zaplanować automatyczne wyłączenie po 60 minutach loginu.

Coś jak:

at now + 60 minutes -f /sbin/halt
Pan Shunz
źródło
To zadanie jest od atsamego początku. Możesz również zobaczyć atzadania w /var/spool/
formacie
5
Odradzałbym używanie atw tym kontekście, ponieważ przetrwa ponowne uruchomienie. Jeśli OP miałby się zalogować, ręcznie zamknąć, a następnie zalogować się ponownie w ciągu godziny, zostałby wyrzucony przed upływem godziny po ostatnim logowaniu, kiedy nastąpi pierwsze zaplanowane zamknięcie.
Aaron
@Aaron to prawda. Nie myślałem o tym. Trwałość rozruchu jest zastrzeżeniem dla tego rozwiązania.
sdkks,
5

Następujące działa commandz parametrami, a jeśli zakończy się pomyślnie, natychmiast wyłączy to pole, zakładając, że użytkownik może uruchomić poweroff. Może być konieczne użycie sudo poweroff.

command --parameters && poweroff

Podczas gdy następujący po prostu uruchamia się poweroffnatychmiast po zakończeniu polecenia:

command --parameters ; poweroff

Jeśli uważasz, że polecenie wymaga odpoczynku po zakończeniu, uruchom

command --parameters ; sleep 3600 ; poweroff

Jeśli uważasz, że polecenie może być uruchamiane w godzinach nadliczbowych, możesz ograniczyć je do godziny:

timeout 1h command --parameters ; poweroff

timeoutjest częścią coreutilspakietu, więc prawdopodobnie już go masz.

Criggie
źródło
3

Jeśli naprawdę martwisz się bezpieczeństwem, użyj mechanicznego wyłącznika czasowego na źródle zasilania. Po prostu ustaw na czas, w którym chcesz się zamknąć. W ten sposób nikt nie może zalogować się zdalnie i wyłączyć wyłączenia. Potrzebujesz fizycznego dostępu.

gogatorzy
źródło
2
Uszkodzenie systemu plików?
Xen2050
@ Xen2050 nie stanowi problemu w żadnym nowoczesnym (kronikującym) systemie plików.
Tom
1
@Tom Czy masz źródło wymuszonych umountów, które nigdy nie spowodują uszkodzenia systemu plików, jeśli istnieje kronikowanie? Brzmi dla mnie nowość, chciałbym o tym przeczytać. Musi przynajmniej oznaczać system plików jako brudny, co wymusza fsck, prawda?
Xen2050
1
W większości przypadków należy po prostu odtworzyć dziennik i wykonać to. Wyłączenie nie powinno spowodować uszkodzenia systemu plików w kronikowanym systemie plików, chociaż nie ma gwarancji, chyba że użyjesz systemu plików takiego jak ZFS, który jest specjalnie zaprojektowany do tego przypadku.
Tom
1
Powtarzanie dziennika może się nie powieść - miałem kilka trudnych sesji fsck kilka tygodni temu po ½-sekundowej przerwie w zasilaniu komputera bez UPS. To korzystało z ext4 z dziennikiem; nie jest całkowicie niezwyciężony!
Toby Speight
2

Jeśli jesteś w systemdmaszynie, możesz użyć monotonicznego timera

Jednostka czasowa /etc/systemd/system/shutdown_after_an_hour.timer

[Unit]
Description=shutdown after an hour

[Timer]
OnBootSec=1h

[Install]
WantedBy=timers.target

Jednostka czasowa /etc/systemd/system/shutdown_after_an_hour.service:

[Unit]
Description=shutdown after an hour

[Service]
ExecStart=/sbin/poweroff --force --no-wall
Type=oneshot

Jest włączony przez

# systemctl enable shutdown_after_an_hour.timer

Jego status (szczególnie ile czasu pozostało do wyłączenia) jest dostępny za pośrednictwem

# systemctl list-timers shutdown_after_an_hour.timer

Będzie działał przy następnym ponownym uruchomieniu, nie będzie dla systemctl startniego przydatny podczas sesji, gdy zostanie utworzony, ponieważ albo nie będzie działał (ponieważ nie został uruchomiony podczas ponownego uruchamiania), albo od razu zamknie maszynę, jeśli minęła godzina. Nie wiem, co się wydarzy, nigdy nie testowałem tego konkretnego przypadku.

WoJ
źródło
1

Spróbuj umieścić skrypt ( sudo shutdown -P 3600) w /etc/init.dkatalogu, aby uruchomić go automatycznie podczas uruchamiania.

Lub spróbuj użyć anacron, dodając polecenie do /etc/anacrontabpliku. Sugeruję również użycie nohupprzed poleceniem, aby upewnić się, że polecenie nadal działa po wylogowaniu.

Saveriofr
źródło
1
W zależności od dystrybucji dystrybucja może nie zostać wykonana po prostu w
init.d
@sdkks, masz rację. Można również rozważyć Anacron. umieszczenie skryptu w / etc / anacrontab, również używanym z 'nohup' w przypadku wylogowania.
Saveriofr
1
@Saveriofr Możesz edytować swoją odpowiedź, aby poprawić jej jakość (lepiej niż publikowanie dodatkowych informacji w komentarzu).
Anthony G - sprawiedliwość dla Moniki
1

Wykorzystaj plik wylogowania swojej powłoki

Jeśli potrzebujesz tylko serwera do interaktywnych lub nieinteraktywnych zadań uruchomionych przez UID, rozważ umieszczenie poleceń zamykania w pliku ~ / .bash_logout . Podręcznik GNU Bash mówi:

Kiedy kończy się interakcyjna powłoka logowania lub nieinteraktywna powłoka logowania wykonuje wbudowane polecenie zakończenia, Bash odczytuje i wykonuje polecenia z pliku ~ / .bash_logout, jeśli istnieje.

Tak więc dodanie „sudo poweroff” lub podobnego do pliku wylogowania spowoduje wyłączenie serwera, gdy tylko wylogujesz się z bieżącej sesji lub gdy zadzwoni nieinteraktywna sesja Bash exit. Można również zdecydować się na stosowanie u lub przekazać opóźnienia czasowego do wyłączenia , jeśli wolisz, aby odroczyć zamknięcie.

Aby uzyskać bardziej interaktywne podejście do tego, możesz umieścić następujące Bashisms w pliku wylogowania:

# Shutdown unless N or n is pressed within 30 seconds.
shopt -s nocasematch
read -t 30 -N 1 -p 'Shutdown now? (Y/n) '
[[ "$REPLY" =~ n ]] || sudo poweroff

Ostrzeżenia

Jest kilka ostrzeżeń, o których należy pamiętać w związku z tym rozwiązaniem:

  • Prawdopodobnie będzie to działać nawet pod terminalem uruchomionym przez X Windows, ale prawdopodobnie nie zadziała dla sesji X11, która nie została uruchomiona przez startx lub podobną.
  • Jeśli masz wywoływane nieinteraktywne skrypty exit, mogą wystąpić wyłączenia, których się nie spodziewasz.
  • Plik sudoers może monitować o podanie hasła, jeśli nie podałeś NOPASSWDkomend zamykania systemu lub jeśli nie zadzwoniłeś sudo -vprzed uruchomieniem komendy zamykania systemu.
  • Prawdopodobnie są jeszcze inne przypadki krawędzi, o których jeszcze nie myślałem.

Krótko mówiąc, możesz zastanowić się, czy to podejście spełnia twoje rzeczywiste potrzeby, czy też zupełnie inne podejście, takie jak monitorowanie braku zalogowanych użytkowników lub inna alternatywa, jest lepszym rozwiązaniem. Twój przebieg na pewno będzie się różnić.

CodeGnome
źródło