<!-- Bothost docs | HTML: https://bothost.ru/docs/works-locally-fails-on-server | Markdown: https://bothost.ru/docs/works-locally-fails-on-server.md | Index: https://bothost.ru/llms.txt -->

# Бот работает локально, но падает на сервере: ModuleNotFoundError и restarting

На компьютере бот отвечает, после деплоя на Bothost контейнер уходит в `restarting` или сразу `exited`. Ниже Python `ModuleNotFoundError`, отсутствующий `.env`, неверный главный файл и то, как отличить это от ошибок Node `MODULE_NOT_FOUND`.

> **Для людей и ИИ.** Каноническая страница: https://bothost.ru/docs/works-locally-fails-on-server · Markdown: https://bothost.ru/docs/works-locally-fails-on-server.md · Индекс: https://bothost.ru/llms.txt
> Отвечает на запросы: bot works locally but not on server, bot crashes after deployment, ModuleNotFoundError, No module named, ImportError, attempted relative import, can't open file, KeyError BOT_TOKEN, container restarting.
> Node.js `Cannot find module '/app/dist/...'` и `Cannot find module '/app/index.js'` разобраны отдельно: [справочник ошибок при деплое](common-errors).

---

## Как устроен запуск на Bothost

Контейнер — Linux. В него попадает код из Git или из архива, зависимости ставятся на сборке из `requirements.txt` или `package.json`. Локальное виртуальное окружение, пакеты из `pip install` «просто в систему» и файл `.env` с вашего диска в контейнер не копируются.

Платформа передаёт токен и служебные переменные сама: `BOT_TOKEN`, `API_TOKEN`, `TELEGRAM_BOT_TOKEN`, для Discord `DISCORD_BOT_TOKEN`, плюс `PORT`, `DATA_DIR=/app/data` и при включённом домене `WEBHOOK_URL`. Полный список: [переменные окружения](environment-variables).

Сборка и запуск — разные логи.

| Что открыть | О чём говорит |
|---|---|
| Логи сборки | `pip install`, `npm ci`, ошибка Dockerfile. Пока сборка красная, процесс бота ещё не стартовал |
| Логи работы | Первая ошибка после старта процесса: импорт, нет файла, нет переменной, синтаксис |

Сообщение об успешной сборке значит только то, что образ собрался. Падение в логах работы при зелёной сборке — тема этой статьи.

---

## Сначала статус

Пока контейнер в `restarting`, бот не может отвечать в Telegram, держать webhook или писать в базу. Ищите в логах работы **первую** строку traceback в цикле и сопоставьте её с разделами ниже. Повтор той же ошибки каждые несколько секунд — процесс стартует и сразу завершается, Docker поднимает его снова.

---

## ModuleNotFoundError

### Как выглядит

```text
ModuleNotFoundError: No module named 'aiogram'
```

Варианты той же ситуации: `No module named 'dotenv'`, `No module named 'PIL'`, `No module named 'handlers'`. Сборка при этом часто успешна: `pip` отработал по тому `requirements.txt`, который был в репозитории, и пакета там не было.

### Почему локально пакет есть

На компьютере библиотека стоит в venv или в пользовательском site-packages. На Bothost ставится только то, что перечислено в **корневом** `requirements.txt` (или объявлено в `pyproject.toml`). Команда сборки:

```bash
pip install --no-cache-dir -r requirements.txt
```

Имя в файле и имя в `import` часто различаются:

| В requirements.txt | В коде |
|---|---|
| `python-dotenv` | `import dotenv` |
| `Pillow` | `import PIL` |
| `python-telegram-bot` | `import telegram` |
| `pyTelegramBotAPI` | `import telebot` |
| `discord.py` | `import discord` |

Если в файле нет строки, в контейнере нет модуля, даже если на вашей машине `python -c "import aiogram"` проходит.

### Что сделать

1. Добавьте пакет в корневой `requirements.txt` и зафиксируйте версию, с которой бот проверен локально:

```text
aiogram==3.13.1
python-dotenv==1.0.1
```

Без версии на сборке может приехать другой мажор, и падение будет уже на `ImportError` внутри библиотеки, а не на `No module named`.

2. Задеплойте заново. Рестарт контейнера зависимости не доустанавливает: они попадают в образ только при сборке.
3. Убедитесь, что файл лежит в корне репозитория, а не только в подпапке, если бот собирается из корня.

Подробнее про форматы зависимостей Python, Java и Go: [установка библиотек](installing-libraries).

### ModuleNotFoundError на свой файл

```text
ModuleNotFoundError: No module named 'handlers'
```

