<!-- Bothost docs | HTML: https://bothost.ru/docs/custom-dockerfile | Markdown: https://bothost.ru/docs/custom-dockerfile.md | Index: https://bothost.ru/llms.txt -->

# Кастомный Dockerfile на Bothost

Эта статья для случаев, когда стандартной автонастройки недостаточно и вы хотите полностью контролировать сборку и запуск контейнера.

---

## Когда нужен кастомный Dockerfile

Используйте свой `Dockerfile`, если вам нужно:

- установить системные пакеты (`apt`, `apk`) или нестандартные зависимости;
- делать многоэтапную сборку (build stage + runtime stage);
- явно контролировать команду запуска (`CMD`/`ENTRYPOINT`);
- запускать веб-приложение вместе с ботом на конкретном порту;
- использовать собственную структуру проекта, которую автоопределение не покрывает.

Если ваш проект простой (например, Python-бот с `requirements.txt`), чаще всего достаточно стандартного сценария деплоя без кастомного Dockerfile.

## Как включить свой Dockerfile

1. Положите файл `Dockerfile` в **корень** репозитория.
2. В форме создания или редактирования бота откройте блок **«Дополнительные настройки»**.
3. Включите галочку **«Использовать собственный Dockerfile»**.

![Галочка «Использовать собственный Dockerfile» в дополнительных настройках бота](/docs/images/custom-dockerfile-checkbox.png)

После этого система будет собирать образ по вашему `Dockerfile` вместо автоматически сгенерированного.

## Базовые требования Bothost

Чтобы контейнер корректно работал с доменом/webhook на платформе:

- приложение должно слушать `0.0.0.0`, а не `127.0.0.1`;
- порт должен браться из переменной окружения `PORT`;
- в настройках бота внутренний порт должен совпадать с портом, который реально слушает приложение;
- после изменения порта/домена нужен повторный деплой.

Для веб-сервисов (FastAPI, Express и т.д.) это критично: иначе получите `502/504` даже при успешной сборке.

## Минимальный шаблон для Python (бот + веб endpoint)

```dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Приложение должно читать PORT из env и слушать 0.0.0.0
CMD ["python", "main.py"]
```

## Минимальный шаблон для Node.js

```dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

# Приложение должно читать PORT из env и слушать 0.0.0.0
CMD ["node", "index.js"]
```

## Минимальный шаблон для Go (multi-stage)

```dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /usr/local/bin/bot .

FROM alpine:3.20
RUN apk --no-cache add ca-certificates
WORKDIR /app
# Бинарник кладём в /usr/local/bin/, а не в /app —
# иначе он будет скрыт bind mount'ом при деплое.
# Данные (БД и т.д.) храним в /app/data как обычно.
COPY --from=builder /usr/local/bin/bot /usr/local/bin/bot
RUN mkdir -p /app/data && chmod 777 /app/data
CMD ["/usr/local/bin/bot"]
```

> **Важно для Go и других компилируемых языков:** на Bothost каталог `/app`
> при запуске контейнера монтируется с исходниками из Git. Бинарник, скомпилированный
> в образе и положенный в `/app`, будет скрыт этим mount'ом и не найдётся при старте.
> Всегда кладите бинарники в `/usr/local/bin/` или другой путь вне `/app`.
> Подробнее: [Справочник ошибок при деплое](common-errors).

## Типовые ошибки

- Приложение слушает `localhost` вместо `0.0.0.0`.
- Порт захардкожен в коде, а не берётся из `PORT`.
- `CMD` запускает не тот файл/бинарник.
- Нужные файлы не копируются в образ (`COPY` неполный).
- Сборка успешна, но процесс сразу падает при старте (смотрите runtime-логи, а не только build-логи).
- **`Cannot find module '/app/dist/...'`** при успешной сборке — часто из‑за `WORKDIR /app` и артефактов сборки (`dist/`, `build/`), которые не попадают в примонтированный с Git каталог `/app`. Решение: перенести `WORKDIR` в путь вне `/app` (например `/usr/src/app`), данные оставить в `/app/data`. Подробно: [Справочник ошибок при деплое](common-errors).

## Чеклист перед деплоем

- `Dockerfile` лежит в корне репозитория.
- Команда запуска стартует долгоживущий процесс (а не одноразовый скрипт).
- Для веб-приложения есть обработчик `health` (или понятный endpoint для проверки).
- Сервис поднимается локально с переменной `PORT`:

```bash
PORT=8080 docker run --rm -p 8080:8080 <image>
```

- После пуша выполнен деплой и проверены:
  - логи сборки,
  - логи запуска,
  - доступность домена/вебхука.

---

## См. также

- [Работа с доменами и портами](domains-and-ports)
- [Веб-приложения и домены](web-apps-domains)
- [Установка библиотек: Python, Java и Go](installing-libraries)
- [Главный файл (точка входа)](main-file-entrypoint)
- [Справочник ошибок при деплое](common-errors)
- [FAQ](faq)
