Бот на сервере круглосуточно

В прогоне курса бот «Кодиума» две недели жил бы на ноутбуке, если бы не одна мелочь: ноутбук закрывают на ночь. Заявка, отправленная в 23:40, уходит в пустоту, потому что программа, которая её принимает, спит вместе с компьютером. Владельцу школы нужен бот, который отвечает и ночью, и в выходные. Для этого бот переезжает на сервер.

Чему научишься в этом уроке:
• объяснить заказчику, почему бот живёт на сервере за рубежом, и показать замер;
• арендовать сервер Timeweb Cloud и войти на него по SSH-ключу;
• поручить агенту выкладку: отдельный пользователь, закрытый .env и служба, которая поднимает бота сама;
• проверить бота перезагрузкой сервера и поправить часовой пояс.

Сервер: компьютер, который не выключают

Представь камеру хранения на вокзале, только с розеткой и интернетом: ты арендуешь ячейку, кладёшь туда свою программу, и она работает круглые сутки, пока ты спишь. Такой арендованный компьютер в чужом здании называется сервером (слово уже было в словаре урока 0.3). Экрана и мышки у него нет: управляют им из своего терминала по защищённому каналу.

Почему не сервер в России

Сначала мы поставили бота «Кодиума» на сервер Timeweb Cloud в Новосибирске. Логика простая: данные учеников лучше держать в России. Агент выложил бота за один проход, служба запустилась. А потом бот перестал отвечать на /start.

Замер показал причину. Мы 20 раз подряд спросили Telegram «ты здесь?» (запрос getMe). С сервера в Новосибирске успешно прошли 10 из 20, остальные ждали ответа 10–15 секунд и обрывались. С домашнего компьютера в тот же час было 20 из 20. Яндекс с того же сервера открывался мгновенно, значит дело не в самом сервере, а в дороге до Telegram. В журнале бота стояло TelegramNetworkError: Request timeout error.

Тогда бот переехал на сервер Timeweb Cloud в Амстердаме: там тот же замер дал 20 из 20, а Яндекс Диск по-прежнему доступен. Чтобы не держать персональные данные за рубежом, бот их на сервере не хранит: имя и телефон проходят через него и сразу уходят в файл заявок на Яндекс Диске заказчика (это ты настроил в уроке 2.4). На сервере остаются только номер заявки, курс и даты, а в запасном pending.jsonl только номер, курс и время.

Это не юридическая консультация. Схема «сервер за рубежом, данные на Диске в России» снижает риск, но кто отвечает за персональные данные и что ещё нужно сделать по 152-ФЗ, решает заказчик со своим юристом. Твоя задача: честно описать заказчику, где что лежит.
Инфографика из двух столбцов. Слева «Новосибирск»: 20 запросов к Telegram, 10 зелёных (успешно) и 10 красных (таймаут 10–15 с), подпись «бот перестал отвечать на /start». Справа «Амстердам»: 20 зелёных из 20. Внизу общая строка: «Яндекс Диск доступен с обоих серверов».

Почему боту не нужен домен

Бот может узнавать о новых сообщениях двумя способами. Long polling («долгий опрос»): бот сам раз за разом спрашивает Telegram «есть новое?». Вебхук: Telegram сам стучится к боту, и для этого у бота должен быть адрес сайта с защищённым соединением HTTPS.

Наш бот работает опросом, поэтому ему не нужны ни домен, ни HTTPS, ни открытый порт. Если заказчик когда-нибудь попросит вебхук, как ставятся домен и HTTPS, разобрано в уроке трека 2 про установку на сервер.

