GithubHelp home page GithubHelp logo

alpogold / server_instruction_nginx_tb Goto Github PK

View Code? Open in Web Editor NEW

This project forked from evgeny-jem/server_instruction

0.0 0.0 0.0 128 KB

Instructions for setting up a Linux server (Ubuntu/Debian) for the Telegram bot (FastAPI + Uvicorn webhook). Stack: Git, Docker, docker-compose, Postgres, Redis, Nats, Pyenv, Cron

Dockerfile 100.00%

server_instruction_nginx_tb's Introduction

Настраиваем сервер Linux (Ubuntu/Debian) под ТГ-бота вебхук (FastAPI + Uvicorn).

Стэк для бота: Postgres, Redis, Nats и др..
Стэк на сервере: Git, Docker (docker-compose), Nginx, Certbot, Pyenv, Cron
Cron и Pyenv были мной добавлены отдельно, а не в докере, так как не разобрался с корректным запуском крона в докере, при котором можно смотреть логи крона. Если вы знаете, как корректно запускать крон в докере, буду признателен за комментарии. (https://t.me/EVGENIY_JEM)

Я понимаю, что в эпоху GPT многие инструкции становятся не нужны, но чтобы сэкономить время, в первую очередь самому себе, я набросал мануал, который выполнил на последнем проекте.
ВАЖНОЕ ЗАМЕЧАНИЕ! Я не считаю себя профессионалом и не считаю, что мой способ самый лучший и корректный. Данный мануал - это лишь личный опыт, а я не претендую на истину в последней инстанции.

1. Обновляем системные пакеты:

sudo apt update
sudo apt dist-upgrade
sudo apt upgrade

2. Устанавливаем Git, Docker, и Nginx, и другие:

sudo apt install git docker.io nginx docker-compose
sudo apt install -y build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-openssl
sudo systemctl enable docker

3. Настраиваем брандмауэр:

Для того, чтобы серевер Telegram API мог достучаться до нашего бота, необходимо, чтобы были открыты входящие соединения.

sudo ufw allow 'Nginx Full'

Данная команда открывает входящий трафик по протоколу http и https.

4. Запускаем Nginx:

nginx - это веб-сервер, который мы будем использовать для проксирования запросов от Telegram API к вашему вебхуку.

sudo systemctl enable nginx
sudo systemctl start nginx 
systemctl status nginx

В выводе команды вы должны увидеть что-то вроде Active: active (running)

5. Настройка Nginx:

a. Создайте файл конфигурации для вашего сайта в /etc/nginx/sites-available/:

sudo nano /etc/nginx/sites-available/example.com

b. Добавьте следующее содержимое в файл конфигурации:

# Директивы для HTTP (80й порт)
server {
  listen 80; # Слушать порт 80 (стандартный HTTP порт).
  server_name example.com; # Имя сервера (домен), для которого эта конфигурация применима.
}

# Директивы для HTTPS (443й порт)
server {
  listen 443 ssl; # Слушать порт 443 (стандартный HTTPS порт) с SSL.
  server_name example.com; # Имя сервера (домен), для которого эта конфигурация применима.
  
  # Пути к файлам сертификата и ключа.
  # Данный блок должен заполниться автоматически после настройки SSL из пункта 7
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  # Директивы для проксирования
  location / { # "location /"  - Определяет, как обрабатывать запросы к корневому URL (/)
    proxy_pass http://localhost:YOUR_BOT_PORT; # proxy_pass - Куда перенаправлять входящие запросы. Порт, на котором работает ваш Telegram бот
    # Параметры ниже необязательны
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Где example.com - это имя вашего домена, которое вам дал ваш хостинг.
Замените YOUR_BOT_PORT на порт, на котором работает ваш Telegram бот (который вы пробросили из Docker-контейнера на хост-машину).

c. Создайте символическую ссылку на этот файл в директории sites-enabled

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

d. Переименовать дефолтные настройки, во избежание конфликта. Либо закомментировать все строки в файле default:

sudo mv /etc/nginx/sites-enabled/default /etc/nginx/sites-enabled/default.backup

e. Проверьте конфигурацию Nginx:

sudo nginx -t 

Если все в порядке, вы должны увидеть сообщение: syntax is okay, test is successful

f. Перезапустите Nginx:

sudo systemctl restart nginx

6. Устанавливаем Certbot для работы с SSL:

sudo apt install certbot python3-certbot-nginx

7. Настройка SSL для Nginx:

a. Запускаем Certbot для настройки SSL:

sudo certbot --nginx -d example.com -d www.example.com

Если не сработал вариант выше, то пробуем командой, но уже внутри certbot прописываем ваш домен:

sudo certbot -–nginx

b. Следуем инструкциям, чтобы настроить SSL для вашего домена. Там не сложно.

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

8. Установка вебхука для Telegram-бота:

a. Обычно это делается внутри кода, в файле запуска бота. Задача дать понять Телеграму, что все обновления нужно слать вам на адрес вебхука. Но если вы не делали это в коде, то можно прямо с консоли отправить:

curl -F "url=https://YOUR_DOMAIN/YOUR_WEBHOOK_PATH" https://api.telegram.org/botYOUR_BOT_TOKEN/setWebhook

b. Проверить:

curl https://api.telegram.org/botYOUR_BOT_TOKEN/getWebhookInfo

В ответ должны быть показаны данные вашего вебхука

9. Для настройки докер контейнера делаем в корневой папке проекта файл Dockerfile:

# Используем официальный образ Python
FROM python:3.11.5

# Устанавливаем рабочую директорию в контейнере
WORKDIR /app

# Копируем зависимости и устанавливаем их
COPY requirements.txt .
RUN pip install --upgrade pip setuptools
RUN pip install -r requirements.txt
RUN chmod 755 .

# Копируем исходный код в контейнер
COPY . .

# Указываем команду для запуска приложения
CMD ["python", "app.py"] # Указываем название вашего главного файла

10. Также там-же делаем файл .dockerignore со следующим содержанием:

# Игнорируем каталоги с зависимостями и кэшем Python
__pycache__/
*.pyc
*.pyo
venv/

# Игнорируем файлы и каталоги Git
.git/

# Игнорируем каталог с логами
logs/

# Игнорируем временные директории и файлы
tmp/

# Осторожно с исключением файлов конфигурации и секретов.
# Если эти файлы необходимы для запуска вашего приложения, их исключение может привести к сбоям.
# *.config
# *.env
# *.secret

# Игнорируем директории и файлы, созданные IDE или текстовыми редакторами
.vscode/
.idea/

# Добавьте другие папки и файлы, которые не должны быть включены в ваш Docker-образ

11. Также там-же делаем файл .gitignore следующего содержания:

# Игнорируем каталоги с зависимостями и кэшем Python
__pycache__/
*.pyc
*.pyo
venv/

# Игнорируем локальные конфигурационные файлы и секреты
*.config
*.env
*.secret

# Игнорируем каталог с логами
logs/

# Игнорируем каталог с бинарными файлами и дистрибутивами
dist/
*.egg-info/

# Игнорируем IDE-специфичные файлы (например, для PyCharm)
.idea/
.vscode/


# Если есть тестовые данные, которые не должны попадать в репозиторий
# test_data/

# Добавьте другие папки и файлы, которые не должны быть включены в ваш Git-репозитарий

12. Также там-же делаем файл docker-compose.yml, в котором создаем наши службы, пробрасываем порты, перечисляем зависимости. Этот файл служит основой запуска вашего проекта.

Мой предыдущий проект имел файл со следующим содержанием: бот, база данных postgres, база данных redis, nats сервер и nats воркер (для взаимодействия с nats сервером) В 19м пункте смотрите, как собирался контейнер для nats сервера.

version: "3"
services:
  имя_службы_бота:
    build: .
    container_name: имя_службы_бота
    ports:
      - "8080:8080"
    command: [ "python", "app.py" ] # app.py - Название главного файла проекта
    depends_on:
      - nats_server  # указываем зависимость от NATS сервера
      - redis  # добавляем зависимость от Redis
      - postgres  # добавляем зависимость от PostgreSQL
    restart: always

  nats_worker:
    build: .
    container_name: nats_worker
    command: [ "python", "nats_worker.py" ]
    depends_on:
      - nats_server  # указываем зависимость от NATS сервера
      - redis  # добавляем зависимость от Redis
      - postgres  # добавляем зависимость от PostgreSQL
    restart: always
    
  # Имейте в виду, что в конфиг файле бота в .env или settings.toml, смотря что используете,
  # адрес хоста должен быть не 127.0.0.1, а именем службы из вашего docker-compose: NATS_HOST='nats_server'
  nats_server: # Добавляем NATS сервер как новую службу.
    build:
      context: .
      dockerfile: Dockerfile.nats  # Указываем путь к Dockerfile.nats в котором все настройки и параметры запуска (см. п.19)
    ports:
      - "4222:4222"  # открываем порт для внешних соединений
      - "6222:6222"
      - "8222:8222"  # Для HTTP мониторинга
    volumes:
      - "nats_data:/app/data"  # Папка для хранения данных (в моем случае в папку проекта в папке data)
    # - "nats_logs:/app/logs"  # Папка для логов (не обязательна)
    restart: always

  # Имейте в виду, что в конфиг файле бота в .env или settings.toml, смотря что используете,
  # адрес хоста должен быть не 127.0.0.1, а именем службы из вашего docker-compose: REDIS_HOST='redis'
  redis: # добавляем Redis сервер как новую службу
    image: "redis:latest"  # можно указать конкретную версию вместо latest
    volumes:
      - redis_data:/usr/local/etc/redis
    ports:
      - "6379:6379"  # открываем порт для внешних соединений
    restart: always

  # Имейте в виду, что в конфиг файле бота в .env или settings.toml, смотря что используете,
  # адрес хоста должен быть не 127.0.0.1, а именем службы из вашего docker-compose: POSTGRES_HOST='postgres'
  postgres: # добавляем PostgreSQL сервер как новую службу
    image: "postgres:latest"  # можно указать конкретную версию вместо latest
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${имя_переменной_из_env_файла}
      POSTGRES_USER: ${имя_переменной_из_env_файла}
      POSTGRES_PASSWORD: ${имя_переменной_из_env_файла}
    ports:
      - "5432:5432"  # открываем порт для внешних соединений
    restart: always

volumes:
  postgres_data:  # объявляем volume для постоянного хранения данных PostgreSQL. Если не указать, то при остановке docker-compose и повторного запуска, ваши файлы пропадут
  nats_data:
  redis_data:

13. Я использую Git (GitHub) в качестве репозитария и считаю хорошей привычкой все делать через него. Также это позволяет удобно и быстро разворачивать проекты в новом месте. Для себя избрал самый быстрый и надежный способ – использовать SSH ключ, поэтому моя инструкция ниже.

a. Далее создаем SSH ключ на сервере, если SSH ключ уже присутствует на сервер, то сразу к пункту “c”:

ssh-keygen -t rsa -b 4096 -C "ваша почта, с которой вы регались на github"

Просто нажимайте "Enter" для всех вопросов, если вы хотите использовать параметры по умолчанию.

b. Запуск SSH-агента и добавление вашего ключа:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa

c. Копирование SSH-ключа в буфер обмена. Команда выведет ваш публичный SSH-ключ. Скопируйте его в буфер обмена:

cat ~/.ssh/id_rsa.pub

d. Добавление нового SSH-ключа на GitHub:

Перейдите на GitHub и зайдите в "Settings" (находится в правом верхнем углу). В меню слева выберите "SSH and GPG keys" -> "New SSH key". Вставьте скопированный ключ в поле "Key" и дайте ему название.

14. Клонирование репозитория с использованием SSH:

a. Перейдите в папку, в которой вы планируете размещать свои проекты. Я обычно создаю папку apps и все проекты клонирую туда:

mkdir apps
cd apps

b. Запустите команду клонирования проекта, которую можно скопировать с GitHub, нажав зеленую кнопочку code, выбрав SSH:

git clone [email protected]:ваше_имя_пользователя_github/название_проекта.git

После этого сервер вас спросит, действительно ли доверяется этому ssh ключу, подтвердите и проект будет скопирован к вам на сервер в apps/название_проекта_из_github

15. Обновляемся, собираем и запускаем контейнер, смотрим логи:

a. Перейдите в папку с проектом (см п. 14)

cd apps/название_проекта

b. Если вы внесли какие-то изменения в проект и необходимо их применить на сервере (если контейнер уже запущен, то сначала остановить):

git pull

c. Остановить запущенный контейнер:

docker-compose down

d. Собрать и запустить контейнер (с указанными аргументами контейнер пересобирается и работает, если сервер будет перезагружен):

docker-compose up -d --build

e. Если необходимо зайти внутрь запущенного контейнера и провести там какие-то манипуляции:

docker exec -it container_id_or_name /bin/bash

f. Если вы хотите видеть логи приложения:

docker-compose logs -f имя_контейнера_из_docker-compose.yml  

16. Alembic.

Если в вашем проекте база данных, то таблицы должны быть размечены прежде, чем все заработает. Вы можете это сделать вручную, зайдя внутрь соответствующего контейнера (службы postgres из файла docker-compose.yml) или если вы используете миграцию от Alembic, то команды для запуска и разметки таблиц бд, не заходя внутрь контейнера:

a. Создание новой миграции:

docker exec -it container_id_or_name alembic revision --autogenerate -m "Initial migration"

b. Применение новой миграции:

docker exec -it container_id_or_name alembic upgrade head  

И не забудьте, что Alembic должен быть установлен в вашем контейнере. Если вы его добавляли в файл requirements.txt вашего проекта, то он конечно будет уже в контейнере.

17. Использование Pyenv (не для Docker, а именно на сервере).

Pyenv позволяет установить несколько версий Python и переключаться между ними, если нужно. Если бы вопрос с Cron я смог решить в docker-compose, то не стал бы этим заморачиваться:

a. Установка pyenv:

curl https://pyenv.run | bash 

b. Добавляем pyenv в $PATH:

echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
source ~/.bashrc

c. Теперь необходимо обновить файлы конфигурации вашей оболочки, чтобы pyenv автоматически загружался при старте. Откройте файл .bashrc в текстовом редакторе:

nano ~/.bashrc 

d. Вставьте следующие строки в конец файла:

export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

f. Сохраните изменения и закройте редактор. Примените изменения:

source ~/.bashrc

g. Устанавливаем Python:

pyenv install 3.11.5 

h. Устанавливаем его как глобальную версию:

pyenv global 3.11.5 

i. Теперь ваша система должна использовать выбранную версию Python по умолчанию. Вы можете проверить это, запустив:

python --version 

Эта команда должна показать Python 3.11.x.

18. Использование Cron.

Чтобы запускать какой-то файл по расписанию, необходимо, чтобы все библиотеки, используемые в этом файле были установлены в системе (в нашем случае в окружении Pyenv, которое в п.17 мы установили и настроили):

a. Переходим в папку с проектом:

cd путь_до_проекта/название_вашего_проекта

b. Устанавливаем все необходимые библиотеки (зависимости):

pip install -r requirements.txt

c. Для дальнейшего использования cron нам необходимо знать в какой директории установлен питон:

pyenv which python 

d. Открываем список заданий cron:

crontab -e

e. Добавляем вниз наше задание:

*/5 * * * * cd /home/ваше_имя_пользователя/ваш_путь/до_папки_проекта && /home/ ваше_имя_пользователя /.pyenv/versions/3.11.5/bin/python имя_запускаемого_файла.py >> /home/ваше_имя_пользователя/ваш_путь/до_папки_с_логами/cron.log 2>&1 

0 0 * * * - это пример, для запуска каждый день в 00:00
Здесь:
• Первый 0 обозначает минуты (0 минут).
• Второй 0 обозначает часы (0 часов, или полночь).
• Звёздочки обозначают "любое значение" для дней месяца, месяцев и дней недели соответственно.

19. Для сборки docker контейнера nats сервера создаем в корне вашего проекта файл Dockerfile.nats следующего содержания:

# Используем базовый образ Debian
FROM debian:bullseye-slim

# Устанавливаем необходимые пакеты (wget и tar) - для загрузки и распаковки наших образов
RUN apt-get update && \
    apt-get install -y wget tar

# Загружаем и устанавливаем nats-server
RUN wget https://github.com/nats-io/nats-server/releases/download/v2.9.15/nats-server-v2.9.15-linux-amd64.tar.gz && \
    tar -zxf nats-server-*.tar.gz && \
    cp nats-server-*-linux-amd64/nats-server /usr/bin/ && \
    rm -rf nats-server-*-linux-amd64 nats-server-*.tar.gz

# Загружаем и устанавливаем natscli
RUN wget https://github.com/nats-io/natscli/releases/download/v0.0.35/nats-0.0.35-amd64.deb && \
    dpkg -i nats-0.0.35-amd64.deb && \
    rm nats-0.0.35-amd64.deb

# Команда для запуска NATS сервера с JetStream и другими параметрами
CMD ["nats-server", "-js", "--store_dir", "/app/data", "--net", "nats_server", "--addr", "0.0.0.0", "--port", "4222", "--http_port", "8222", "--debug", "--trace"]
# Как можете видеть, я запускаю сервер с параметром --net nats_server, так как так у меня называется служба в docker-compose.yml

Еще небольшое замечание. Если вы используете nats, то вы должны создавать stream. Либо делаете это динамически в коде, либо вручную, тогда в конец вышеприведенного докер файла необходимо добавить еще команду по запуску потока. Официальная документация по запуску потока тут: https://docs.nats.io/running-a-nats-service/nats_admin/jetstream_admin/streams

Если вы хотели бы дополнить или что-то поправить, буду рад вашим комментариям https://t.me/EVGENIY_JEM

server_instruction_nginx_tb's People

Contributors

evgeny-jem avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.