docs: project name change, migration script
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ ADMIN_IDS=comma_separated_admin_ids #
|
|||||||
# PostgreSQL Database Connection Settings
|
# PostgreSQL Database Connection Settings
|
||||||
POSTGRES_USER= # Required: database user name
|
POSTGRES_USER= # Required: database user name
|
||||||
POSTGRES_PASSWORD= # Required: database password
|
POSTGRES_PASSWORD= # Required: database password
|
||||||
POSTGRES_HOST=remnawave-tg-shop-db # Database container name
|
POSTGRES_HOST=remnawave-minishop-db # Database container name
|
||||||
POSTGRES_PORT=5432 # Port
|
POSTGRES_PORT=5432 # Port
|
||||||
POSTGRES_DB=postgres # Database name
|
POSTGRES_DB=postgres # Database name
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Replace the example domains below with your real webhook and Mini App hostnames.
|
# Replace the example domains below with your real webhook and Mini App hostnames.
|
||||||
webhook.domain.com {
|
webhook.domain.com {
|
||||||
encode zstd gzip
|
encode zstd gzip
|
||||||
reverse_proxy remnawave-tg-shop:{$WEB_SERVER_PORT:8080}
|
reverse_proxy remnawave-minishop:{$WEB_SERVER_PORT:8080}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.domain.com {
|
app.domain.com {
|
||||||
encode zstd gzip
|
encode zstd gzip
|
||||||
reverse_proxy remnawave-tg-shop:{$WEBAPP_SERVER_PORT:8081}
|
reverse_proxy remnawave-minishop:{$WEBAPP_SERVER_PORT:8081}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,24 +213,24 @@ Remnawave Minishop — это Telegram-бот **и** Web App (Mini App) для
|
|||||||
Вам понадобится обратный прокси (например, Nginx) для обработки HTTPS-трафика и перенаправления запросов на контейнер с ботом.
|
Вам понадобится обратный прокси (например, Nginx) для обработки HTTPS-трафика и перенаправления запросов на контейнер с ботом.
|
||||||
|
|
||||||
**Пути для перенаправления:**
|
**Пути для перенаправления:**
|
||||||
- `https://<ваш_домен>/webhook/yookassa` → `http://remnawave-tg-shop:<WEB_SERVER_PORT>/webhook/yookassa`
|
- `https://<ваш_домен>/webhook/yookassa` → `http://remnawave-minishop:<WEB_SERVER_PORT>/webhook/yookassa`
|
||||||
- `https://<ваш_домен>/webhook/freekassa` → `http://remnawave-tg-shop:<WEB_SERVER_PORT>/webhook/freekassa`
|
- `https://<ваш_домен>/webhook/freekassa` → `http://remnawave-minishop:<WEB_SERVER_PORT>/webhook/freekassa`
|
||||||
- `https://<ваш_домен>/webhook/platega` → `http://remnawave-tg-shop:<WEB_SERVER_PORT>/webhook/platega`
|
- `https://<ваш_домен>/webhook/platega` → `http://remnawave-minishop:<WEB_SERVER_PORT>/webhook/platega`
|
||||||
- `https://<ваш_домен>/webhook/severpay` → `http://remnawave-tg-shop:<WEB_SERVER_PORT>/webhook/severpay`
|
- `https://<ваш_домен>/webhook/severpay` → `http://remnawave-minishop:<WEB_SERVER_PORT>/webhook/severpay`
|
||||||
- `https://<ваш_домен>/webhook/cryptopay` → `http://remnawave-tg-shop:<WEB_SERVER_PORT>/webhook/cryptopay`
|
- `https://<ваш_домен>/webhook/cryptopay` → `http://remnawave-minishop:<WEB_SERVER_PORT>/webhook/cryptopay`
|
||||||
- `https://<ваш_домен>/webhook/panel` → `http://remnawave-tg-shop:<WEB_SERVER_PORT>/webhook/panel`
|
- `https://<ваш_домен>/webhook/panel` → `http://remnawave-minishop:<WEB_SERVER_PORT>/webhook/panel`
|
||||||
- **Для Telegram:** Бот автоматически установит вебхук, если в `.env` указан `WEBHOOK_BASE_URL`. Путь будет `https://<ваш_домен>/<BOT_TOKEN>`.
|
- **Для Telegram:** Бот автоматически установит вебхук, если в `.env` указан `WEBHOOK_BASE_URL`. Путь будет `https://<ваш_домен>/<BOT_TOKEN>`.
|
||||||
|
|
||||||
Где `remnawave-tg-shop` — это имя сервиса из `docker-compose.yml`, а `<WEB_SERVER_PORT>` — порт, указанный в `.env`.
|
Где `remnawave-minishop` — это имя сервиса из `docker-compose.yml`, а `<WEB_SERVER_PORT>` — порт, указанный в `.env`.
|
||||||
|
|
||||||
**Отдельный порт Web App:**
|
**Отдельный порт Web App:**
|
||||||
- `https://<домен_web_app>/` → `http://remnawave-tg-shop:<WEBAPP_SERVER_PORT>/`
|
- `https://<домен_web_app>/` → `http://remnawave-minishop:<WEBAPP_SERVER_PORT>/`
|
||||||
|
|
||||||
Web App не должен проксироваться на `WEB_SERVER_PORT`: этот порт оставьте для Telegram, платежных и Remnawave webhooks.
|
Web App не должен проксироваться на `WEB_SERVER_PORT`: этот порт оставьте для Telegram, платежных и Remnawave webhooks.
|
||||||
|
|
||||||
6. **Просмотр логов:**
|
6. **Просмотр логов:**
|
||||||
```bash
|
```bash
|
||||||
docker compose logs -f remnawave-tg-shop
|
docker compose logs -f remnawave-minishop
|
||||||
```
|
```
|
||||||
|
|
||||||
> 💡 Если включена проверка подписки на канал (`REQUIRED_CHANNEL_ID`), добавьте бота администратором в этот канал. Пользователь увидит кнопку «Проверить подписку», и, после первого успешного подтверждения, дальнейшие действия блокироваться не будут.
|
> 💡 Если включена проверка подписки на канал (`REQUIRED_CHANNEL_ID`), добавьте бота администратором в этот канал. Пользователь увидит кнопку «Проверить подписку», и, после первого успешного подтверждения, дальнейшие действия блокироваться не будут.
|
||||||
@@ -270,8 +270,8 @@ Web App запускается в том же контейнере, что и б
|
|||||||
3. Проксируйте отдельный домен или location на порт Web App:
|
3. Проксируйте отдельный домен или location на порт Web App:
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
upstream remnawave-tg-shop-webapp {
|
upstream remnawave-minishop-webapp {
|
||||||
server remnawave-tg-shop:8081;
|
server remnawave-minishop:8081;
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
@@ -283,7 +283,7 @@ Web App запускается в том же контейнере, что и б
|
|||||||
ssl_certificate_key "/etc/nginx/ssl/app_privkey.key";
|
ssl_certificate_key "/etc/nginx/ssl/app_privkey.key";
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://remnawave-tg-shop-webapp;
|
proxy_pass http://remnawave-minishop-webapp;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@@ -352,8 +352,8 @@ cd /opt/remnawave/nginx && nano nginx.conf
|
|||||||
Добавьте в `nginx.conf` следующую конфигурацию:
|
Добавьте в `nginx.conf` следующую конфигурацию:
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
upstream remnawave-tg-shop {
|
upstream remnawave-minishop {
|
||||||
server remnawave-tg-shop:8080;
|
server remnawave-minishop:8080;
|
||||||
}
|
}
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
@@ -385,7 +385,7 @@ server {
|
|||||||
error_page 400 404 500 502 @redirect;
|
error_page 400 404 500 502 @redirect;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://remnawave-tg-shop$request_uri;
|
proxy_pass http://remnawave-minishop$request_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
location @redirect {
|
location @redirect {
|
||||||
@@ -491,12 +491,12 @@ IMAGE_TAG=3.0.0 docker compose -f docker-compose-remote-server.yml up -d
|
|||||||
```caddyfile
|
```caddyfile
|
||||||
webhook.domain.com {
|
webhook.domain.com {
|
||||||
encode zstd gzip
|
encode zstd gzip
|
||||||
reverse_proxy remnawave-tg-shop:{$WEB_SERVER_PORT:8080}
|
reverse_proxy remnawave-minishop:{$WEB_SERVER_PORT:8080}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.domain.com {
|
app.domain.com {
|
||||||
encode zstd gzip
|
encode zstd gzip
|
||||||
reverse_proxy remnawave-tg-shop:{$WEBAPP_SERVER_PORT:8081}
|
reverse_proxy remnawave-minishop:{$WEBAPP_SERVER_PORT:8081}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -514,6 +514,10 @@ docker compose -f docker-compose-caddy.yml up -d --build
|
|||||||
|
|
||||||
После этого Caddy сам выпустит сертификаты и будет проксировать webhook'и на порт `8080`, а Mini App - на `8081`.
|
После этого Caddy сам выпустит сертификаты и будет проксировать webhook'и на порт `8080`, а Mini App - на `8081`.
|
||||||
|
|
||||||
|
## 🔄 Миграция с `remnawave-tg-shop` на `remnawave-minishop`
|
||||||
|
|
||||||
|
Короткая инструкция, автоматический запуск helper'а из `raw` и ручной вариант переноса вынесены в отдельный документ: [docs/migration-to-minishop.md](docs/migration-to-minishop.md).
|
||||||
|
|
||||||
## 📁 Структура проекта
|
## 📁 Структура проекта
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -540,7 +544,7 @@ docker compose -f docker-compose-caddy.yml up -d --build
|
|||||||
│ ├── migrator.py # Миграции схемы при старте
|
│ ├── migrator.py # Миграции схемы при старте
|
||||||
│ └── models.py # Модели SQLAlchemy
|
│ └── models.py # Модели SQLAlchemy
|
||||||
├── locales/ # Файлы локализации (ru.json, en.json)
|
├── locales/ # Файлы локализации (ru.json, en.json)
|
||||||
├── scripts/ # Сборка JS Web App и обновление копий Telegram JS
|
├── scripts/ # Сборка JS Web App, обновление копий Telegram JS и миграционный helper
|
||||||
├── tests/ # Pytest-тесты
|
├── tests/ # Pytest-тесты
|
||||||
├── .env.example # Пример файла с переменными окружения
|
├── .env.example # Пример файла с переменными окружения
|
||||||
├── Caddyfile # Пример конфигурации Caddy
|
├── Caddyfile # Пример конфигурации Caddy
|
||||||
|
|||||||
+15
-15
@@ -1,8 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
remnawave-tg-shop:
|
remnawave-minishop:
|
||||||
build: .
|
build: .
|
||||||
container_name: remnawave-tg-shop
|
container_name: remnawave-minishop
|
||||||
hostname: remnawave-tg-shop
|
hostname: remnawave-minishop
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
@@ -11,19 +11,19 @@ services:
|
|||||||
- ./locales:/app/locales
|
- ./locales:/app/locales
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
remnawave-tg-shop-db:
|
remnawave-minishop-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
remnawave-tg-shop-db:
|
remnawave-minishop-db:
|
||||||
image: postgres:17
|
image: postgres:17
|
||||||
container_name: remnawave-tg-shop-db
|
container_name: remnawave-minishop-db
|
||||||
hostname: remnawave-tg-shop-db
|
hostname: remnawave-minishop-db
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- TZ=UTC
|
- TZ=UTC
|
||||||
volumes:
|
volumes:
|
||||||
- remnawave-tg-shop-db-data:/var/lib/postgresql/data
|
- remnawave-minishop-db-data:/var/lib/postgresql/data
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
|
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
|
||||||
@@ -33,14 +33,14 @@ services:
|
|||||||
|
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2-alpine
|
image: caddy:2-alpine
|
||||||
container_name: remnawave-tg-shop-caddy
|
container_name: remnawave-minishop-caddy
|
||||||
hostname: remnawave-tg-shop-caddy
|
hostname: remnawave-minishop-caddy
|
||||||
environment:
|
environment:
|
||||||
- TZ=UTC
|
- TZ=UTC
|
||||||
- WEB_SERVER_PORT=${WEB_SERVER_PORT:-8080}
|
- WEB_SERVER_PORT=${WEB_SERVER_PORT:-8080}
|
||||||
- WEBAPP_SERVER_PORT=${WEBAPP_SERVER_PORT:-8081}
|
- WEBAPP_SERVER_PORT=${WEBAPP_SERVER_PORT:-8081}
|
||||||
depends_on:
|
depends_on:
|
||||||
- remnawave-tg-shop
|
- remnawave-minishop
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
@@ -51,9 +51,9 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
remnawave-tg-shop-db-data:
|
remnawave-minishop-db-data:
|
||||||
name: remnawave-tg-shop-db-data
|
name: remnawave-minishop-db-data
|
||||||
caddy_data:
|
caddy_data:
|
||||||
name: remnawave-tg-shop-caddy-data
|
name: remnawave-minishop-caddy-data
|
||||||
caddy_config:
|
caddy_config:
|
||||||
name: remnawave-tg-shop-caddy-config
|
name: remnawave-minishop-caddy-config
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
remnawave-tg-shop:
|
remnawave-minishop:
|
||||||
image: ghcr.io/3252a8/remnawave-tg-shop:${IMAGE_TAG:-3.0.0}
|
image: ghcr.io/3252a8/remnawave-tg-shop:${IMAGE_TAG:-3.0.0}
|
||||||
container_name: remnawave-tg-shop
|
container_name: remnawave-minishop
|
||||||
hostname: remnawave-tg-shop
|
hostname: remnawave-minishop
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
ports:
|
||||||
@@ -16,17 +16,17 @@ services:
|
|||||||
- ./locales:/app/locales
|
- ./locales:/app/locales
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- remnawave-tg-shop-db
|
- remnawave-minishop-db
|
||||||
remnawave-tg-shop-db:
|
remnawave-minishop-db:
|
||||||
image: postgres:17
|
image: postgres:17
|
||||||
container_name: remnawave-tg-shop-db
|
container_name: remnawave-minishop-db
|
||||||
hostname: remnawave-tg-shop-db
|
hostname: remnawave-minishop-db
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- TZ=UTC
|
- TZ=UTC
|
||||||
volumes:
|
volumes:
|
||||||
- remnawave-tg-shop-db-data:/var/lib/postgresql/data
|
- remnawave-minishop-db-data:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- remnawave-network
|
- remnawave-network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -38,5 +38,5 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
remnawave-network: null
|
remnawave-network: null
|
||||||
volumes:
|
volumes:
|
||||||
remnawave-tg-shop-db-data:
|
remnawave-minishop-db-data:
|
||||||
name: remnawave-tg-shop-db-data
|
name: remnawave-minishop-db-data
|
||||||
|
|||||||
+10
-10
@@ -1,15 +1,15 @@
|
|||||||
services:
|
services:
|
||||||
remnawave-tg-shop:
|
remnawave-minishop:
|
||||||
build: .
|
build: .
|
||||||
container_name: remnawave-tg-shop
|
container_name: remnawave-minishop
|
||||||
hostname: remnawave-tg-shop
|
hostname: remnawave-minishop
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
networks:
|
networks:
|
||||||
- remnawave-network
|
- remnawave-network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
remnawave-tg-shop-db:
|
remnawave-minishop-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- 127.0.0.1:8080:8080
|
- 127.0.0.1:8080:8080
|
||||||
@@ -21,14 +21,14 @@ services:
|
|||||||
retries: 5
|
retries: 5
|
||||||
start_period: 30s
|
start_period: 30s
|
||||||
|
|
||||||
remnawave-tg-shop-db:
|
remnawave-minishop-db:
|
||||||
image: postgres:17
|
image: postgres:17
|
||||||
container_name: remnawave-tg-shop-db
|
container_name: remnawave-minishop-db
|
||||||
hostname: remnawave-tg-shop-db
|
hostname: remnawave-minishop-db
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
volumes:
|
||||||
- remnawave-tg-shop-db-data:/var/lib/postgresql/data
|
- remnawave-minishop-db-data:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- remnawave-network
|
- remnawave-network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -43,5 +43,5 @@ networks:
|
|||||||
external: true
|
external: true
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
remnawave-tg-shop-db-data:
|
remnawave-minishop-db-data:
|
||||||
name: remnawave-tg-shop-db-data
|
name: remnawave-minishop-db-data
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
# Миграция с `remnawave-tg-shop` на `remnawave-minishop`
|
||||||
|
|
||||||
|
Начиная с этой версии контейнеры и тома названы `remnawave-minishop*` вместо `remnawave-tg-shop*`. Старый и новый стеки используют **разные имена томов**, поэтому простой `docker compose up -d` после `git pull` создаст пустую БД. Эта инструкция описывает, как перенести данные.
|
||||||
|
|
||||||
|
Есть два пути:
|
||||||
|
|
||||||
|
- [Автоматический](#автоматический-способ-через-скрипт) — один скрипт, идемпотентный, проверяет состояние на каждом шаге.
|
||||||
|
- [Ручной](#ручной-способ) — команды, которые делает скрипт, если хочется понимать происходящее или выполнить выборочно.
|
||||||
|
|
||||||
|
В обоих случаях:
|
||||||
|
- старые тома **не удаляются** автоматически — это безопасный бэкап на случай отката;
|
||||||
|
- сертификаты Caddy (если используется `docker-compose-caddy.yml`) тоже переносятся, чтобы Let's Encrypt не выписывал их заново и не упереться в rate limit.
|
||||||
|
|
||||||
|
## Автоматический способ (через скрипт)
|
||||||
|
|
||||||
|
Если helper ещё не лежит у вас локально, запускайте его прямо из `raw` из корня старого репозитория:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash <(curl -fsSL https://raw.githubusercontent.com/3252a8/remnawave-minishop/main/scripts/migrate_to_minishop.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
> Команда выше рассчитана на `bash` / Git Bash / WSL. Если вы запускаете из PowerShell, удобнее сначала открыть Git Bash.
|
||||||
|
|
||||||
|
Если вы уже подтянули новую версию и файл есть локально, можно запускать и так:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/migrate_to_minishop.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
По умолчанию скрипт работает с `docker-compose.yml` и переключается на ветку `main`. Можно переопределить через переменные окружения:
|
||||||
|
|
||||||
|
| Переменная | Назначение | По умолчанию |
|
||||||
|
| ----------------- | ----------------------------------------------------------------------- | ---------------------- |
|
||||||
|
| `PROJECT_ROOT` | Явный путь к корню старого репозитория, если запуск не из него | текущая директория |
|
||||||
|
| `COMPOSE_FILE` | Какой compose-файл стартовать в конце | `docker-compose.yml` |
|
||||||
|
| `TARGET_BRANCH` | На какую ветку переключаться и подтягивать обновления | `main` |
|
||||||
|
| `GIT_REMOTE` | Какой remote использовать для `fetch`/`pull` | `origin` |
|
||||||
|
| `NEW_ORIGIN_URL` | Если задано и не совпадает с URL выбранного remote — он будет обновлён | (не меняется) |
|
||||||
|
| `ASSUME_YES` | `1` — не задавать интерактивных вопросов | `0` |
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Caddy-вариант из raw
|
||||||
|
COMPOSE_FILE=docker-compose-caddy.yml \
|
||||||
|
bash <(curl -fsSL https://raw.githubusercontent.com/3252a8/remnawave-minishop/main/scripts/migrate_to_minishop.sh)
|
||||||
|
|
||||||
|
# С переключением origin на форк 3252a8
|
||||||
|
NEW_ORIGIN_URL=https://github.com/3252a8/remnawave-minishop.git \
|
||||||
|
bash <(curl -fsSL https://raw.githubusercontent.com/3252a8/remnawave-minishop/main/scripts/migrate_to_minishop.sh)
|
||||||
|
|
||||||
|
# Без интерактива
|
||||||
|
ASSUME_YES=1 \
|
||||||
|
bash <(curl -fsSL https://raw.githubusercontent.com/3252a8/remnawave-minishop/main/scripts/migrate_to_minishop.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
Что делает скрипт:
|
||||||
|
|
||||||
|
1. **Останавливает текущий стек**: проверяет известные контейнеры старой и новой схемы и останавливает их, если они запущены.
|
||||||
|
2. **Переключает `origin`**, если задана переменная `NEW_ORIGIN_URL`, иначе оставляет как есть.
|
||||||
|
3. **Подтягивает целевую ветку** (`git fetch` + `git switch` + `git pull --ff-only`). Прерывается, если в рабочем дереве есть незакоммиченные изменения.
|
||||||
|
4. **Переносит тома** `remnawave-tg-shop-*` → `remnawave-minishop-*` через одноразовый `alpine`-контейнер. Если новый том уже непустой, копирование пропускается. Заодно правится `POSTGRES_HOST` в `.env` (с бэкапом в `.env.bak`).
|
||||||
|
5. **Стартует новый стек** (`docker compose -f $COMPOSE_FILE up -d --remove-orphans`, а для локальной сборки ещё и `--build`) и печатает `docker compose ps`.
|
||||||
|
|
||||||
|
Скрипт идемпотентен: повторный запуск ничего не сломает, просто пропустит уже выполненные шаги.
|
||||||
|
|
||||||
|
После того как убедитесь, что бот работает и данные на месте, удалите старые тома:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker volume rm remnawave-tg-shop-db-data
|
||||||
|
docker volume rm remnawave-tg-shop-caddy-data remnawave-tg-shop-caddy-config 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Если у вас есть внешний reverse proxy (Nginx и т.п.), не забудьте поправить в его конфиге `upstream`/`proxy_pass`: имя хоста контейнера изменилось с `remnawave-tg-shop` на `remnawave-minishop`. Скрипт не трогает внешние конфиги.
|
||||||
|
|
||||||
|
## Ручной способ
|
||||||
|
|
||||||
|
1. **Остановите старый стек и обновите код:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
git fetch origin
|
||||||
|
git checkout main
|
||||||
|
git pull --ff-only origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Перенесите том БД в новое имя:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker volume create remnawave-minishop-db-data
|
||||||
|
docker run --rm \
|
||||||
|
-v remnawave-tg-shop-db-data:/from:ro \
|
||||||
|
-v remnawave-minishop-db-data:/to \
|
||||||
|
alpine sh -c "cd /from && cp -a . /to"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Обновите `.env`:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sed -i.bak 's/^POSTGRES_HOST=remnawave-tg-shop-db$/POSTGRES_HOST=remnawave-minishop-db/' .env
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **(Только для Caddy)** перенесите тома Caddy с TLS-сертификатами и состоянием ACME:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
for v in caddy-data caddy-config; do
|
||||||
|
docker volume create "remnawave-minishop-$v"
|
||||||
|
docker run --rm \
|
||||||
|
-v "remnawave-tg-shop-$v":/from:ro \
|
||||||
|
-v "remnawave-minishop-$v":/to \
|
||||||
|
alpine sh -c "cd /from && cp -a . /to"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Запустите новый стек:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
# или
|
||||||
|
docker compose -f docker-compose-caddy.yml up -d --build
|
||||||
|
# или
|
||||||
|
docker compose -f docker-compose-remote-server.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Проверьте:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs -f remnawave-minishop
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **(Опционально) удалите старые тома**, когда убедитесь, что новый стек стабилен:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker volume rm remnawave-tg-shop-db-data
|
||||||
|
docker volume rm remnawave-tg-shop-caddy-data remnawave-tg-shop-caddy-config 2>/dev/null || true
|
||||||
|
```
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=""
|
||||||
|
|
||||||
|
OLD_PREFIX="remnawave-tg-shop"
|
||||||
|
NEW_PREFIX="remnawave-minishop"
|
||||||
|
OLD_DB_VOLUME="${OLD_PREFIX}-db-data"
|
||||||
|
NEW_DB_VOLUME="${NEW_PREFIX}-db-data"
|
||||||
|
OLD_CADDY_VOLUMES=("${OLD_PREFIX}-caddy-data" "${OLD_PREFIX}-caddy-config")
|
||||||
|
NEW_CADDY_VOLUMES=("${NEW_PREFIX}-caddy-data" "${NEW_PREFIX}-caddy-config")
|
||||||
|
KNOWN_CONTAINERS=(
|
||||||
|
"${OLD_PREFIX}"
|
||||||
|
"${OLD_PREFIX}-db"
|
||||||
|
"${OLD_PREFIX}-caddy"
|
||||||
|
"${NEW_PREFIX}"
|
||||||
|
"${NEW_PREFIX}-db"
|
||||||
|
"${NEW_PREFIX}-caddy"
|
||||||
|
)
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '%s\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf 'Ошибка: %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || die "Не найдено обязательное средство \`$1\` в PATH."
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_root() {
|
||||||
|
if [[ -n "${PROJECT_ROOT:-}" ]]; then
|
||||||
|
[[ -d "$PROJECT_ROOT" ]] || die "PROJECT_ROOT не существует: $PROJECT_ROOT"
|
||||||
|
(cd -- "$PROJECT_ROOT" >/dev/null && pwd -P)
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local git_root
|
||||||
|
if git_root="$(git rev-parse --show-toplevel 2>/dev/null)"; then
|
||||||
|
printf '%s\n' "$git_root"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
pwd -P
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
log "+ $*"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
container_exists() {
|
||||||
|
docker inspect "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
container_running() {
|
||||||
|
[[ "$(docker inspect -f '{{.State.Running}}' "$1" 2>/dev/null || true)" == "true" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_container() {
|
||||||
|
local name="$1"
|
||||||
|
|
||||||
|
if ! container_exists "$name"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if container_running "$name"; then
|
||||||
|
docker stop "$name" >/dev/null
|
||||||
|
fi
|
||||||
|
docker rm "$name" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_exists() {
|
||||||
|
docker volume inspect "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_is_empty() {
|
||||||
|
docker run --rm -v "$1:/data" alpine sh -c 'test -z "$(find /data -mindepth 1 -print -quit)"' >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_volume() {
|
||||||
|
local source="$1"
|
||||||
|
local target="$2"
|
||||||
|
|
||||||
|
if ! volume_exists "$source"; then
|
||||||
|
log " - Пропускаю том \`$source\`: исходный том не найден."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if volume_exists "$target" && ! volume_is_empty "$target"; then
|
||||||
|
log " - Пропускаю том \`$target\`: он уже не пустой."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker volume create "$target" >/dev/null
|
||||||
|
docker run --rm -v "$source:/from:ro" -v "$target:/to" alpine sh -c 'cd /from && cp -a . /to/'
|
||||||
|
}
|
||||||
|
|
||||||
|
is_old_postgres_host() {
|
||||||
|
grep -Eq "^[[:space:]]*POSTGRES_HOST[[:space:]]*=[[:space:]]*${OLD_PREFIX}-db[[:space:]]*(#.*)?$" "$ROOT/.env"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_new_postgres_host() {
|
||||||
|
grep -Eq "^[[:space:]]*POSTGRES_HOST[[:space:]]*=[[:space:]]*${NEW_PREFIX}-db[[:space:]]*(#.*)?$" "$ROOT/.env"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_postgres_host() {
|
||||||
|
if is_old_postgres_host; then
|
||||||
|
sed -i.bak -E "s|^([[:space:]]*POSTGRES_HOST[[:space:]]*=[[:space:]]*)${OLD_PREFIX}-db([[:space:]]*(#.*)?)$|\\1${NEW_PREFIX}-db\\2|" "$ROOT/.env"
|
||||||
|
log " - \`.env\` обновлён, резервная копия сохранена в \`.env.bak\`."
|
||||||
|
elif is_new_postgres_host; then
|
||||||
|
log " - \`POSTGRES_HOST\` уже указывает на новый контейнер, ничего менять не нужно."
|
||||||
|
else
|
||||||
|
log " - \`POSTGRES_HOST\` не похож на старую схему, пропускаю изменение."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
require_cmd git
|
||||||
|
require_cmd docker
|
||||||
|
docker info >/dev/null
|
||||||
|
|
||||||
|
ROOT="$(resolve_root)"
|
||||||
|
|
||||||
|
local compose_file="${COMPOSE_FILE:-docker-compose.yml}"
|
||||||
|
local target_branch="${TARGET_BRANCH:-main}"
|
||||||
|
local git_remote="${GIT_REMOTE:-origin}"
|
||||||
|
local new_origin_url="${NEW_ORIGIN_URL:-}"
|
||||||
|
local assume_yes="${ASSUME_YES:-0}"
|
||||||
|
local current_origin
|
||||||
|
local current_branch
|
||||||
|
local remote_ref
|
||||||
|
local head_commit
|
||||||
|
local compose_has_build=0
|
||||||
|
local compose_has_caddy=0
|
||||||
|
local -a compose_cmd
|
||||||
|
local -a running_containers=()
|
||||||
|
local -a summary=()
|
||||||
|
local -a up_args
|
||||||
|
local name
|
||||||
|
local source
|
||||||
|
local target
|
||||||
|
local answer
|
||||||
|
|
||||||
|
if [[ $compose_file != /* ]]; then
|
||||||
|
compose_file="$ROOT/$compose_file"
|
||||||
|
fi
|
||||||
|
[[ -f "$compose_file" ]] || die "Compose-файл не найден: $compose_file"
|
||||||
|
[[ -e "$ROOT/.git" ]] || die "Скрипт нужно запускать из корня git-репозитория."
|
||||||
|
[[ -f "$ROOT/.env" ]] || die "Не найден \`.env\` в корне репозитория."
|
||||||
|
|
||||||
|
if docker compose version >/dev/null 2>&1; then
|
||||||
|
compose_cmd=(docker compose)
|
||||||
|
elif command -v docker-compose >/dev/null 2>&1; then
|
||||||
|
compose_cmd=(docker-compose)
|
||||||
|
else
|
||||||
|
die "Не найден ни \`docker compose\`, ни \`docker-compose\`."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$(git -C "$ROOT" status --porcelain=v1)" ]]; then
|
||||||
|
die "В рабочем дереве есть незакоммиченные изменения. Сначала сохраните их, чтобы миграция не затёрла чужие правки."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -Eq '^[[:space:]]*build:[[:space:]]*' "$compose_file"; then
|
||||||
|
compose_has_build=1
|
||||||
|
fi
|
||||||
|
if grep -Eq '^[[:space:]]*caddy:[[:space:]]*$' "$compose_file"; then
|
||||||
|
compose_has_caddy=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for name in "${KNOWN_CONTAINERS[@]}"; do
|
||||||
|
if container_exists "$name"; then
|
||||||
|
running_containers+=("$name")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
current_origin="$(git -C "$ROOT" remote get-url "$git_remote")"
|
||||||
|
if [[ -n "$new_origin_url" && "$current_origin" != "$new_origin_url" ]]; then
|
||||||
|
summary+=( "обновить $git_remote с \`$current_origin\` на \`$new_origin_url\`" )
|
||||||
|
fi
|
||||||
|
summary+=( "скачать ветку \`$target_branch\` из \`$git_remote\`" )
|
||||||
|
if volume_exists "$OLD_DB_VOLUME"; then
|
||||||
|
summary+=( "проверить том БД \`$OLD_DB_VOLUME\` и перенести в \`$NEW_DB_VOLUME\` при необходимости" )
|
||||||
|
fi
|
||||||
|
if ((compose_has_caddy)); then
|
||||||
|
for i in 0 1; do
|
||||||
|
source="${OLD_CADDY_VOLUMES[$i]}"
|
||||||
|
target="${NEW_CADDY_VOLUMES[$i]}"
|
||||||
|
if volume_exists "$source"; then
|
||||||
|
summary+=( "проверить том \`$source\` и перенести в \`$target\` при необходимости" )
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if is_old_postgres_host; then
|
||||||
|
summary+=( "обновить \`POSTGRES_HOST\` в \`.env\`" )
|
||||||
|
fi
|
||||||
|
summary+=( "запустить compose-файл \`$(basename "$compose_file")\`" )
|
||||||
|
|
||||||
|
if [[ "$assume_yes" != "1" ]]; then
|
||||||
|
if [[ ! -t 0 ]]; then
|
||||||
|
die "Скрипт ожидает интерактивное подтверждение. Запустите с \`ASSUME_YES=1\` для неинтерактивного режима."
|
||||||
|
fi
|
||||||
|
log "План миграции:"
|
||||||
|
for name in "${summary[@]}"; do
|
||||||
|
log " - $name"
|
||||||
|
done
|
||||||
|
read -r -p "Продолжить? [y/N]: " answer
|
||||||
|
case "$answer" in
|
||||||
|
y|Y|yes|YES|Yes)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Миграция отменена пользователем."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "1. Останавливаю старый стек"
|
||||||
|
if ((${#running_containers[@]})); then
|
||||||
|
for name in "${running_containers[@]}"; do
|
||||||
|
stop_container "$name"
|
||||||
|
log " - контейнер \`$name\` остановлен/удалён"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
log " - запущенных контейнеров старой схемы не найдено"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$new_origin_url" && "$current_origin" != "$new_origin_url" ]]; then
|
||||||
|
log "2. Обновляю origin"
|
||||||
|
run git -C "$ROOT" remote set-url "$git_remote" "$new_origin_url"
|
||||||
|
else
|
||||||
|
log "2. Origin уже актуален, пропускаю"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "3. Обновляю git до ветки \`$target_branch\`"
|
||||||
|
run git -C "$ROOT" fetch "$git_remote" "$target_branch"
|
||||||
|
|
||||||
|
current_branch="$(git -C "$ROOT" branch --show-current || true)"
|
||||||
|
if [[ -z "$current_branch" ]]; then
|
||||||
|
current_branch="$(git -C "$ROOT" rev-parse --abbrev-ref HEAD)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$current_branch" != "$target_branch" ]]; then
|
||||||
|
if git -C "$ROOT" show-ref --verify --quiet "refs/heads/$target_branch"; then
|
||||||
|
run git -C "$ROOT" switch "$target_branch"
|
||||||
|
else
|
||||||
|
run git -C "$ROOT" switch -c "$target_branch" --track "$git_remote/$target_branch"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log " - уже на ветке \`$target_branch\`"
|
||||||
|
fi
|
||||||
|
|
||||||
|
remote_ref="$(git -C "$ROOT" rev-parse "$git_remote/$target_branch")"
|
||||||
|
head_commit="$(git -C "$ROOT" rev-parse HEAD)"
|
||||||
|
if [[ "$head_commit" != "$remote_ref" ]]; then
|
||||||
|
run git -C "$ROOT" pull --ff-only "$git_remote" "$target_branch"
|
||||||
|
else
|
||||||
|
log " - локальная ветка уже совпадает с удалённой, \`git pull\` не нужен"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "4. Переношу тома"
|
||||||
|
if copy_volume "$OLD_DB_VOLUME" "$NEW_DB_VOLUME"; then
|
||||||
|
log " - БД перенесена в \`$NEW_DB_VOLUME\`"
|
||||||
|
fi
|
||||||
|
if ((compose_has_caddy)); then
|
||||||
|
for i in 0 1; do
|
||||||
|
source="${OLD_CADDY_VOLUMES[$i]}"
|
||||||
|
target="${NEW_CADDY_VOLUMES[$i]}"
|
||||||
|
if copy_volume "$source" "$target"; then
|
||||||
|
log " - \`$source\` перенесён в \`$target\`"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "5. Обновляю \`.env\`"
|
||||||
|
update_postgres_host
|
||||||
|
|
||||||
|
log "6. Запускаю новый стек"
|
||||||
|
if ((compose_has_build)); then
|
||||||
|
up_args=(up -d --build --remove-orphans)
|
||||||
|
else
|
||||||
|
up_args=(up -d --remove-orphans)
|
||||||
|
fi
|
||||||
|
run "${compose_cmd[@]}" -f "$compose_file" "${up_args[@]}"
|
||||||
|
run "${compose_cmd[@]}" -f "$compose_file" ps
|
||||||
|
|
||||||
|
log "Готово."
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user