Шаг 1. Арендуй сервер

  1. Зарегистрируйся в Timeweb Cloud, раздел «Облачные серверы». Оплата в рублях.
  2. Регион выбери за рубежом: в прогоне был Амстердам.
  3. Система: Ubuntu 24.04 (Ubuntu это бесплатная разновидность Linux, самая частая на серверах). Боту хватает маленького сервера: в прогоне было 1 ядро и 1,9 ГБ памяти.
  4. Цены на 09.10.2026: самый дешёвый видимый тариф Cloud-40 (2 ядра, 2 ГБ, 40 ГБ) стоит 900 ₽ в месяц при оплате за год, помесячно около 1 000 ₽. Ещё два тарифа на странице спрятаны под «Показать ещё», их мы не раскрывали. Оплата почасовая: точную цену смотри в счёте Timeweb. Сервер списывает деньги, пока существует; учебный удали после миссии 2.8, если он не нужен заказчику.

Создание сервера по кнопкам, со снимками экрана, пройдено руками в уроке трека 2 про установку на сервер. Дойди там до шага, где сервер получил адрес, и возвращайся.

Шаг 2. Вход по SSH-ключу

Пароль похож на кодовый замок: подсмотрел цифры и вошёл. SSH-ключ похож на обычный ключ с замком. Замок (открытая половина ключа) висит на сервере, а сам ключ (закрытая половина) лежит только на твоём компьютере. SSH расшифровывается как «защищённая оболочка»: это защищённый канал, по которому ты управляешь сервером из терминала. В прогоне вход был только по ключу.

Ключ создаётся одной командой в PowerShell. На вопросы можно нажимать Enter:

ssh-keygen -t ed25519

Открытую половину (файл с окончанием .pub в папке .ssh твоего пользователя) вставь в панель Timeweb в раздел SSH-ключей при создании сервера. Закрытую не отправляй никому, даже агенту в чат. Проверка входа в PowerShell:

ssh root@<адрес сервера>

При первом входе ssh спросит, доверять ли серверу, и покажет его отпечаток. Набери yes и Enter, это нормально. Получилось войти, значит ключ работает. Набери exit: дальше на сервер ходит агент.

Шаг 3. Поручи выкладку агенту

Перед заданием останови бота у себя на компьютере: закрой окно, где он запущен, или нажми в нём Ctrl+C. Две копии бота одновременно спорят за сообщения Telegram, и бот на сервере начинает отвечать через раз. В прогоне первая просьба «выложи на сервер» закончилась странно: агенту не разрешили запускать команды, и он молча написал файлы-инструкции вместо выкладки. У тебя Claude Code спросит разрешение на каждую команду. Читай, что он собирается выполнить, и подтверждай (урок 1.7).

Вот задание прогона дословно, только адрес заменён. Последнюю строку курс добавил после того случая с файлами-инструкциями:

Теперь выложи бота на мой сервер, чтобы он работал круглосуточно без моего компьютера.
Сервер: Ubuntu 24.04, адрес <адрес сервера>, вход: ssh root@<адрес сервера> (ключ у меня уже настроен, пароль не нужен).
Как сделать:
- создай на сервере отдельного пользователя bot (не запускай бота от root), папка /opt/bot-kodium;
- скопируй туда файлы проекта по scp, КРОМЕ .venv, zayavki.db, логов и кэшей; файл .env скопируй отдельно и поставь права 600;
- создай на сервере виртуальное окружение и поставь зависимости из requirements.txt;
- сделай службу systemd bot-kodium: запуск от пользователя bot, автоперезапуск при падении, автозапуск после перезагрузки;
- запусти службу и покажи её статус и последние строки журнала (journalctl).
Локально бот сейчас остановлен — двух копий одновременно быть не должно. Добавь в README раздел «Как выложить на сервер и как обновить».
Выполни сам, не пиши инструкции вместо выполнения.

