# usefull commands - Убрать переносы строк: sed -i 's/\r$//' name-file.sh - find . -type f \( -name '*.sh' -o -name 'validate-env' \) -exec dos2unix {} + - docker compose stop # мягко останавливает контейнеры (не удаляет) - sudo shutdown -h now # выглючить ВМ - Генерация паролей - (со спец.символами) openssl rand -base64 32 - (без спец.символов) openssl rand -hex 16 - openssl rand -base64 16 | xclip -selection clipboard # Linux Туннель до БД: ssh -i C:\Users\MI\.ssh\hansel -L 5433:192.168.0.211:5432 root@135.106.164.58 -N #Обновление проекта cd /tmp rm han-chat-backend.tar.gz cd /opt/han-chat/backend rm C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz tar -C HAN_chat_specification/codebase/backend -czf han-chat-backend.tar.gz . scp -i C:\Users\MI\.ssh\hansel C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz root@135.106.164.58:/tmp/han-chat-backend.tar.gz tar -xzf /tmp/han-chat-backend.tar.gz find . -type f \( -name '*.sh' -o -name 'validate-env' \) -exec dos2unix {} + chmod +x scripts/validate-env deployment/scripts/*.sh redis/scripts/*.sh nginx/scripts/*.sh # Разворачиваем инфраструктуру в Селектел ч1 ## Создание сети ## Создание групп безопасности для сети и для БД Для сети открываем порты 80, 22, 443 Для БД открываем порты 5432, 5433 но только из CIDR (192.168.0.211\24) ## Создаем ВМ, подключаем к новой сети (через порт) и перезагружаем (либо руками вводить новые сетевые настройки - надо выбрать) # Подключение к ВМ и первичный скрипт ++ ssh -i C:\Users\MI\.ssh\hansel root@135.106.164.58 ++ scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\Assistent\HAN_chat_specification\codebase\backend\deployment\scripts\setup-vm.sh" root@135.106.164.58:/tmp/setup-vm.sh chmod +x /tmp/setup-vm.sh sudo /tmp/setup-vm.sh # Скрипт создал деплой пользователя. Нужно Перенести туда публичный ключ и дать права на файл и папку ## Вставляем публичный ключ новой строкой Далее даем права sudo nano /home/deploy/.ssh/authorized_keys sudo chmod 700 /home/deploy/.ssh sudo chmod 600 /home/deploy/.ssh/authorized_keys sudo chown -R deploy:deploy /home/deploy/.ssh ## Пароль деплою для использования sudo sudo passwd deploy ## После этого можно подключаться под деплой пользователем ssh -i C:\Users\MI\.ssh\han_chat_deploy deploy@135.106.164.58 ## GIT не работал. Проект пришлось копировать. tar -C HAN_chat_specification/codebase/backend -czf han-chat-backend.tar.gz . scp -i C:\Users\MI\.ssh\han_chat_deploy C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz deploy@135.106.164.58:/tmp/ scp -i C:\Users\MI\.ssh\hansel C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz root@135.106.164.58:/tmp/ ## Дальше распаковка cd /opt/han-chat/backend tar -xzf /tmp/han-chat-backend.tar.gz ## Правим переносы строк и даем права на исполнение find . -type f \( -name '*.sh' -o -name 'validate-env' \) -exec dos2unix {} + chmod +x scripts/validate-env deployment/scripts/*.sh redis/scripts/*.sh nginx/scripts/*.sh # Разворачиваем инфраструктуру в Селектел ч2 ## Создаем БД В базе подключаем pgcrypto Чтобы корректно работал PgBouncer выбираем session pooling ### Копируем СА сертификат Вариант Деплоя: mkdir -p /opt/han-chat/backend/secrets/pg scp -i C:\Users\MI\.ssh\han_chat_deploy -r C:\Users\MI\Documents\job\HAN_new_life\HANapp\Production\sertificates\CA.pem deploy@135.106.164.58:/opt/han-chat/backend/secrets/pg/ca.pem chmod 644 /opt/han-chat/backend/secrets/pg/ca.pem Вариант Селектела: mkdir -p ~/.postgresql/ wget https://storage.dbaas.selcloud.ru/CA.pem -O ~/.postgresql/root.crt chmod 0600 ~/.postgresql/root.crt ### Правки DNS-маршрутизации (в прошлый раз, какие-то трабблы были с базовой маршрутизацией) - скрипт ниже создаст sudo tee /etc/netplan/99-han-dns.yaml <<'EOF' network: version: 2 ethernets: eth0: nameservers: addresses: - 8.8.8.8 - 1.1.1.1 search: - selcloud.ru eth1: dhcp4-overrides: use-dns: false use-domains: false EOF sudo chmod 600 /etc/netplan/99-han-dns.yaml sudo netplan apply resolvectl flush-caches ### Проверка подключения к Postgers в ВМ nc -zv 192.168.0.211 5433 sudo apt update sudo apt install postgresql-client psql "host=master.ef54e3e4-ad3d-4b80-a6af-d63269e0895a.c.dbaas.selcloud.ru \ port=5432 \ dbname=han_chat \ user=dbAdmin \ sslmode=verify-ca" (psql "host=master.ef54e3e4-ad3d-4b80-a6af-d63269e0895a.c.dbaas.selcloud.ru port=5432 dbname=han_chat user=dbAdmin sslmode=verify-ca") ### Заводим пользователей и схемы Пользователей создаем через интерфейс селектела. Под админом даем права на создание в БД: GRANT CREATE ON DATABASE han_chat TO han_app; GRANT CREATE ON DATABASE han_chat TO bitrix_local_app; GRANT CREATE ON DATABASE han_chat TO bitrix_sync_user; GRANT CREATE ON DATABASE han_chat TO message_safety_app; GRANT CREATE ON DATABASE han_chat TO keycloak_user; Схемы создаем от лица пользователей, заходя каждым из них в БД. + Запрещаем всем посторонним входить в схему han_app и др. CREATE SCHEMA IF NOT EXISTS han_app; REVOKE ALL ON SCHEMA han_app FROM PUBLIC; ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO han_app; SHOW search_path; --чтобы заработало надо переподключиться (должно быть han_app) CREATE SCHEMA IF NOT EXISTS bitrix_local; REVOKE ALL ON SCHEMA bitrix_local FROM PUBLIC; ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO bitrix_local; SHOW search_path; --чтобы заработало надо переподключиться CREATE SCHEMA IF NOT EXISTS bitrix_sync; REVOKE ALL ON SCHEMA bitrix_sync FROM PUBLIC; ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO bitrix_sync; SHOW search_path; --чтобы заработало надо переподключиться CREATE SCHEMA IF NOT EXISTS message_safety; REVOKE ALL ON SCHEMA message_safety FROM PUBLIC; ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO message_safety; SHOW search_path; --чтобы заработало надо переподключиться CREATE SCHEMA IF NOT EXISTS keycloak; REVOKE ALL ON SCHEMA keycloak FROM PUBLIC; ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO keycloak; SHOW search_path; --чтобы заработало надо переподключиться Проверка search_path SELECT r.rolname, d.datname, s.setconfig FROM pg_db_role_setting s JOIN pg_roles r ON r.oid = s.setrole JOIN pg_database d ON d.oid = s.setdatabase WHERE r.rolname in ('han_app', 'bitrix_local_app', 'bitrix_sync_user', 'message_safety_app', 'keycloak_user'); После реализации bitrix_sync (проверить, вероятно не на все таблицы права нужны): -- Даем право на чтение (SELECT) всех СУЩЕСТВУЮЩИХ таблиц в схеме GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA han_app TO bitrix_sync_user; -- Настраиваем права по умолчанию для новых таблиц ALTER DEFAULT PRIVILEGES IN SCHEMA han_app GRANT SELECT ON TABLES TO bitrix_sync_user; -- Если нужно дать право на чтение и для новых последовательностей (sequences): ALTER DEFAULT PRIVILEGES IN SCHEMA han_app GRANT USAGE, SELECT ON SEQUENCES TO bitrix_sync_user; ## Заводим S3 хранилища: Создаем 2 сервисных пользователя и заводим им ключи: - API backend SELECTEL_S3_ACCESS_KEY / SELECTEL_S3_SECRET_KEY - Message Safety SELECTEL_S3_QUARANTINE_READ_ACCESS_KEY / SELECTEL_S3_QUARANTINE_READ_SECRET_KEY Создаем 3 приватных бакета - han-chat-quarantine (политика доступа API backend RW, Message Safety R) - han-chat-attachments (политика доступа API backend RW) - han-chat-documents (политика доступа API backend RW) RW: ListBucket GetBucketLocation PutObject GetObject DeleteObject ListBucketMultipartUploads ListMultipartUploadParts AbortMultipartUpload R: ListBucket GetBucketLocation GetObject ListBucketMultipartUploads ListMultipartUploadParts Политика CORS (бакет han-chat-quarantine, vHosted обязателен): Allowed origin: https://chat.han0107.ru Methods: POST, PUT, GET, HEAD Headers: * (или явно content-type; wildcard x-amz-* в Selectel не работает) Expose headers: ETag # Тест инфраструктуры mkdir -p /opt/han-chat/infratest cd /opt/han-chat/infratest scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\Assistent\HAN_chat_specification\infratest\*" root@135.106.164.58:/opt/han-chat/infratest --настраиваю env на локальной машине и копирую на диск scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\job\HAN_new_life\HANapp\Production\.env" root@135.106.164.58:/opt/han-chat/infratest/ Создаем изолированное окружение: python3 -m venv .venv . .venv/bin/activate python3 -m pip install --upgrade pip python3 -m pip install -r requirements.txt Если не работает, то надо DNS переправить на eth0 resolvectl dns eth0 1.1.1.1 8.8.8.8 resolvectl domain eth0 '~.' resolvectl flush-caches resolvectl query pypi.org # Подготовка к запуску Сертификат рекомендуется скопировать в папку с секретами cp /root/.postgresql/root.crt /opt/han-chat/backend/secrets/pg/root.crt chmod 644 /opt/han-chat/backend/secrets/pg/root.crt В битрикс регистрируем локальное приложение: Установка: https://chat.example.ru/bitrix/install Обработчик: https://chat.example.ru/bitrix/handler ??? (не понадобилось) Placement: https://chat.example.ru/bitrix/placement --настраиваю env на локальной машине и копирую на диск scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\job\HAN_new_life\HANapp\Production\.env" root@135.106.164.58:/opt/han-chat/backend --Проверка .env cd /opt/han-chat/backend chmod 600 .env ./scripts/validate-env .env docker compose --env-file .env config --quiet docker compose --env-file .env config --services python3 -m unittest discover -s tests -v --Проверка портов (Публиковаться должны только 80 и 443 у nginx) docker compose --env-file .env config | grep -n 'published:' --Собираем локальные образы: docker compose --env-file .env build --pull docker compose --env-file .env images ## Миграции БД и начальные настройки cd /opt/han-chat/backend PITR_MARKER_CONFIRMED=true deployment/scripts/migrate.sh deployment/scripts/seed.sh ## Запуск внутренних сервисов Сначала запустите Redis: ```sh docker compose --env-file .env up -d redis docker compose --env-file .env ps redis ``` Затем Keycloak и OpenTelemetry: ```sh docker compose --env-file .env up -d keycloak otel-collector docker compose --env-file .env ps keycloak otel-collector ``` Первый запуск Keycloak может занять несколько минут: он создаст свои таблицы и импортирует realm `han-chat`. После готовности Keycloak: ```sh docker compose --env-file .env up -d message-safety docker compose --env-file .env up -d api-backend docker compose --env-file .env up -d bitrix-local-app bitrix-sync docker compose --env-file .env up -d \ delivery-worker safety-recovery-worker cleanup-worker docker compose --env-file .env ps ``` Если сервис не становится healthy: ```sh docker compose --env-file .env logs --tail=200 docker inspect "$(docker compose --env-file .env ps -q )" ``` ## Первоначальный выпуск TLS-сертификата Для ACME требуется работающий nginx по HTTP. В `.env` оставьте `NGINX_TLS_ENABLED=true`, но первый nginx запустите с временным переопределением: ```sh NGINX_TLS_ENABLED=false \ docker compose --env-file .env up -d frontend-static nginx ``` Проверьте HTTP: ```sh curl -I http://chat.han0107.ru/ ``` Сначала рекомендуется проверить Certbot через staging: ```sh docker compose --env-file .env --profile certbot run --rm certbot certonly \ --staging \ --webroot -w /var/www/certbot \ -d chat.han0107.ru \ --cert-name chat.han0107.ru-staging \ --email ap@han.ru \ --agree-tos --no-eff-email --non-interactive ``` После успешного staging-теста выпустите рабочий сертификат с основным cert-name без `--staging`: ```sh docker compose --env-file .env --profile certbot run --rm certbot certonly \ --webroot -w /var/www/certbot \ -d chat.han0107.ru \ --cert-name chat.han0107.ru \ --email ap@han.ru \ --agree-tos --no-eff-email --non-interactive ``` Пересоздайте nginx уже с TLS: ```sh docker compose --env-file .env up -d --force-recreate nginx docker compose --env-file .env exec -T nginx nginx -t -c /tmp/nginx.conf curl -I https://chat.han0107.ru/ ``` Повторно запустите VM setup, чтобы он обнаружил проект и установил systemd-таймер продления сертификата: ```sh sudo /opt/han-chat/backend/deployment/scripts/setup-vm.sh systemctl status han-chat-ssl-renew.timer ## Запуск всего контура Теперь можно привести весь проект к состоянию, описанному Compose: ```sh cd /opt/han-chat/backend docker compose --env-file .env up -d docker compose --env-file .env ps ``` Проверьте, что контейнеры не перезапускаются: ```sh docker compose --env-file .env ps docker compose --env-file .env logs --since=10m ``` ## Публичная проверка Запустите smoke-тест: ```sh cd /opt/han-chat/backend deployment/scripts/smoke.sh ``` Также вручную проверьте: ```sh curl -fsS https://chat.han0107.ru/api/v1/public/app-config | jq curl -fsS https://chat.han0107.ru/api/v1/public/content | jq curl -fsS \ https://chat.han0107.ru/auth/realms/han-chat/.well-known/openid-configuration | jq ``` Внутренний API не должен быть опубликован: ```sh curl -i https://chat.han0107.ru/internal/safety/v1/messages/check ``` Ожидаемый статус — `404`. Откройте в браузере: ```text https://chat.example.ru/ ``` Для тестовой авторизации используйте значение `KEYCLOAK_OTP_MOCK_CODE` из `.env`. Настройки keykcloack: Для битрикса код установки приложения: docker compose --env-file .env exec -T api-backend python - <<'PY' import os import urllib.request base = os.environ["BITRIX_LOCAL_APP_BASE_URL"] token = os.environ["BITRIX_LOCAL_APP_INTERNAL_TOKEN"] request = urllib.request.Request( base + "/internal/openlines/v1/setup/retry", method="POST", headers={"Authorization": "Bearer " + token}, ) print(urllib.request.urlopen(request).read().decode()) PY