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 -e | crontab -e | Редактировать свой crontab (откроется редактор из $EDITOR). |
| crontab -l | crontab -l | Показать свой crontab. |
| crontab -r | crontab -r | Удалить весь crontab (без подтверждения, осторожно). |
| crontab -u | sudo crontab -u deploy -l | Работа с crontab другого пользователя (нужны права root). |
| crontab -i | crontab -ri | Удалять с подтверждением. |
| /etc/cron.d/ | /etc/cron.d/backup | Системные задания с полем пользователя (шестое поле). |
| /etc/cron.daily | ls /etc/cron.daily | Скрипты, которые запускаются раз в день через run-parts. |
| /var/log/syslog | grep 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-таймеры
| Команда | Вариант | Что делает |
| at | echo "./job.sh" | at now + 5 minutes | Одноразовое задание через 5 минут (пакет at). |
| at -f | at -f job.sh 23:00 tomorrow | Взять команды из файла, выполнить завтра в 23:00. |
| atq | atq | Список запланированных задач at. |
| atrm | atrm 12 | Удалить задачу с номером 12. |
| systemctl list-timers | systemctl list-timers --all | Расписание systemd-таймеров: когда запустится и когда последний раз. |
| systemd-run | sudo systemd-run --on-calendar="*-*-* 04:00" /usr/local/bin/job.sh | Создать временное задание на расписании systemd. |
| systemd-run --scope | systemd-run --user --scope -p MemoryMax=512M ./heavy.sh | Запустить с ограничением памяти. |
SSH: ключи
| Команда | Вариант | Что делает |
| ssh-keygen | ssh-keygen -t ed25519 -C "ivan@laptop" | Создать ключ Ed25519 (рекомендуемый тип). |
| ssh-keygen -b | ssh-keygen -t rsa -b 4096 | RSA-ключ, если Ed25519 не поддерживается. |
| ssh-keygen -f | ssh-keygen -t ed25519 -f ~/.ssh/deploy_key | Указать имя файла. |
| ssh-keygen -p | ssh-keygen -p -f ~/.ssh/id_ed25519 | Сменить парольную фразу ключа. |
| ssh-keygen -l | ssh-keygen -lf ~/.ssh/id_ed25519.pub | Отпечаток ключа. |
| ssh-keygen -R | ssh-keygen -R server.example.com | Удалить старый ключ хоста из known_hosts (после переустановки сервера). |
| ssh-copy-id | ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host | Добавить публичный ключ в authorized_keys на сервере. |
| ssh-copy-id -p | ssh-copy-id -p 2222 user@host | Нестандартный порт. |
| ssh-agent | eval "$(ssh-agent -s)" | Запустить агент, который держит расшифрованный ключ. |
| ssh-add | ssh-add ~/.ssh/id_ed25519 | Добавить ключ в агент (введёте парольную фразу один раз). |
| ssh-add -l | ssh-add -l | Ключи, загруженные в агент. |
| ssh-add -D | ssh-add -D | Удалить все ключи из агента. |
SSH: подключение и команды
| Команда | Вариант | Что делает |
| ssh | ssh ivan@server.example.com | Подключиться. |
| ssh -p | ssh -p 2222 ivan@server | Нестандартный порт. |
| ssh -i | ssh -i ~/.ssh/deploy_key deploy@server | Указать ключ. |
| ssh -t | ssh -t server 'sudo systemctl status nginx' | Выделить терминал, нужен для sudo с запросом пароля или интерактивных программ. |
| ssh cmd | ssh server 'df -h /' | Выполнить одну команду и выйти. |
| ssh -v | ssh -vvv server | Отладка подключения (аутентификация, ключи, порт). |
| ssh -o | ssh -o ConnectTimeout=5 -o BatchMode=yes server true | Проверка доступа в скриптах: без запросов, с таймаутом. |
| ssh -J | ssh -J bastion.example.com internal-db | Подключиться через jump-хост (ProxyJump). |
| ssh -N | ssh -N -f -L 5432:db:5432 bastion | Только туннель, без команды; -f уводит в фон. |
| ssh -4 / -6 | ssh -4 server | Принудительно IPv4 или IPv6. |
| ssh -X | ssh -X server | Перенаправить X11 (графические программы на сервере). |
| ssh -A | ssh -A bastion | Переслать агент ключей. Включайте только для доверенных хостов. |
SSH: туннели
| Команда | Вариант | Что делает |
| ssh -L | ssh -L 8080:localhost:80 user@server | Локальный порт 8080 ведёт на порт 80 сервера (он доступен только с вашей машины). |
| ssh -L remote | ssh -L 5432:db.internal:5432 bastion | Доступ к внутренней базе через bastion. |
| ssh -R | ssh -R 9000:localhost:3000 user@public | Порт 9000 на публичном сервере ведёт на ваш localhost:3000. |
| ssh -D | ssh -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 ~/.ssh | chmod 700 ~/.ssh | Папка с ключами доступна только владельцу. |
| chmod 600 ключ | chmod 600 ~/.ssh/id_ed25519 | Приватный ключ. Без этого ssh откажется работать. |
| chmod 600 authorized_keys | chmod 600 ~/.ssh/authorized_keys | Файл разрешённых ключей на сервере. |
| sshd -t | sudo sshd -t | Проверить синтаксис sshd_config перед перезагрузкой службы. |
| systemctl reload sshd | sudo systemctl reload ssh | Применить изменения конфига sshd (на Debian служба называется ssh). |
| sshd_config | PermitRootLogin no ; PasswordAuthentication no | Отключить вход root и вход по паролю (сначала убедитесь, что ключи работают). |
| who / last | last -i | head | Кто и с каких адресов заходил по SSH. |
| journalctl -u ssh | sudo 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: ошибка в конфиге может не дать подключиться после перезапуска.