Что здесь что, по-простому:

  • КРОМЕ .venv и zayavki.db. .venv собран под Windows и на Ubuntu не заработает, сервер делает свой. zayavki.db это файл твоей локальной базы с тестовыми заявками, на сервере бот заведёт новую.
  • Пользователь bot. Жилец с ключом только от своей комнаты. Если в боте найдут дыру, взломщик получит комнату, а не весь дом (root).
  • Права 600 на .env. Конверт, который может вскрыть только владелец. В файле лежат токен бота и токен Диска, правила те же, что в уроке 1.6.
  • Служба systemd. Вахтёр сервера: запускает бота при включении и поднимает снова, если тот упал.
  • Раздел README. Пригодится в уроке 2.6, когда будешь передавать бота.

Что должно получиться на сервере: файл службы /etc/systemd/system/bot-kodium.service. Набирать его не нужно, агент пишет его сам; сверься, что строки похожи:

[Unit]
Description=Telegram Bot Kodium
After=network.target

[Service]
Type=simple
User=bot
WorkingDirectory=/opt/bot-kodium
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/bot-kodium/.venv/bin/python bot.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

User=bot значит «от имени пользователя bot», Restart=always значит «поднимать после падения», а WantedBy=multi-user.target включает автозапуск при старте сервера.

Шаг 4. Проверь перезагрузкой

Служба, которая «вроде запущена», и служба, которая переживает перезагрузку, это разные вещи. В прогоне проверка была жёсткой: сервер перезагрузили, подождали минуту и снова вошли. Войди сам: ssh root@<адрес сервера> в PowerShell. Команду ниже набирай уже в этом окне, после входа на сервер, а не на своём компьютере. Соединение после неё оборвётся, так и должно быть.

reboot

Подожди минуту, снова войди по ssh и набери три команды проверки из прогона:

systemctl status bot-kodium
journalctl -u bot-kodium -n 20
systemctl is-enabled bot-kodium

Как читать ответ. active (running) в строке Active значит «служба работает». inactive (dead) значит «служба не запущена». enabled в ответе третьей команды значит «включён автозапуск после перезагрузки». Вторая показывает последние 20 строк журнала бота: там видны ошибки. Потом напиши боту /start с телефона: он должен ответить.

Снимок терминала сервера: вывод systemctl status bot-kodium — строка Loaded с пометкой enabled, зелёная строка Active: active (running), процесс /opt/bot-kodium/.venv/bin/python bot.py; ниже строки журнала «Файл успешно скачан», «Файл успешно загружен», «Заявка успешно сохранена на Яндекс Диск»; в конце systemctl is-enabled bot-kodium отвечает enabled. Адрес сервера и ссылки Диска скрыты.

Часы сервера идут по всемирному времени UTC, это на 3 часа раньше московского. В прогоне бот записал время согласия на 3 часа раньше настоящего. Для заказчика это не мелочь: в споре о согласии дата важна.

В прогоне агент поправил это так: время берётся в поясе Europe/Moscow (часовой пояс Москвы) через модуль zoneinfo, и в уведомлении стало «Согласие: 09.10.2026 16:42 МСК». Пакет tzdata, без которого этот код не работает на Windows, ты добавил в уроке 2.4. Задание агенту:

Время согласия бери в поясе Europe/Moscow через zoneinfo и пиши в уведомлении с пометкой МСК. Проверь, что tzdata есть в requirements.txt. Обнови бота на сервере и перезапусти службу bot-kodium, выполни сам.

Запасной путь: Railway

Railway запускает бота без своего сервера: пробный период с разовыми 5 $ на 30 дней без карты, тариф Hobby 5 $ в месяц (цены на 09.10.2026). Платить только в долларах, картой российского банка не получится, поэтому основной путь курса Timeweb.

