Linux: расписание задач и SSH

Cron, at и systemd-таймеры, а также ключи, конфигурация, туннели и удалённое выполнение команд по SSH

Cron: синтаксис расписания

# минута(0-59)  час(0-23)  день(1-31)  месяц(1-12)  день_недели(0-7, 0 и 7 — воскресенье)
  *             *           *           *            *        команда
РасписаниеЗначение
0 3 * * *Каждый день в 03:00
*/5 * * * *Каждые 5 минут
0 9 * * 1-5По будням в 09:00
30 2 1 * *1 числа каждого месяца в 02:30
0 */2 * * *Каждые два часа, ровно в 0 минут
0 9,18 * * *В 09:00 и 18:00
0 0 * * 0Каждое воскресенье в полночь
@rebootОдин раз при загрузке
@daily / @weekly / @monthlyСокращения для 0 0 * * *, 0 0 * * 0, 0 0 1 * *
@hourlyКаждый час, в 0 минут

Управление crontab

КомандаВариантЧто делает
crontab -ecrontab -eРедактировать свой crontab (откроется редактор из $EDITOR).
crontab -lcrontab -lПоказать свой crontab.
crontab -rcrontab -rУдалить весь crontab (без подтверждения, осторожно).
crontab -usudo crontab -u deploy -lРабота с crontab другого пользователя (нужны права root).
crontab -icrontab -riУдалять с подтверждением.
/etc/cron.d//etc/cron.d/backupСистемные задания с полем пользователя (шестое поле).
/etc/cron.dailyls /etc/cron.dailyСкрипты, которые запускаются раз в день через run-parts.
/var/log/sysloggrep CRON /var/log/syslog | tailЖурнал выполнения cron (на systemd — journalctl -u cron).

Пример crontab

# Бэкап каждую ночь в 03:15, с логом
15 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# Очистка временных файлов старше 7 дней, раз в час
0 * * * * find /srv/tmp -type f -mtime +7 -delete

# Проверка доступности сайта каждые 5 минут
*/5 * * * * curl -fsS -o /dev/null https://example.com || echo "down $(date)" >> /var/log/site.log

# Переменные окружения в crontab (PATH по умолчанию урезан)
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
В cron окружение почти пустое: нет вашего PATH и переменных из ~/.bashrc. Указывайте полные пути к программам (например, /usr/bin/python3) и перенаправляйте вывод в файл, иначе ошибки уйдут на почту или потеряются.

at и systemd-таймеры

КомандаВариантЧто делает
atecho "./job.sh" | at now + 5 minutesОдноразовое задание через 5 минут (пакет at).
at -fat -f job.sh 23:00 tomorrowВзять команды из файла, выполнить завтра в 23:00.
atqatqСписок запланированных задач at.
atrmatrm 12Удалить задачу с номером 12.
systemctl list-timerssystemctl list-timers --allРасписание systemd-таймеров: когда запустится и когда последний раз.
systemd-runsudo systemd-run --on-calendar="*-*-* 04:00" /usr/local/bin/job.shСоздать временное задание на расписании systemd.
systemd-run --scopesystemd-run --user --scope -p MemoryMax=512M ./heavy.shЗапустить с ограничением памяти.

SSH: ключи

КомандаВариантЧто делает
ssh-keygenssh-keygen -t ed25519 -C "ivan@laptop"Создать ключ Ed25519 (рекомендуемый тип).
ssh-keygen -bssh-keygen -t rsa -b 4096RSA-ключ, если Ed25519 не поддерживается.
ssh-keygen -fssh-keygen -t ed25519 -f ~/.ssh/deploy_keyУказать имя файла.
ssh-keygen -pssh-keygen -p -f ~/.ssh/id_ed25519Сменить парольную фразу ключа.
ssh-keygen -lssh-keygen -lf ~/.ssh/id_ed25519.pubОтпечаток ключа.
ssh-keygen -Rssh-keygen -R server.example.comУдалить старый ключ хоста из known_hosts (после переустановки сервера).
ssh-copy-idssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostДобавить публичный ключ в authorized_keys на сервере.
ssh-copy-id -pssh-copy-id -p 2222 user@hostНестандартный порт.
ssh-agenteval "$(ssh-agent -s)"Запустить агент, который держит расшифрованный ключ.
ssh-addssh-add ~/.ssh/id_ed25519Добавить ключ в агент (введёте парольную фразу один раз).
ssh-add -lssh-add -lКлючи, загруженные в агент.
ssh-add -Dssh-add -DУдалить все ключи из агента.