Это уже не пакет с PyPI. Локально файл находится из-за того, что вы запускаете скрипт из папки проекта и IDE добавляет её в `sys.path`. В контейнере рабочий каталог `/app`, а пакет не является пакетом: нет запуска как модуля, или импорт написан относительно запускаемого файла.

```text
ImportError: attempted relative import with no known parent package
```

появляется, когда файл с `from .handlers import router` запустили как скрипт (`python bot.py`), а не как модуль (`python -m package.bot`). На Bothost команда запуска — это главный файл из настроек. Либо укажите запуск модулем через свой Dockerfile ([кастомный Dockerfile](custom-dockerfile)), либо замените относительные импорты на импорты от корня проекта, который реально есть в `/app`.

Регистр букв на Linux важен. `import Config` не откроет `config.py`. Windows такой импорт часто прощает. Переименуйте файл и импорт в один регистр и задеплойте снова.

---

## bot crashes after deployment

### Нет переменной, которая локально приходит из .env

```text
KeyError: 'BOT_TOKEN'
Token is invalid or not found
```

Локально токен берётся из `.env` через `python-dotenv` или из переменных IDE. Файл `.env` обычно в `.gitignore`, в клон на сервере он не входит. `load_dotenv()` молча ничего не загружает, следующая строка падает.

На Bothost токен уже лежит в `BOT_TOKEN`. Читайте его напрямую:

```python
import os

token = os.environ["BOT_TOKEN"].strip()
```

Дополнительные секреты (`OPENAI_API_KEY` и подобные) добавьте в разделе переменных окружения бота в панели, затем перезапустите контейнер. Коммитить их в репозиторий не нужно.

Если имя в коде другое (`TOKEN`, `TG_BOT_TOKEN`), заведите в панели переменную с этим именем или поменяйте код на `BOT_TOKEN`.

### Неверный главный файл

```text
python: can't open file '/app/bot.py': [Errno 2] No such file or directory
```

В настройках бота или в `CMD` указан файл, которого нет в корне. Код лежит во вложенной папке (`mybot/bot.py`), а поле «Главный файл» пустое или содержит `bot.py`. Укажите путь от корня репозитория, например `mybot/bot.py`, и задеплойте снова. Как платформа выбирает точку входа: [главный файл](main-file-entrypoint).

Для Node та же ситуация даёт `Cannot find module '/app/index.js'`. Это отдельный разбор в [справочнике ошибок](common-errors), вместе с пропадающим `dist/` при `WORKDIR /app`.

### Синтаксис и версия Python

```text
SyntaxError: invalid syntax
TypeError: ... unexpected keyword argument
```

Образ Python на платформе может отличаться от версии на компьютере. Конструкция, которая есть только в более новой версии, валит процесс на первой строке. Зафиксируйте совместимый код или соберите образ со своей версией через [Dockerfile](custom-dockerfile). В логе сборки видно, какой интерпретатор ставит зависимости.

### Процесс сразу завершается без ошибки

В логе есть ваш `print` и больше ничего, статус `exited` или `restarting`. Скрипт дошёл до конца: нет `start_polling`, `client.run`, `app.run` или другого бесконечного цикла. Локально вы этого не замечаете, потому что следом смотрите в консоль и запускаете снова. Бот на сервере должен оставаться запущенным процессом, а не одноразовым скриптом.

---

## bot works locally but not on server

Если процесс всё же `running`, а не падает, это уже не импорт. Сверьте поведение, которое на компьютере маскируется окружением:

- токен и режим апдейтов: [бот не отвечает](bot-not-responding);
- webhook на `localhost` локально не проверяется, на сервере Telegram ходит на публичный HTTPS: [ошибки webhook](telegram-webhook-errors);
- база в папке проекта жива на диске компьютера и пустая в новом контейнере: [SQLite пропала](sqlite-data-lost);
- исходящий вызов к нейросети таймаутится из-за региона IP ноды: в [справочнике ошибок](common-errors) раздел про DeepSeek, Gemini, OpenAI и Claude.

---

## Порядок в логах

1. Логи сборки зелёные, в них есть `pip install` по вашему `requirements.txt`.
2. Логи работы: первая строка traceback совпадает с одним разделом выше.
3. После правки файла зависимостей или главного файла сделан новый деплой, а не только рестарт.
4. Статус держится `running`, в логе есть строка старта polling или HTTP-сервера.

---

## См. также

- [Справочник ошибок при деплое](common-errors) (`MODULE_NOT_FOUND`, `dist/`, вложенный `index.js`)
- [Установка библиотек](installing-libraries)
- [Главный файл](main-file-entrypoint)
- [Переменные окружения](environment-variables)
- [Кастомный Dockerfile](custom-dockerfile)

**В логе другая ошибка?** Пришлите первую строку traceback в поддержку: [@bothostru](https://t.me/bothostru).