Если не получилось

  • Агент написал deploy.ps1, DEPLOY.md и прочее, а на сервере пусто → ему не дали выполнить команды → скажи «выполни сам» и подтверждай запросы разрешений.
  • Бот на сервере отвечает через раз, в журнале слово Conflict → бот запущен ещё и у тебя на компьютере → закрой локальное окно бота.
  • В журнале TelegramNetworkError: Request timeout error, бот молчит на /start → дорога до Telegram рвётся (так было в Новосибирске) → проверь регион сервера, переезжай за рубеж.
  • После reboot статус inactive (dead) → служба не включена в автозапуск → systemctl is-enabled bot-kodium; если не enabled, попроси агента включить автозапуск и повтори перезагрузку.
  • Время согласия на 3 часа раньше → сервер в UTC → время через zoneinfo с поясом Europe/Moscow.
  • ssh просит пароль вместо ключа → открытая половина ключа не попала на сервер → добавь её в панели Timeweb и пересоздай вход.

Контрольный вопрос. Заказчик спрашивает: «Почему не сервер в России? Так же проще с законом». Что ответить по фактам прогона?

АРоссийские серверы дороже зарубежных в несколько раз
БTimeweb не сдаёт серверы в России новым клиентам
ВС сервера в Новосибирске до Telegram доходила половина запросов, бот переставал отвечать; данные при этом лежат на Яндекс Диске в России
ГНа российском сервере нельзя поставить Ubuntu

Подсказка: Вспомни замер getMe: сколько из 20 и где.

На курсе задания проверяются автоматически. Решить первое задание бесплатно →  ·  Подобрать курс

Контрольный вопрос. Ты перезагрузил сервер, вошёл снова, а бот не отвечает на /start. Статус службы: inactive (dead). Что проверить первым?

АНе истёк ли токен бота у BotFather
БХватает ли серверу памяти
ВПравильный ли часовой пояс на сервере
ГВключена ли служба в автозапуск: systemctl is-enabled bot-kodium

Подсказка: До перезагрузки бот работал. Что отвечает за запуск после включения сервера?

На курсе задания проверяются автоматически. Решить первое задание бесплатно →  ·  Подобрать курс

Контрольный вопрос. Бот на сервере в Амстердаме пишет в уведомлении время согласия 13:42, а заявку отправили в 16:42 по Москве. Как починить?

АПеревести часы на компьютере ученика
ББрать время через zoneinfo с поясом Europe/Moscow и добавить tzdata в зависимости
ВПереехать на сервер в Москве
ГВычитать 3 часа вручную в файле заявок

Подсказка: На сколько часов UTC отстаёт от Москвы и что сделал агент в прогоне?

На курсе задания проверяются автоматически. Решить первое задание бесплатно →  ·  Подобрать курс

Задание. МИССИЯ «Бот не спит». 1. Арендуй сервер Timeweb Cloud за рубежом (Ubuntu 24.04) и войди по SSH-ключу. 2. Останови бота у себя и поручи агенту выкладку заданием из урока. 3. Сломай и почини: перезагрузи сервер командой reboot и дождись, что бот поднялся сам. Если не поднялся, найди причину по разделу «Если не получилось». 4. Отправь боту тестовую заявку и проверь время согласия в уведомлении. Принято, если: приложен снимок systemctl status bot-kodium после перезагрузки со строкой active (running) и вывод systemctl is-enabled bot-kodium со словом enabled; снимок уведомления владельцу, где время согласия совпадает с московским и стоит МСК; одна фраза, какой регион сервера ты выбрал и почему. Адрес сервера, токены и телефон на снимках закрыты.

Подсказка: Сначала заставь бота пережить reboot, потом занимайся временем: это две разные поломки.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

На курсе задания проверяются автоматически. Решить первое задание бесплатно →  ·  Подобрать курс

Что дальше

Бот работает круглые сутки без твоего ноутбука. Следующий шаг: передать его заказчику так, чтобы он мог жить без тебя, и оформить работу в кейс.

Итог:
• бот живёт на сервере Timeweb за рубежом, персональные данные уходят на Яндекс Диск;
• служба systemd поднимает бота сама, это проверено перезагрузкой;
• время согласия пишется по Москве, tzdata в зависимостях.

← Назад  ·  ↑ В начало урока  ·  ⌂ В начало курса  ·  Вперёд →

Школа Виктора Комлева