SSH: подключение и команды

КомандаВариантЧто делает
sshssh ivan@server.example.comПодключиться.
ssh -pssh -p 2222 ivan@serverНестандартный порт.
ssh -issh -i ~/.ssh/deploy_key deploy@serverУказать ключ.
ssh -tssh -t server 'sudo systemctl status nginx'Выделить терминал, нужен для sudo с запросом пароля или интерактивных программ.
ssh cmdssh server 'df -h /'Выполнить одну команду и выйти.
ssh -vssh -vvv serverОтладка подключения (аутентификация, ключи, порт).
ssh -ossh -o ConnectTimeout=5 -o BatchMode=yes server trueПроверка доступа в скриптах: без запросов, с таймаутом.
ssh -Jssh -J bastion.example.com internal-dbПодключиться через jump-хост (ProxyJump).
ssh -Nssh -N -f -L 5432:db:5432 bastionТолько туннель, без команды; -f уводит в фон.
ssh -4 / -6ssh -4 serverПринудительно IPv4 или IPv6.
ssh -Xssh -X serverПеренаправить X11 (графические программы на сервере).
ssh -Assh -A bastionПереслать агент ключей. Включайте только для доверенных хостов.

SSH: туннели

КомандаВариантЧто делает
ssh -Lssh -L 8080:localhost:80 user@serverЛокальный порт 8080 ведёт на порт 80 сервера (он доступен только с вашей машины).
ssh -L remotessh -L 5432:db.internal:5432 bastionДоступ к внутренней базе через bastion.
ssh -Rssh -R 9000:localhost:3000 user@publicПорт 9000 на публичном сервере ведёт на ваш localhost:3000.
ssh -Dssh -D 1080 -N user@serverДинамический SOCKS-прокси на локальном порту 1080.

Конфигурация ~/.ssh/config

Host web
    HostName 10.0.0.12
    User deploy
    Port 2222
    IdentityFile ~/.ssh/deploy_key
    IdentitiesOnly yes

Host db
    HostName 10.0.1.5
    User ivan
    ProxyJump bastion

Host bastion
    HostName bastion.example.com
    User ivan
    ServerAliveInterval 60
    ServerAliveCountMax 3

После этого достаточно ssh web или ssh db, а scp file db:/tmp/ тоже работает через ProxyJump.

Права и безопасность

КомандаВариантЧто делает
chmod 700 ~/.sshchmod 700 ~/.sshПапка с ключами доступна только владельцу.
chmod 600 ключchmod 600 ~/.ssh/id_ed25519Приватный ключ. Без этого ssh откажется работать.
chmod 600 authorized_keyschmod 600 ~/.ssh/authorized_keysФайл разрешённых ключей на сервере.
sshd -tsudo sshd -tПроверить синтаксис sshd_config перед перезагрузкой службы.
systemctl reload sshdsudo systemctl reload sshПрименить изменения конфига sshd (на Debian служба называется ssh).
sshd_configPermitRootLogin no ; PasswordAuthentication noОтключить вход root и вход по паролю (сначала убедитесь, что ключи работают).
who / lastlast -i | headКто и с каких адресов заходил по SSH.
journalctl -u sshsudo journalctl -u ssh --since todayЖурнал попыток входа и ошибок.

Пример: защищённый туннель к базе через bastion

# Поднять туннель в фоне: локальный порт 15432 ведёт на базу
ssh -f -N -L 15432:10.0.1.5:5432 ivan@bastion.example.com

# Подключиться к базе через локальный порт
psql -h 127.0.0.1 -p 15432 -U app appdb

# Закрыть туннель: найти процесс и завершить
pgrep -af "ssh -f -N -L 15432"
pkill -f "ssh -f -N -L 15432"
ssh -R и ssh -D открывают доступ из внешней сети к вашему локальному сервису. Не оставляйте их без присмотра и привязывайте к localhost (например, -R 127.0.0.1:9000:...). Также не включайте PasswordAuthentication yes на публичных серверах: их постоянно перебирают.
Чтобы не потерять доступ при изменении sshd_config, не закрывайте текущую сессию, пока не проверите вход второй. И сначала запускайте sshd -t: ошибка в конфиге может не дать подключиться после перезапуска.