Compare commits
11 Commits
415e6f8849
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95383d09fc | ||
|
|
e79b508531 | ||
|
|
8c5696b6aa | ||
|
|
abb6929e19 | ||
|
|
ee39acbeec | ||
|
|
af21f6d16e | ||
|
|
d8cdee91fe | ||
|
|
b0e23312d8 | ||
|
|
43ab81e8d1 | ||
|
|
9300488d2b | ||
|
|
053d7e5855 |
335
UPDATE_SERVER_README.md
Normal file
335
UPDATE_SERVER_README.md
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
# 🚀 Umbrix Update Server - Инструкция
|
||||||
|
|
||||||
|
## 📋 Обзор
|
||||||
|
|
||||||
|
Umbrix использует систему автообновлений через **Sparkle Appcast XML**. Приложение проверяет файл `appcast.xml` на вашем сервере и уведомляет пользователей о новых версиях.
|
||||||
|
|
||||||
|
## 🏗️ Структура системы обновлений
|
||||||
|
|
||||||
|
### 1. **appcast.xml** - Манифест обновлений
|
||||||
|
Находится: `/home/vodorod/dorod/hiddify-umbrix-v1.7.0/appcast.xml`
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 2.5.8</title>
|
||||||
|
<description>🚀 Новые функции...</description>
|
||||||
|
<pubDate>Sat, 18 Jan 2026 06:00:00 +0000</pubDate>
|
||||||
|
<sparkle:version>2.5.8</sparkle:version>
|
||||||
|
|
||||||
|
<!-- Linux DEB -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.deb"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-deb"
|
||||||
|
type="application/x-debian-package" />
|
||||||
|
</item>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. **Настройки в коде**
|
||||||
|
Файл: `lib/core/model/constants.dart`
|
||||||
|
|
||||||
|
```dart
|
||||||
|
// URL вашего сервера appcast.xml
|
||||||
|
static const appCastUrl = "http://localhost:8000/api/appcast.xml";
|
||||||
|
|
||||||
|
// Для публичного домена:
|
||||||
|
// static const appCastUrl = "https://updates.umbrix.net/appcast.xml";
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📂 Структура веб-сервера
|
||||||
|
|
||||||
|
```
|
||||||
|
/home/vodorod/update-server/
|
||||||
|
├── api/
|
||||||
|
│ └── appcast.xml # Копия из проекта
|
||||||
|
├── downloads/ # Файлы обновлений
|
||||||
|
│ ├── umbrix-2.5.8-linux.deb
|
||||||
|
│ ├── umbrix-2.5.8-linux.rpm
|
||||||
|
│ ├── umbrix-2.5.8-linux.AppImage
|
||||||
|
│ └── umbrix-2.5.8-windows.exe
|
||||||
|
└── admin/ # Ваш Update Manager (localhost:8000/admin/)
|
||||||
|
└── index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 Процесс публикации обновления
|
||||||
|
|
||||||
|
### Шаг 1: Собрать новую версию
|
||||||
|
```bash
|
||||||
|
cd ~/dorod/hiddify-umbrix-v1.7.0
|
||||||
|
./build-all-packages.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 2: Скопировать файлы на сервер
|
||||||
|
```bash
|
||||||
|
# Создать папку для версии
|
||||||
|
mkdir -p /home/vodorod/update-server/downloads/
|
||||||
|
|
||||||
|
# Скопировать пакеты
|
||||||
|
cp dist/2.5.8+258/umbrix-2.5.8+258-linux.deb \
|
||||||
|
/home/vodorod/update-server/downloads/umbrix-2.5.8-linux.deb
|
||||||
|
|
||||||
|
cp dist/2.5.8+258/umbrix-2.5.8+258-linux.rpm \
|
||||||
|
/home/vodorod/update-server/downloads/umbrix-2.5.8-linux.rpm
|
||||||
|
|
||||||
|
cp dist/2.5.8+258/umbrix-2.5.8+258-linux.AppImage \
|
||||||
|
/home/vodorod/update-server/downloads/umbrix-2.5.8-linux.AppImage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 3: Обновить appcast.xml
|
||||||
|
|
||||||
|
Раскомментируйте и измените секцию в `appcast.xml`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 2.5.8</title>
|
||||||
|
<description>🚀 Новые функции:
|
||||||
|
- Улучшена стабильность
|
||||||
|
- Исправлены ошибки</description>
|
||||||
|
<pubDate>Sat, 18 Jan 2026 06:00:00 +0000</pubDate>
|
||||||
|
<sparkle:version>2.5.8</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>2.5.8</sparkle:shortVersionString>
|
||||||
|
<sparkle:minimumSystemVersion>2.0.0</sparkle:minimumSystemVersion>
|
||||||
|
|
||||||
|
<!-- Linux DEB (Debian/Ubuntu) -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.deb"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-deb"
|
||||||
|
type="application/x-debian-package"
|
||||||
|
length="30000000" />
|
||||||
|
|
||||||
|
<!-- Linux RPM (Fedora/CentOS) -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.rpm"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-rpm"
|
||||||
|
type="application/x-rpm"
|
||||||
|
length="36000000" />
|
||||||
|
|
||||||
|
<!-- Linux AppImage (Universal) -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.AppImage"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-appimage"
|
||||||
|
type="application/x-appimage"
|
||||||
|
length="38000000" />
|
||||||
|
</item>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 4: Скопировать appcast.xml на сервер
|
||||||
|
```bash
|
||||||
|
cp appcast.xml /home/vodorod/update-server/api/appcast.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 Запуск локального сервера
|
||||||
|
|
||||||
|
### Вариант 1: Python HTTP сервер (простой)
|
||||||
|
```bash
|
||||||
|
cd /home/vodorod/update-server
|
||||||
|
python3 -m http.server 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
Доступ:
|
||||||
|
- Appcast: `http://localhost:8000/api/appcast.xml`
|
||||||
|
- Скачивания: `http://localhost:8000/downloads/`
|
||||||
|
- Admin: `http://localhost:8000/admin/`
|
||||||
|
|
||||||
|
### Вариант 2: Nginx (продакшн)
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 8000;
|
||||||
|
server_name localhost;
|
||||||
|
root /home/vodorod/update-server;
|
||||||
|
|
||||||
|
location /api/appcast.xml {
|
||||||
|
add_header Content-Type application/xml;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /downloads/ {
|
||||||
|
autoindex on;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📱 Про поле "URL для скачивания APK" в веб-интерфейсе
|
||||||
|
|
||||||
|
**ВАЖНО**: Это поле осталось от оригинального Hiddify (Android приложение). Для **Umbrix Linux десктоп** оно **НЕ используется**.
|
||||||
|
|
||||||
|
Umbrix для Linux использует:
|
||||||
|
- ✅ **DEB пакеты** (Debian/Ubuntu)
|
||||||
|
- ✅ **RPM пакеты** (Fedora/CentOS)
|
||||||
|
- ✅ **AppImage** (универсальный формат)
|
||||||
|
|
||||||
|
Поле "APK" в веб-интерфейсе можно:
|
||||||
|
1. **Игнорировать** (оставить пустым)
|
||||||
|
2. **Переименовать** в "URL для скачивания DEB/RPM/AppImage"
|
||||||
|
3. **Удалить** из веб-интерфейса
|
||||||
|
|
||||||
|
## 🔐 Безопасность
|
||||||
|
|
||||||
|
### Для продакшн (публичный домен):
|
||||||
|
|
||||||
|
1. **HTTPS обязателен**:
|
||||||
|
```dart
|
||||||
|
static const appCastUrl = "https://updates.umbrix.net/appcast.xml";
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Подписывание обновлений** (Sparkle поддерживает):
|
||||||
|
```bash
|
||||||
|
# Генерация ключей
|
||||||
|
openssl genrsa -out private_key.pem 2048
|
||||||
|
openssl rsa -in private_key.pem -pubout > public_key.pem
|
||||||
|
|
||||||
|
# Подпись файла
|
||||||
|
openssl dgst -sha256 -sign private_key.pem \
|
||||||
|
umbrix-2.5.8-linux.deb > signature.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Добавить signature в appcast.xml**:
|
||||||
|
```xml
|
||||||
|
<enclosure
|
||||||
|
url="https://updates.umbrix.net/downloads/umbrix-2.5.8-linux.deb"
|
||||||
|
sparkle:dsaSignature="MC0CFQCqfTq..." />
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🧪 Тестирование
|
||||||
|
|
||||||
|
### 1. Проверить доступность appcast.xml
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8000/api/appcast.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Проверить в приложении
|
||||||
|
- Запустить Umbrix
|
||||||
|
- Зайти в Настройки → Проверить обновления
|
||||||
|
- Приложение скачает appcast.xml и покажет уведомление о новой версии
|
||||||
|
|
||||||
|
### 3. Логи отладки
|
||||||
|
В коде установлен `_debugUpgrader = true`, логи будут в консоли:
|
||||||
|
```
|
||||||
|
[UPGRADER] Checking appcast: http://localhost:8000/api/appcast.xml
|
||||||
|
[UPGRADER] Current version: 1.7.0
|
||||||
|
[UPGRADER] Latest version: 2.5.8
|
||||||
|
[UPGRADER] Update available!
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Мониторинг скачиваний
|
||||||
|
|
||||||
|
### Вариант 1: Nginx access.log
|
||||||
|
```bash
|
||||||
|
tail -f /var/log/nginx/access.log | grep "/downloads/"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Вариант 2: Python скрипт с логированием
|
||||||
|
```python
|
||||||
|
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class LoggingHandler(SimpleHTTPRequestHandler):
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
print(f"[{datetime.datetime.now()}] {args[0]}")
|
||||||
|
|
||||||
|
HTTPServer(('', 8000), LoggingHandler).serve_forever()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Миграция на публичный домен
|
||||||
|
|
||||||
|
Когда будете готовы к продакшну:
|
||||||
|
|
||||||
|
1. **Купить домен**: `updates.umbrix.net`
|
||||||
|
|
||||||
|
2. **Настроить DNS**:
|
||||||
|
```
|
||||||
|
A updates.umbrix.net → 123.45.67.89
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Изменить в коде**:
|
||||||
|
```dart
|
||||||
|
static const appCastUrl = "https://updates.umbrix.net/appcast.xml";
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Пересобрать и выпустить обновление**:
|
||||||
|
```bash
|
||||||
|
./build-all-packages.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Все последующие версии** будут проверять новый домен
|
||||||
|
|
||||||
|
## ❓ FAQ
|
||||||
|
|
||||||
|
### Q: Как часто приложение проверяет обновления?
|
||||||
|
A: Раз в 12 часов (настройка `durationUntilAlertAgain`)
|
||||||
|
|
||||||
|
### Q: Можно ли принудительно проверить обновления?
|
||||||
|
A: Да, через меню "Настройки → Проверить обновления"
|
||||||
|
|
||||||
|
### Q: Что делать, если обновление не находится?
|
||||||
|
A: Проверьте:
|
||||||
|
1. Доступен ли `appcast.xml` по URL
|
||||||
|
2. Версия в `<sparkle:version>` больше текущей
|
||||||
|
3. Логи отладки в консоли приложения
|
||||||
|
|
||||||
|
### Q: Как откатить обновление?
|
||||||
|
A: Удалите или закомментируйте `<item>` новой версии в `appcast.xml`
|
||||||
|
|
||||||
|
## 📝 Пример полного appcast.xml
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||||
|
<channel>
|
||||||
|
<title>Umbrix Updates</title>
|
||||||
|
<description>Umbrix VPN автообновления</description>
|
||||||
|
<link>http://localhost:8000</link>
|
||||||
|
<language>ru</language>
|
||||||
|
|
||||||
|
<!-- Новая версия 2.5.8 -->
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 2.5.8</title>
|
||||||
|
<description>🚀 Новые функции:
|
||||||
|
- Улучшена стабильность
|
||||||
|
- Исправлены ошибки
|
||||||
|
- Добавлена поддержка новых протоколов</description>
|
||||||
|
<pubDate>Sat, 18 Jan 2026 06:00:00 +0000</pubDate>
|
||||||
|
<sparkle:version>2.5.8</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>2.5.8</sparkle:shortVersionString>
|
||||||
|
<sparkle:minimumSystemVersion>2.0.0</sparkle:minimumSystemVersion>
|
||||||
|
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.deb"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-deb"
|
||||||
|
type="application/x-debian-package"
|
||||||
|
length="30000000" />
|
||||||
|
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.rpm"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-rpm"
|
||||||
|
type="application/x-rpm"
|
||||||
|
length="36000000" />
|
||||||
|
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.AppImage"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-appimage"
|
||||||
|
type="application/x-appimage"
|
||||||
|
length="38000000" />
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<!-- Текущая версия 1.7.0 -->
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 1.7.0</title>
|
||||||
|
<description>Стабильный релиз</description>
|
||||||
|
<pubDate>Fri, 17 Jan 2026 08:49:07 +0000</pubDate>
|
||||||
|
<sparkle:version>1.7.0</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>1.7.0</sparkle:shortVersionString>
|
||||||
|
</item>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Готово!
|
||||||
|
|
||||||
|
Теперь система обновлений полностью настроена и готова к использованию!
|
||||||
60
appcast.xml
60
appcast.xml
@@ -2,6 +2,64 @@
|
|||||||
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||||
<channel>
|
<channel>
|
||||||
<title>Umbrix Updates</title>
|
<title>Umbrix Updates</title>
|
||||||
<!-- No updates available - this is Umbrix, not Hiddify -->
|
<description>Umbrix VPN автообновления</description>
|
||||||
|
<link>http://localhost:8000</link>
|
||||||
|
<language>ru</language>
|
||||||
|
|
||||||
|
<!-- Пример структуры для обновления версии 2.5.8 -->
|
||||||
|
<!-- Раскомментируйте и измените, когда будет новая версия -->
|
||||||
|
<!--
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 2.5.8</title>
|
||||||
|
<description>🚀 Новые функции:
|
||||||
|
- Улучшена стабильность
|
||||||
|
- Исправлены ошибки</description>
|
||||||
|
<pubDate>Sat, 18 Jan 2026 06:00:00 +0000</pubDate>
|
||||||
|
<sparkle:version>2.5.8</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>2.5.8</sparkle:shortVersionString>
|
||||||
|
<sparkle:minimumSystemVersion>2.0.0</sparkle:minimumSystemVersion>
|
||||||
|
|
||||||
|
<!-- Linux DEB (Debian/Ubuntu) -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.deb"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-deb"
|
||||||
|
type="application/x-debian-package"
|
||||||
|
length="30000000" />
|
||||||
|
|
||||||
|
<!-- Linux RPM (Fedora/CentOS) -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.rpm"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-rpm"
|
||||||
|
type="application/x-rpm"
|
||||||
|
length="36000000" />
|
||||||
|
|
||||||
|
<!-- Linux AppImage (Universal) -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-linux.AppImage"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="linux-appimage"
|
||||||
|
type="application/x-appimage"
|
||||||
|
length="38000000" />
|
||||||
|
|
||||||
|
<!-- Windows EXE -->
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-2.5.8-windows.exe"
|
||||||
|
sparkle:version="2.5.8"
|
||||||
|
sparkle:os="windows"
|
||||||
|
type="application/x-msdownload"
|
||||||
|
length="45000000" />
|
||||||
|
</item>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Текущая версия 1.7.0 (без обновлений) -->
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 1.7.0</title>
|
||||||
|
<description>Стабильный релиз</description>
|
||||||
|
<pubDate>Fri, 17 Jan 2026 08:49:07 +0000</pubDate>
|
||||||
|
<sparkle:version>1.7.0</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>1.7.0</sparkle:shortVersionString>
|
||||||
|
</item>
|
||||||
</channel>
|
</channel>
|
||||||
</rss>
|
</rss>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ echo -e "${GREEN}✓${NC} Custom libcore integrated: $NEW_SIZE"
|
|||||||
# Step 5: Add icon and prepare data directory
|
# Step 5: Add icon and prepare data directory
|
||||||
echo -e "\n${YELLOW}[5/6]${NC} Preparing bundle assets..."
|
echo -e "\n${YELLOW}[5/6]${NC} Preparing bundle assets..."
|
||||||
cp -f "$PROJECT_DIR/logo/ic_launcher_playstore.png" "$BUNDLE_DIR/umbrix.png"
|
cp -f "$PROJECT_DIR/logo/ic_launcher_playstore.png" "$BUNDLE_DIR/umbrix.png"
|
||||||
|
chmod 644 "$BUNDLE_DIR/umbrix.png"
|
||||||
mkdir -p "$BUNDLE_DIR/data"
|
mkdir -p "$BUNDLE_DIR/data"
|
||||||
echo -e "${GREEN}✓${NC} Icon and data directory ready"
|
echo -e "${GREEN}✓${NC} Icon and data directory ready"
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
abstract class Constants {
|
abstract class Constants {
|
||||||
static const appName = "Umbrix";
|
static const appName = "Umbrix";
|
||||||
static const githubUrl = "https://github.com/umbrix-app/umbrix";
|
static const githubUrl = "https://update.umbrix.net/vodorod/umbrix";
|
||||||
static const githubReleasesApiUrl = "https://api.github.com/repos/umbrix-app/umbrix/releases";
|
static const githubReleasesApiUrl = "https://update.umbrix.net/api/v1/repos/vodorod/umbrix/releases";
|
||||||
static const githubLatestReleaseUrl = "https://github.com/umbrix-app/umbrix/releases/latest";
|
static const githubLatestReleaseUrl = "https://update.umbrix.net/vodorod/umbrix/releases/latest";
|
||||||
static const appCastUrl = "https://raw.githubusercontent.com/umbrix-app/umbrix/main/appcast.xml";
|
static const appCastUrl = "http://localhost:8000/api/appcast.xml";
|
||||||
static const telegramChannelUrl = "https://t.me/umbrix_app";
|
static const telegramChannelUrl = "https://t.me/umbrix_app";
|
||||||
static const privacyPolicyUrl = "https://umbrix.net/privacy.html";
|
static const privacyPolicyUrl = "https://umbrix.net/privacy.html";
|
||||||
static const termsAndConditionsUrl = "https://umbrix.net/terms.html";
|
static const termsAndConditionsUrl = "https://umbrix.net/terms.html";
|
||||||
@@ -15,14 +15,17 @@ abstract class Constants {
|
|||||||
// Собственный сервер обновлений (для приватного репозитория)
|
// Собственный сервер обновлений (для приватного репозитория)
|
||||||
// 📝 ИНСТРУКЦИЯ: Замените на URL вашего API сервера
|
// 📝 ИНСТРУКЦИЯ: Замените на URL вашего API сервера
|
||||||
// Пример: "https://api.umbrix.net/api/latest"
|
// Пример: "https://api.umbrix.net/api/latest"
|
||||||
// 🧪 Для тестирования в эмуляторе используйте: "http://10.0.2.2:8000/api.php"
|
// 🖥️ Для Linux десктопа используйте: "http://localhost:8000/api/appcast.xml"
|
||||||
|
// 📱 Для Android эмулятора используйте: "http://10.0.2.2:8000/api/appcast.xml"
|
||||||
// См. документацию в папке: update-server/README.md
|
// См. документацию в папке: update-server/README.md
|
||||||
static const customUpdateServerUrl = "http://10.0.2.2:8000/api.php";
|
|
||||||
|
// ТЕСТ: Используем httpbin.org для демонстрации (возвращает тестовые данные)
|
||||||
|
static const customUpdateServerUrl = "https://httpbin.org/json";
|
||||||
|
|
||||||
// Использовать собственный сервер обновлений вместо GitHub
|
// Использовать собственный сервер обновлений вместо GitHub
|
||||||
// true = использовать customUpdateServerUrl (для приватного репозитория)
|
// true = использовать customUpdateServerUrl (для приватного репозитория)
|
||||||
// false = использовать GitHub Releases (для публичного репозитория)
|
// false = использовать GitHub Releases (для публичного репозитория)
|
||||||
static const useCustomUpdateServer = true;
|
static const useCustomUpdateServer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const kAnimationDuration = Duration(milliseconds: 250);
|
const kAnimationDuration = Duration(milliseconds: 250);
|
||||||
|
|||||||
@@ -50,26 +50,26 @@ GoRouter router(RouterRef ref) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final tabLocations = [
|
final tabLocations = [
|
||||||
const HomeRoute().location, // 0: Главная
|
const HomeRoute().location, // 0: Главная
|
||||||
const ProxiesRoute().location, // 1: Локации
|
const ProxiesRoute().location, // 1: Локации
|
||||||
const PerAppProxyRoute().location, // 2: Исключения
|
const PerAppProxyRoute().location, // 2: Исключения
|
||||||
const SettingsRoute().location, // 3: Настройки
|
const SettingsRoute().location, // 3: Настройки
|
||||||
const AboutRoute().location, // 4: О программе
|
const AboutRoute().location, // 4: О программе
|
||||||
];
|
];
|
||||||
|
|
||||||
int getCurrentIndex(BuildContext context) {
|
int getCurrentIndex(BuildContext context) {
|
||||||
final String location = GoRouterState.of(context).uri.path;
|
final String location = GoRouterState.of(context).uri.path;
|
||||||
|
|
||||||
// Проверяем точное совпадение для главной
|
// Проверяем точное совпадение для главной
|
||||||
if (location == const HomeRoute().location) return 0;
|
if (location == const HomeRoute().location) return 0;
|
||||||
|
|
||||||
// Проверяем остальные маршруты по порядку
|
// Проверяем остальные маршруты по порядку
|
||||||
// ВАЖНО: более длинные пути проверяем раньше!
|
// ВАЖНО: более длинные пути проверяем раньше!
|
||||||
if (location.startsWith(const PerAppProxyRoute().location)) return 2; // /settings/per-app-proxy
|
if (location.startsWith(const PerAppProxyRoute().location)) return 2; // /settings/per-app-proxy
|
||||||
if (location.startsWith(const ProxiesRoute().location)) return 1; // /proxies
|
if (location.startsWith(const ProxiesRoute().location)) return 1; // /proxies
|
||||||
if (location.startsWith(const SettingsRoute().location)) return 3; // /settings
|
if (location.startsWith(const SettingsRoute().location)) return 3; // /settings
|
||||||
if (location.startsWith(const AboutRoute().location)) return 4; // /about
|
if (location.startsWith(const AboutRoute().location)) return 4; // /about
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,20 @@ abstract class GithubReleaseParser {
|
|||||||
}
|
}
|
||||||
final preRelease = json["prerelease"] as bool;
|
final preRelease = json["prerelease"] as bool;
|
||||||
final publishedAt = DateTime.parse(json["published_at"] as String);
|
final publishedAt = DateTime.parse(json["published_at"] as String);
|
||||||
|
|
||||||
|
// Парсим assets
|
||||||
|
final List<ReleaseAsset> assets = [];
|
||||||
|
if (json["assets"] != null) {
|
||||||
|
for (final assetJson in json["assets"] as List) {
|
||||||
|
final asset = assetJson as Map<String, dynamic>;
|
||||||
|
assets.add(ReleaseAsset(
|
||||||
|
name: asset["name"] as String,
|
||||||
|
downloadUrl: asset["browser_download_url"] as String,
|
||||||
|
size: asset["size"] as int,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return RemoteVersionEntity(
|
return RemoteVersionEntity(
|
||||||
version: version,
|
version: version,
|
||||||
buildNumber: buildNumber,
|
buildNumber: buildNumber,
|
||||||
@@ -31,6 +45,7 @@ abstract class GithubReleaseParser {
|
|||||||
url: json["html_url"] as String,
|
url: json["html_url"] as String,
|
||||||
publishedAt: publishedAt,
|
publishedAt: publishedAt,
|
||||||
flavor: flavor,
|
flavor: flavor,
|
||||||
|
assets: assets,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,27 @@ class RemoteVersionEntity with _$RemoteVersionEntity {
|
|||||||
required String url,
|
required String url,
|
||||||
required DateTime publishedAt,
|
required DateTime publishedAt,
|
||||||
required Environment flavor,
|
required Environment flavor,
|
||||||
|
@Default([]) List<ReleaseAsset> assets,
|
||||||
}) = _RemoteVersionEntity;
|
}) = _RemoteVersionEntity;
|
||||||
|
|
||||||
String get presentVersion =>
|
String get presentVersion =>
|
||||||
flavor == Environment.prod ? version : "$version ${flavor.name}";
|
flavor == Environment.prod ? version : "$version ${flavor.name}";
|
||||||
|
|
||||||
|
/// Найти asset по расширению файла
|
||||||
|
String? findAssetByExtension(String extension) {
|
||||||
|
try {
|
||||||
|
return assets.firstWhere((asset) => asset.name.endsWith(extension)).downloadUrl;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class ReleaseAsset with _$ReleaseAsset {
|
||||||
|
const factory ReleaseAsset({
|
||||||
|
required String name,
|
||||||
|
required String downloadUrl,
|
||||||
|
required int size,
|
||||||
|
}) = _ReleaseAsset;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:umbrix/core/app_info/app_info_provider.dart';
|
import 'package:umbrix/core/app_info/app_info_provider.dart';
|
||||||
import 'package:umbrix/core/localization/locale_preferences.dart';
|
import 'package:umbrix/core/localization/locale_preferences.dart';
|
||||||
|
import 'package:umbrix/core/model/constants.dart';
|
||||||
import 'package:umbrix/core/preferences/preferences_provider.dart';
|
import 'package:umbrix/core/preferences/preferences_provider.dart';
|
||||||
import 'package:umbrix/core/utils/preferences_utils.dart';
|
import 'package:umbrix/core/utils/preferences_utils.dart';
|
||||||
import 'package:umbrix/features/app_update/data/app_update_data_providers.dart';
|
import 'package:umbrix/features/app_update/data/app_update_data_providers.dart';
|
||||||
@@ -18,7 +19,7 @@ const _debugUpgrader = true;
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Upgrader upgrader(UpgraderRef ref) => Upgrader(
|
Upgrader upgrader(UpgraderRef ref) => Upgrader(
|
||||||
// Removed appcastConfig - no updates for Umbrix
|
appcastConfig: AppcastConfiguration(url: Constants.appCastUrl),
|
||||||
debugLogging: _debugUpgrader && kDebugMode,
|
debugLogging: _debugUpgrader && kDebugMode,
|
||||||
durationUntilAlertAgain: const Duration(hours: 12),
|
durationUntilAlertAgain: const Duration(hours: 12),
|
||||||
messages: UpgraderMessages(
|
messages: UpgraderMessages(
|
||||||
|
|||||||
@@ -57,23 +57,55 @@ class NewVersionDialog extends HookConsumerWidget with PresLogger {
|
|||||||
downloadProgress.value = 0.0;
|
downloadProgress.value = 0.0;
|
||||||
|
|
||||||
final tempDir = await getTemporaryDirectory();
|
final tempDir = await getTemporaryDirectory();
|
||||||
|
|
||||||
|
// Определяем нужное расширение файла
|
||||||
String fileExt = '';
|
String fileExt = '';
|
||||||
if (Platform.isWindows)
|
if (Platform.isWindows)
|
||||||
fileExt = '.exe';
|
fileExt = '.exe';
|
||||||
else if (Platform.isMacOS)
|
else if (Platform.isMacOS)
|
||||||
fileExt = '.dmg';
|
fileExt = '.dmg';
|
||||||
else if (Platform.isLinux) fileExt = '.AppImage';
|
else if (Platform.isLinux)
|
||||||
|
fileExt = '.deb';
|
||||||
|
|
||||||
|
// Ищем asset с нужным расширением
|
||||||
|
final downloadUrl = newVersion.findAssetByExtension(fileExt);
|
||||||
|
|
||||||
|
if (downloadUrl == null) {
|
||||||
|
if (context.mounted) {
|
||||||
|
CustomToast.error('Файл установки $fileExt не найден в релизе').show(context);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final savePath = '${tempDir.path}/umbrix-${newVersion.version}$fileExt';
|
final savePath = '${tempDir.path}/umbrix-${newVersion.version}$fileExt';
|
||||||
final file = File(savePath);
|
final file = File(savePath);
|
||||||
if (await file.exists()) await file.delete();
|
if (await file.exists()) await file.delete();
|
||||||
|
|
||||||
final dio = Dio();
|
final dio = Dio();
|
||||||
await dio.download(newVersion.url, savePath, onReceiveProgress: (received, total) {
|
await dio.download(downloadUrl, savePath, onReceiveProgress: (received, total) {
|
||||||
if (total != -1) downloadProgress.value = received / total;
|
if (total != -1) downloadProgress.value = received / total;
|
||||||
});
|
});
|
||||||
|
|
||||||
loggy.info('Update downloaded to: $savePath');
|
loggy.info('Update downloaded to: $savePath');
|
||||||
|
|
||||||
|
// Для Linux DEB - запускаем установку через системный установщик пакетов
|
||||||
|
if (Platform.isLinux && fileExt == '.deb') {
|
||||||
|
try {
|
||||||
|
// Пытаемся установить через pkexec apt install
|
||||||
|
final result = await Process.run('pkexec', ['apt', 'install', '-y', savePath]);
|
||||||
|
if (result.exitCode == 0) {
|
||||||
|
if (context.mounted) {
|
||||||
|
CustomToast.success('Обновление установлено! Перезапустите приложение.').show(context);
|
||||||
|
context.pop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
loggy.warning('Failed to install via pkexec apt: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для других платформ или если apt не сработал - просто открываем файл
|
||||||
final result = await OpenFile.open(savePath);
|
final result = await OpenFile.open(savePath);
|
||||||
|
|
||||||
if (result.type != ResultType.done && context.mounted) {
|
if (result.type != ResultType.done && context.mounted) {
|
||||||
|
|||||||
@@ -172,49 +172,49 @@ class _CustomAdaptiveScaffold extends HookConsumerWidget {
|
|||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
children: [
|
children: [
|
||||||
// О программе
|
// О программе
|
||||||
Builder(
|
Builder(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final t = ref.watch(translationsProvider);
|
final t = ref.watch(translationsProvider);
|
||||||
return _DrawerMenuItem(
|
return _DrawerMenuItem(
|
||||||
icon: FluentIcons.info_24_regular,
|
icon: FluentIcons.info_24_regular,
|
||||||
selectedIcon: FluentIcons.info_24_filled,
|
selectedIcon: FluentIcons.info_24_filled,
|
||||||
label: t.about.pageTitle,
|
label: t.about.pageTitle,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
RootScaffold.stateKey.currentState?.closeDrawer();
|
RootScaffold.stateKey.currentState?.closeDrawer();
|
||||||
const AboutRoute().push(context);
|
const AboutRoute().push(context);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
|
||||||
// Настройки
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final t = ref.watch(translationsProvider);
|
|
||||||
return _DrawerMenuItem(
|
|
||||||
icon: FluentIcons.settings_24_regular,
|
|
||||||
selectedIcon: FluentIcons.settings_24_filled,
|
|
||||||
label: t.settings.pageTitle,
|
|
||||||
isSelected: false,
|
|
||||||
onTap: () {
|
|
||||||
RootScaffold.stateKey.currentState?.closeDrawer();
|
|
||||||
const SettingsRoute().push(context);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
const Divider(),
|
|
||||||
const _DrawerThemeItem(),
|
|
||||||
const _DrawerLanguageItem(),
|
|
||||||
const _DrawerLicensesItem(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
// Настройки
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final t = ref.watch(translationsProvider);
|
||||||
|
return _DrawerMenuItem(
|
||||||
|
icon: FluentIcons.settings_24_regular,
|
||||||
|
selectedIcon: FluentIcons.settings_24_filled,
|
||||||
|
label: t.settings.pageTitle,
|
||||||
|
isSelected: false,
|
||||||
|
onTap: () {
|
||||||
|
RootScaffold.stateKey.currentState?.closeDrawer();
|
||||||
|
const SettingsRoute().push(context);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Divider(),
|
||||||
|
const _DrawerThemeItem(),
|
||||||
|
const _DrawerLanguageItem(),
|
||||||
|
const _DrawerLicensesItem(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
body: AdaptiveLayout(
|
body: AdaptiveLayout(
|
||||||
primaryNavigation: SlotLayout(
|
primaryNavigation: SlotLayout(
|
||||||
config: <Breakpoint, SlotLayoutConfig>{
|
config: <Breakpoint, SlotLayoutConfig>{
|
||||||
|
|||||||
@@ -67,16 +67,16 @@ class PerAppProxyPage extends HookConsumerWidget with PresLogger {
|
|||||||
tooltip: localizations.searchFieldLabel,
|
tooltip: localizations.searchFieldLabel,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
bottom: PlatformUtils.isDesktop
|
bottom: PlatformUtils.isDesktop
|
||||||
? null // На Desktop только вкладка "Домены"
|
? null // На Desktop только вкладка "Домены"
|
||||||
: TabBar(
|
: TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
onTap: (index) => currentTab.value = index,
|
onTap: (index) => currentTab.value = index,
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(text: t.settings.network.excludedDomains.domainsTab),
|
Tab(text: t.settings.network.excludedDomains.domainsTab),
|
||||||
Tab(text: t.settings.network.excludedDomains.appsTab),
|
Tab(text: t.settings.network.excludedDomains.appsTab),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final searchAppBar = SliverAppBar(
|
final searchAppBar = SliverAppBar(
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ class WindowNotifier extends _$WindowNotifier with AppLogger {
|
|||||||
Future<void> build() async {
|
Future<void> build() async {
|
||||||
if (!PlatformUtils.isDesktop) return;
|
if (!PlatformUtils.isDesktop) return;
|
||||||
|
|
||||||
// if (Platform.isWindows) {
|
|
||||||
// loggy.debug("ensuring single instance");
|
|
||||||
// await WindowsSingleInstance.ensureSingleInstance([], "Hiddify");
|
|
||||||
// }
|
|
||||||
|
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
await windowManager.setMinimumSize(minimumWindowSize);
|
await windowManager.setMinimumSize(minimumWindowSize);
|
||||||
await windowManager.setSize(defaultWindowSize);
|
await windowManager.setSize(defaultWindowSize);
|
||||||
|
|||||||
@@ -108,8 +108,14 @@ install(CODE "
|
|||||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||||
|
|
||||||
install(FILES "../libcore/bin/lib/libcore.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
# Install custom libcore (49MB with FFI parse function)
|
||||||
COMPONENT Runtime)
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../libcore/bin/lib/libcore.so")
|
||||||
|
install(FILES "../libcore/bin/lib/libcore.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
message(STATUS "Custom libcore.so will be installed")
|
||||||
|
else()
|
||||||
|
message(WARNING "Custom libcore.so not found, application may fail at runtime")
|
||||||
|
endif()
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES "../libcore/bin/HiddifyCli"
|
FILES "../libcore/bin/HiddifyCli"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Name=Umbrix
|
Name=Umbrix
|
||||||
Comment=Cross Platform Multi Protocol Proxy Frontend
|
Comment=Cross Platform Multi Protocol Proxy Frontend
|
||||||
Exec=umbrix %U
|
Exec=umbrix %U
|
||||||
Icon=umbrix
|
Icon=/usr/share/icons/hicolor/256x256/apps/umbrix.png
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Network;
|
Categories=Network;
|
||||||
|
|||||||
@@ -14,12 +14,20 @@ struct _MyApplication
|
|||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||||
#define ICON_PATH "./umbrix.png"
|
#define ICON_PATH "/usr/share/icons/hicolor/256x256/apps/umbrix.png"
|
||||||
|
|
||||||
// Implements GApplication::activate.
|
// Implements GApplication::activate.
|
||||||
static void my_application_activate(GApplication *application)
|
static void my_application_activate(GApplication *application)
|
||||||
{
|
{
|
||||||
MyApplication *self = MY_APPLICATION(application);
|
MyApplication *self = MY_APPLICATION(application);
|
||||||
|
|
||||||
|
// Check if window already exists - if so, just present it
|
||||||
|
GList* windows = gtk_application_get_windows(GTK_APPLICATION(application));
|
||||||
|
if (windows) {
|
||||||
|
gtk_window_present(GTK_WINDOW(windows->data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GtkWindow *window =
|
GtkWindow *window =
|
||||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||||
gtk_window_set_icon_from_file(window, ICON_PATH, NULL);
|
gtk_window_set_icon_from_file(window, ICON_PATH, NULL);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ essential: false
|
|||||||
icon: ./logo/ic_launcher_playstore.png
|
icon: ./logo/ic_launcher_playstore.png
|
||||||
|
|
||||||
postinstall_scripts:
|
postinstall_scripts:
|
||||||
|
- chmod 644 /usr/share/icons/hicolor/256x256/apps/umbrix.png
|
||||||
- echo "Installed Umbrix VPN"
|
- echo "Installed Umbrix VPN"
|
||||||
postuninstall_scripts:
|
postuninstall_scripts:
|
||||||
- echo "Uninstalled Umbrix"
|
- echo "Uninstalled Umbrix"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: umbrix
|
name: umbrix
|
||||||
description: Cross Platform Multi Protocol Proxy Frontend.
|
description: Cross Platform Multi Protocol Proxy Frontend.
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
version: 1.7.0+170
|
version: 1.7.3+173
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.0 <4.0.0"
|
sdk: ">=3.3.0 <4.0.0"
|
||||||
|
|||||||
260
update-server/GITEA_SETUP.md
Normal file
260
update-server/GITEA_SETUP.md
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
# 🚀 Установка Gitea для системы обновлений Umbrix
|
||||||
|
|
||||||
|
## 📋 Подготовка
|
||||||
|
|
||||||
|
### 1. Аренда VPS
|
||||||
|
**Минимальные требования:**
|
||||||
|
- RAM: 1GB (рекомендую 2GB для комфорта)
|
||||||
|
- CPU: 1 vCore
|
||||||
|
- SSD: 20GB
|
||||||
|
- OS: Ubuntu 22.04 / Debian 12
|
||||||
|
|
||||||
|
**Рекомендуемые провайдеры:**
|
||||||
|
- Hetzner Cloud (от €3.79/мес, 2GB RAM)
|
||||||
|
- DigitalOcean Droplet ($6/мес)
|
||||||
|
- Contabo VPS (от €4.99/мес, 4GB RAM)
|
||||||
|
|
||||||
|
### 2. Домены
|
||||||
|
Настройте DNS записи для:
|
||||||
|
```
|
||||||
|
git.umbrix.net → IP вашего сервера
|
||||||
|
git-mirror1.umbrix.net → IP сервера (или другой сервер)
|
||||||
|
git-mirror2.umbrix.net → IP сервера (или другой сервер)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. SSL сертификаты (Let's Encrypt)
|
||||||
|
```bash
|
||||||
|
# Установите certbot
|
||||||
|
sudo apt update && sudo apt install -y certbot
|
||||||
|
|
||||||
|
# Получите сертификаты для всех доменов
|
||||||
|
sudo certbot certonly --standalone -d git.umbrix.net
|
||||||
|
sudo certbot certonly --standalone -d git-mirror1.umbrix.net
|
||||||
|
sudo certbot certonly --standalone -d git-mirror2.umbrix.net
|
||||||
|
|
||||||
|
# Скопируйте в папку nginx/ssl/
|
||||||
|
sudo cp /etc/letsencrypt/live/git.umbrix.net/fullchain.pem nginx/ssl/
|
||||||
|
sudo cp /etc/letsencrypt/live/git.umbrix.net/privkey.pem nginx/ssl/
|
||||||
|
# Повторите для mirror1 и mirror2
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐳 Установка Gitea
|
||||||
|
|
||||||
|
### 1. Установите Docker
|
||||||
|
```bash
|
||||||
|
# Удалите старые версии
|
||||||
|
sudo apt remove docker docker-engine docker.io containerd runc
|
||||||
|
|
||||||
|
# Установите Docker
|
||||||
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sudo sh get-docker.sh
|
||||||
|
|
||||||
|
# Добавьте пользователя в группу docker
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
newgrp docker
|
||||||
|
|
||||||
|
# Установите Docker Compose
|
||||||
|
sudo apt install -y docker-compose
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Загрузите конфигурацию
|
||||||
|
```bash
|
||||||
|
# Создайте папку
|
||||||
|
mkdir -p ~/gitea-server
|
||||||
|
cd ~/gitea-server
|
||||||
|
|
||||||
|
# Скопируйте файлы:
|
||||||
|
# - gitea-docker-compose.yml → docker-compose.yml
|
||||||
|
# - nginx.conf → nginx/nginx.conf
|
||||||
|
|
||||||
|
# Создайте папки для SSL
|
||||||
|
mkdir -p nginx/ssl gitea/data gitea/postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Настройте пароль БД
|
||||||
|
Отредактируйте `docker-compose.yml`:
|
||||||
|
```yaml
|
||||||
|
POSTGRES_PASSWORD=ваш_надёжный_пароль_здесь
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Запустите Gitea
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Первоначальная настройка
|
||||||
|
Откройте браузер: `https://git.umbrix.net`
|
||||||
|
|
||||||
|
**Настройки установки:**
|
||||||
|
- Database Type: `PostgreSQL`
|
||||||
|
- Host: `db:5432`
|
||||||
|
- Username: `gitea`
|
||||||
|
- Password: (ваш пароль из docker-compose.yml)
|
||||||
|
- Database Name: `gitea`
|
||||||
|
- SSH Server Domain: `git.umbrix.net`
|
||||||
|
- Gitea Base URL: `https://git.umbrix.net`
|
||||||
|
- **Отключите регистрацию** (только вы сможете создавать аккаунты)
|
||||||
|
|
||||||
|
## 📦 Создание репозитория и релиза
|
||||||
|
|
||||||
|
### 1. Создайте репозиторий
|
||||||
|
- Войдите в Gitea
|
||||||
|
- Нажмите "+" → "New Repository"
|
||||||
|
- Название: `umbrix`
|
||||||
|
- Visibility: `Public` (для обновлений)
|
||||||
|
|
||||||
|
### 2. Загрузите код (с локальной машины)
|
||||||
|
```bash
|
||||||
|
cd ~/dorod/hiddify-umbrix-v1.7.0
|
||||||
|
|
||||||
|
# Инициализируйте Git (если не инициализирован)
|
||||||
|
git init
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit"
|
||||||
|
|
||||||
|
# Добавьте remote (замените на свой домен)
|
||||||
|
git remote add gitea https://git.umbrix.net/your-username/umbrix.git
|
||||||
|
|
||||||
|
# Запушьте код
|
||||||
|
git push -u gitea main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Создайте релиз
|
||||||
|
**Через UI:**
|
||||||
|
1. Перейдите: Releases → New Release
|
||||||
|
2. Tag: `v1.7.3`
|
||||||
|
3. Title: `Umbrix v1.7.3`
|
||||||
|
4. Описание: (release notes)
|
||||||
|
5. Прикрепите файлы:
|
||||||
|
- `umbrix-1.7.3-linux-x86_64.deb`
|
||||||
|
- `umbrix-1.7.3-linux-x86_64.rpm`
|
||||||
|
- `Umbrix-1.7.3-linux-x86_64.AppImage`
|
||||||
|
|
||||||
|
**Через API:**
|
||||||
|
```bash
|
||||||
|
# Получите Access Token: Настройки → Applications → Generate Token
|
||||||
|
|
||||||
|
curl -X POST "https://git.umbrix.net/api/v1/repos/your-username/umbrix/releases" \
|
||||||
|
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"tag_name": "v1.7.3",
|
||||||
|
"name": "Umbrix v1.7.3",
|
||||||
|
"body": "## Что нового\n- Улучшена стабильность",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Загрузите файлы релиза
|
||||||
|
curl -X POST "https://git.umbrix.net/api/v1/repos/your-username/umbrix/releases/ID/assets" \
|
||||||
|
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||||
|
-F "attachment=@dist/umbrix-1.7.3.deb"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 Настройка Umbrix для Gitea
|
||||||
|
|
||||||
|
Отредактируйте `lib/core/model/constants.dart`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
abstract class Constants {
|
||||||
|
static const appName = "Umbrix";
|
||||||
|
static const githubUrl = "https://git.umbrix.net/your-username/umbrix";
|
||||||
|
static const githubReleasesApiUrl = "https://git.umbrix.net/api/v1/repos/your-username/umbrix/releases";
|
||||||
|
static const githubLatestReleaseUrl = "https://git.umbrix.net/your-username/umbrix/releases/latest";
|
||||||
|
|
||||||
|
// ... остальное без изменений
|
||||||
|
static const useCustomUpdateServer = false; // Используем Gitea API
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пересоберите:**
|
||||||
|
```bash
|
||||||
|
flutter build linux --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 Стратегия зеркал (антиблокировка)
|
||||||
|
|
||||||
|
### Вариант 1: DNS Load Balancing
|
||||||
|
Несколько IP для одного домена:
|
||||||
|
```
|
||||||
|
git.umbrix.net → 1.2.3.4, 5.6.7.8, 9.10.11.12
|
||||||
|
```
|
||||||
|
|
||||||
|
### Вариант 2: Поддомены-зеркала
|
||||||
|
```dart
|
||||||
|
static const githubReleasesApiUrl = List<String>[
|
||||||
|
"https://git.umbrix.net/api/v1/repos/your-username/umbrix/releases",
|
||||||
|
"https://git-mirror1.umbrix.net/api/v1/repos/your-username/umbrix/releases",
|
||||||
|
"https://git-mirror2.umbrix.net/api/v1/repos/your-username/umbrix/releases",
|
||||||
|
];
|
||||||
|
|
||||||
|
// В app_update_repository.dart пробуем по очереди:
|
||||||
|
for (final url in Constants.githubReleasesApiUrl) {
|
||||||
|
try {
|
||||||
|
final response = await httpClient.get(url);
|
||||||
|
if (response.statusCode == 200) return response;
|
||||||
|
} catch (e) {
|
||||||
|
continue; // Пробуем следующее зеркало
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Вариант 3: Cloudflare + Workers
|
||||||
|
Прокси через Cloudflare Workers (обходит блокировки):
|
||||||
|
```javascript
|
||||||
|
// worker.js
|
||||||
|
export default {
|
||||||
|
async fetch(request) {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const targetUrl = "https://git.umbrix.net" + url.pathname;
|
||||||
|
return fetch(targetUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Домен: `updates.umbrix.workers.dev`
|
||||||
|
|
||||||
|
## 📊 Мониторинг
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Логи Gitea
|
||||||
|
docker-compose logs -f gitea
|
||||||
|
|
||||||
|
# Статус
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# Использование ресурсов
|
||||||
|
docker stats
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 Обновление Gitea
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💾 Бэкапы
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Бэкап данных Gitea
|
||||||
|
docker exec -u git gitea gitea dump -c /data/gitea/conf/app.ini
|
||||||
|
|
||||||
|
# Бэкап БД
|
||||||
|
docker exec gitea-db pg_dump -U gitea gitea > backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎉 Готово!
|
||||||
|
|
||||||
|
Теперь у вас:
|
||||||
|
- ✅ Свой GitHub-клон на домене `git.umbrix.net`
|
||||||
|
- ✅ API для проверки обновлений (совместим с GitHub API)
|
||||||
|
- ✅ Зеркала для обхода блокировок
|
||||||
|
- ✅ UI для управления релизами
|
||||||
|
|
||||||
|
**URL releases API:**
|
||||||
|
```
|
||||||
|
https://git.umbrix.net/api/v1/repos/your-username/umbrix/releases
|
||||||
|
```
|
||||||
|
|
||||||
|
Формат ответа идентичен GitHub API!
|
||||||
255
update-server/INSTALL_INSTRUCTIONS.md
Normal file
255
update-server/INSTALL_INSTRUCTIONS.md
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
# 🚀 Инструкция по установке Gitea на сервер 85.208.139.84
|
||||||
|
|
||||||
|
## Шаг 1: Подключение к серверу
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Подключитесь к серверу по SSH
|
||||||
|
ssh root@85.208.139.84
|
||||||
|
# или
|
||||||
|
ssh ваш_пользователь@85.208.139.84
|
||||||
|
```
|
||||||
|
|
||||||
|
## Шаг 2: Загрузка установочного скрипта
|
||||||
|
|
||||||
|
**Вариант A: Через scp (с локальной машины)**
|
||||||
|
```bash
|
||||||
|
cd ~/dorod/hiddify-umbrix-v1.7.0/update-server
|
||||||
|
scp install-gitea.sh root@85.208.139.84:/root/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Вариант B: Прямо на сервере (создать файл)**
|
||||||
|
```bash
|
||||||
|
# На сервере
|
||||||
|
nano install-gitea.sh
|
||||||
|
# Скопируйте содержимое файла install-gitea.sh
|
||||||
|
# Сохраните: Ctrl+O, Enter, Ctrl+X
|
||||||
|
```
|
||||||
|
|
||||||
|
**Вариант C: Через curl (самый простой)**
|
||||||
|
```bash
|
||||||
|
# На сервере, скопируйте файл в интернет и скачайте:
|
||||||
|
curl -O https://ваш-сервер/install-gitea.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Шаг 3: Запуск установки
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Сделайте скрипт исполняемым
|
||||||
|
chmod +x install-gitea.sh
|
||||||
|
|
||||||
|
# Запустите установку
|
||||||
|
sudo ./install-gitea.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Установка займёт **3-5 минут**.
|
||||||
|
|
||||||
|
## Шаг 4: Первоначальная настройка Gitea
|
||||||
|
|
||||||
|
1. Откройте браузер: **http://85.208.139.84:3000**
|
||||||
|
|
||||||
|
2. При первом входе увидите страницу установки:
|
||||||
|
|
||||||
|
**Database Settings:**
|
||||||
|
- Database Type: `PostgreSQL` ✓
|
||||||
|
- Host: `db:5432` ✓
|
||||||
|
- Username: `gitea` ✓
|
||||||
|
- Password: `gitea_secure_pass_2026` ✓
|
||||||
|
- Database Name: `gitea` ✓
|
||||||
|
|
||||||
|
**General Settings:**
|
||||||
|
- Site Title: `Umbrix Updates`
|
||||||
|
- Repository Root Path: `/data/git/repositories` ✓
|
||||||
|
- Git LFS Root Path: `/data/git/lfs` ✓
|
||||||
|
- Run As Username: `git` ✓
|
||||||
|
|
||||||
|
**Server and Third-Party Service Settings:**
|
||||||
|
- SSH Server Domain: `85.208.139.84` ✓
|
||||||
|
- SSH Server Port: `2222` ✓
|
||||||
|
- Gitea HTTP Listen Port: `3000` ✓
|
||||||
|
- Gitea Base URL: `http://85.208.139.84:3000` ✓
|
||||||
|
|
||||||
|
**Email Settings:** (можно пропустить)
|
||||||
|
|
||||||
|
**Administrator Account Settings:**
|
||||||
|
- Administrator Username: `admin` (или ваш логин)
|
||||||
|
- Password: (ваш надёжный пароль)
|
||||||
|
- Email: `admin@umbrix.net`
|
||||||
|
|
||||||
|
3. Нажмите **"Install Gitea"**
|
||||||
|
|
||||||
|
4. Дождитесь завершения установки (10-20 секунд)
|
||||||
|
|
||||||
|
5. Войдите с созданными учётными данными
|
||||||
|
|
||||||
|
## Шаг 5: Создание репозитория Umbrix
|
||||||
|
|
||||||
|
1. После входа нажмите **"+"** → **"New Repository"**
|
||||||
|
|
||||||
|
2. Заполните:
|
||||||
|
- Owner: `admin` (ваш пользователь)
|
||||||
|
- Repository Name: `umbrix`
|
||||||
|
- Description: `Umbrix VPN Application`
|
||||||
|
- Visibility: ☑ **Public** (важно для updates!)
|
||||||
|
- Initialize Repository: ☐ (пустой, заполним с локальной машины)
|
||||||
|
|
||||||
|
3. Нажмите **"Create Repository"**
|
||||||
|
|
||||||
|
## Шаг 6: Загрузка кода с локальной машины
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# На локальной машине
|
||||||
|
cd ~/dorod/hiddify-umbrix-v1.7.0
|
||||||
|
|
||||||
|
# Добавьте remote для Gitea
|
||||||
|
git remote add gitea http://85.208.139.84:3000/admin/umbrix.git
|
||||||
|
|
||||||
|
# Запушьте код
|
||||||
|
git push -u gitea main
|
||||||
|
# Введите: admin / ваш_пароль
|
||||||
|
```
|
||||||
|
|
||||||
|
## Шаг 7: Создание первого релиза
|
||||||
|
|
||||||
|
### Через UI:
|
||||||
|
|
||||||
|
1. Откройте: http://85.208.139.84:3000/admin/umbrix
|
||||||
|
2. Перейдите: **Releases** → **New Release**
|
||||||
|
3. Заполните:
|
||||||
|
- Tag version: `v1.7.3`
|
||||||
|
- Release Title: `Umbrix v1.7.3`
|
||||||
|
- Describe this release:
|
||||||
|
```
|
||||||
|
## 🚀 Что нового
|
||||||
|
- Улучшена стабильность подключения
|
||||||
|
- Исправлены ошибки
|
||||||
|
```
|
||||||
|
4. Прикрепите файлы (Drag & Drop):
|
||||||
|
- `dist/umbrix-1.7.3-linux.deb`
|
||||||
|
- `dist/umbrix-1.7.3-linux.rpm`
|
||||||
|
- `dist/Umbrix-1.7.3-linux.AppImage`
|
||||||
|
|
||||||
|
5. Нажмите **"Publish Release"**
|
||||||
|
|
||||||
|
### Через API (автоматизация):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Получите Access Token
|
||||||
|
# Gitea → Settings → Applications → Generate New Token
|
||||||
|
# Permissions: read:repository, write:repository
|
||||||
|
|
||||||
|
TOKEN="ваш_токен"
|
||||||
|
|
||||||
|
# Создайте релиз
|
||||||
|
curl -X POST "http://85.208.139.84:3000/api/v1/repos/admin/umbrix/releases" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"tag_name": "v1.7.3",
|
||||||
|
"name": "Umbrix v1.7.3",
|
||||||
|
"body": "## Что нового\n- Улучшена стабильность",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false
|
||||||
|
}'
|
||||||
|
|
||||||
|
# Загрузите файлы
|
||||||
|
RELEASE_ID=1 # ID из предыдущего ответа
|
||||||
|
|
||||||
|
curl -X POST "http://85.208.139.84:3000/api/v1/repos/admin/umbrix/releases/$RELEASE_ID/assets" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: multipart/form-data" \
|
||||||
|
-F "attachment=@dist/umbrix-1.7.3-linux.deb"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Шаг 8: Настройка Umbrix для использования Gitea
|
||||||
|
|
||||||
|
Отредактируйте `lib/core/model/constants.dart`:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
abstract class Constants {
|
||||||
|
static const appName = "Umbrix";
|
||||||
|
static const githubUrl = "http://85.208.139.84:3000/admin/umbrix";
|
||||||
|
static const githubReleasesApiUrl = "http://85.208.139.84:3000/api/v1/repos/admin/umbrix/releases";
|
||||||
|
static const githubLatestReleaseUrl = "http://85.208.139.84:3000/admin/umbrix/releases/latest";
|
||||||
|
// ...
|
||||||
|
static const useCustomUpdateServer = false; // Используем Gitea API
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Пересоберите:
|
||||||
|
```bash
|
||||||
|
flutter build linux --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Шаг 9: Тест проверки обновлений
|
||||||
|
|
||||||
|
1. Запустите пересобранное приложение
|
||||||
|
2. Откройте: **Настройки** → **О программе**
|
||||||
|
3. Нажмите **"Проверка обновлений"**
|
||||||
|
4. Должно показать: **"Доступно обновление до версии 1.7.3"**
|
||||||
|
|
||||||
|
## 📊 Управление сервером
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# На сервере
|
||||||
|
cd /opt/gitea
|
||||||
|
|
||||||
|
# Просмотр логов
|
||||||
|
docker-compose logs -f gitea
|
||||||
|
|
||||||
|
# Статус контейнеров
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
# Перезапуск
|
||||||
|
docker-compose restart
|
||||||
|
|
||||||
|
# Остановка
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Запуск
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Обновление Gitea
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 Устранение проблем
|
||||||
|
|
||||||
|
### Gitea не запускается
|
||||||
|
```bash
|
||||||
|
docker-compose logs gitea
|
||||||
|
docker-compose logs db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Порты заняты
|
||||||
|
```bash
|
||||||
|
# Проверьте что порты свободны
|
||||||
|
netstat -tulpn | grep 3000
|
||||||
|
netstat -tulpn | grep 2222
|
||||||
|
```
|
||||||
|
|
||||||
|
### Забыли пароль админа
|
||||||
|
```bash
|
||||||
|
docker exec -it gitea gitea admin user change-password -u admin -p новый_пароль
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 Следующие шаги (опционально)
|
||||||
|
|
||||||
|
### 1. Настройка домена (вместо IP)
|
||||||
|
Если есть домен `git.umbrix.net`:
|
||||||
|
1. Добавьте A-запись: `git.umbrix.net → 85.208.139.84`
|
||||||
|
2. Установите Nginx + Certbot для HTTPS
|
||||||
|
3. Обновите `GITEA__server__DOMAIN` в docker-compose.yml
|
||||||
|
|
||||||
|
### 2. Автоматизация сборки
|
||||||
|
Настройте Gitea Actions (аналог GitHub Actions) для автоматической сборки при push.
|
||||||
|
|
||||||
|
### 3. Зеркала
|
||||||
|
Разверните такие же контейнеры на других IP для обхода блокировок.
|
||||||
|
|
||||||
|
## ✅ Готово!
|
||||||
|
|
||||||
|
Теперь у вас работает:
|
||||||
|
- ✓ Gitea на http://85.208.139.84:3000
|
||||||
|
- ✓ API обновлений: http://85.208.139.84:3000/api/v1/repos/admin/umbrix/releases
|
||||||
|
- ✓ Umbrix проверяет обновления через Gitea
|
||||||
37
update-server/api/appcast.xml
Normal file
37
update-server/api/appcast.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||||
|
<channel>
|
||||||
|
<title>Umbrix Updates</title>
|
||||||
|
<description>Umbrix VPN автообновления</description>
|
||||||
|
<link>http://localhost:8000</link>
|
||||||
|
<language>ru</language>
|
||||||
|
|
||||||
|
<!-- ТЕСТОВАЯ ВЕРСИЯ 1.7.3 - АКТИВИРОВАНА -->
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 1.7.3</title>
|
||||||
|
<description>🚀 Новые функции:
|
||||||
|
- Улучшена стабильность
|
||||||
|
- Исправлены ошибки
|
||||||
|
- Single instance работает идеально</description>
|
||||||
|
<pubDate>Sat, 18 Jan 2026 07:00:00 +0000</pubDate>
|
||||||
|
<sparkle:version>1.7.3</sparkle:version>
|
||||||
|
<sparkle:shortVersionString>1.7.3</sparkle:shortVersionString>
|
||||||
|
<sparkle:minimumSystemVersion>1.0.0</sparkle:minimumSystemVersion>
|
||||||
|
|
||||||
|
<enclosure
|
||||||
|
url="http://localhost:8000/downloads/umbrix-1.7.3-linux.deb"
|
||||||
|
sparkle:version="1.7.3"
|
||||||
|
sparkle:os="linux"
|
||||||
|
type="application/x-debian-package"
|
||||||
|
length="30000000" />
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<!-- Текущая версия 1.7.0 -->
|
||||||
|
<item>
|
||||||
|
<title>Umbrix 1.7.0</title>
|
||||||
|
<description>Стабильный релиз</description>
|
||||||
|
<pubDate>Fri, 17 Jan 2026 08:49:07 +0000</pubDate>
|
||||||
|
<sparkle:version>1.7.0</sparkle:version>
|
||||||
|
</item>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
8
update-server/api/latest
Normal file
8
update-server/api/latest
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"version": "1.7.3",
|
||||||
|
"build_number": "173",
|
||||||
|
"is_prerelease": false,
|
||||||
|
"download_url": "http://localhost:8000/downloads/umbrix-1.7.3-linux.deb",
|
||||||
|
"release_notes": "🚀 Новые функции:\n- Улучшена стабильность\n- Исправлены ошибки\n- Single instance работает идеально",
|
||||||
|
"published_at": "2026-01-18T07:00:00Z"
|
||||||
|
}
|
||||||
14
update-server/api/latest.php
Normal file
14
update-server/api/latest.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
|
||||||
|
$version = [
|
||||||
|
"version" => "1.7.3",
|
||||||
|
"build_number" => "173",
|
||||||
|
"is_prerelease" => false,
|
||||||
|
"download_url" => "http://localhost:8000/downloads/umbrix-1.7.3-linux.deb",
|
||||||
|
"release_notes" => "🚀 Новые функции:\n- Улучшена стабильность\n- Исправлены ошибки\n- Single instance работает идеально",
|
||||||
|
"published_at" => "2026-01-18T07:00:00Z"
|
||||||
|
];
|
||||||
|
|
||||||
|
echo json_encode($version, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||||
1
update-server/downloads/umbrix-1.7.3-linux.deb
Normal file
1
update-server/downloads/umbrix-1.7.3-linux.deb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Тестовый .deb для версии 1.7.3
|
||||||
64
update-server/gitea-docker-compose.yml
Normal file
64
update-server/gitea-docker-compose.yml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:latest
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
# Настройки домена
|
||||||
|
- GITEA__server__DOMAIN=git.umbrix.net
|
||||||
|
- GITEA__server__ROOT_URL=https://git.umbrix.net
|
||||||
|
- GITEA__server__SSH_DOMAIN=git.umbrix.net
|
||||||
|
- GITEA__server__SSH_PORT=2222
|
||||||
|
# Настройки зеркал (можно добавлять через запятую)
|
||||||
|
- GITEA__server__ALLOWED_HOST_LIST=git.umbrix.net,git-mirror1.umbrix.net,git-mirror2.umbrix.net
|
||||||
|
# Отключить регистрацию новых пользователей (для приватного использования)
|
||||||
|
- GITEA__service__DISABLE_REGISTRATION=true
|
||||||
|
- GITEA__service__REQUIRE_SIGNIN_VIEW=false
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ./gitea/data:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
ports:
|
||||||
|
- "3000:3000" # HTTP (Nginx будет проксировать)
|
||||||
|
- "2222:22" # SSH для git push
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:14
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=gitea
|
||||||
|
- POSTGRES_PASSWORD=gitea_secure_password_change_me
|
||||||
|
- POSTGRES_DB=gitea
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ./gitea/postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
# Nginx для HTTPS + зеркала
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-gitea
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||||
|
- ./gitea/data/gitea/public:/usr/share/nginx/html/public:ro
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
depends_on:
|
||||||
|
- gitea
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea:
|
||||||
|
external: false
|
||||||
147
update-server/install-gitea.sh
Executable file
147
update-server/install-gitea.sh
Executable file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Цвета для вывода
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}=== Установка Gitea на сервере ===${NC}"
|
||||||
|
|
||||||
|
# Проверка root
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo -e "${RED}Запустите скрипт с sudo${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. Обновление системы
|
||||||
|
echo -e "${YELLOW}[1/7] Обновление системы...${NC}"
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
|
||||||
|
# 2. Установка Docker
|
||||||
|
echo -e "${YELLOW}[2/7] Установка Docker...${NC}"
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sh get-docker.sh
|
||||||
|
rm get-docker.sh
|
||||||
|
systemctl enable docker
|
||||||
|
systemctl start docker
|
||||||
|
echo -e "${GREEN}✓ Docker установлен${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ Docker уже установлен${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Установка Docker Compose
|
||||||
|
echo -e "${YELLOW}[3/7] Установка Docker Compose...${NC}"
|
||||||
|
if ! command -v docker-compose &> /dev/null; then
|
||||||
|
apt install -y docker-compose
|
||||||
|
echo -e "${GREEN}✓ Docker Compose установлен${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ Docker Compose уже установлен${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Создание директорий
|
||||||
|
echo -e "${YELLOW}[4/7] Создание директорий...${NC}"
|
||||||
|
mkdir -p /opt/gitea/{gitea/data,gitea/postgres,nginx/ssl}
|
||||||
|
cd /opt/gitea
|
||||||
|
|
||||||
|
# 5. Создание docker-compose.yml
|
||||||
|
echo -e "${YELLOW}[5/7] Создание конфигурации Docker...${NC}"
|
||||||
|
cat > docker-compose.yml <<'EOF'
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:latest
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
- GITEA__database__DB_TYPE=postgres
|
||||||
|
- GITEA__database__HOST=db:5432
|
||||||
|
- GITEA__database__NAME=gitea
|
||||||
|
- GITEA__database__USER=gitea
|
||||||
|
- GITEA__database__PASSWD=gitea_secure_pass_2026
|
||||||
|
- GITEA__server__DOMAIN=85.208.139.84
|
||||||
|
- GITEA__server__ROOT_URL=http://85.208.139.84:3000
|
||||||
|
- GITEA__server__SSH_DOMAIN=85.208.139.84
|
||||||
|
- GITEA__server__SSH_PORT=2222
|
||||||
|
- GITEA__service__DISABLE_REGISTRATION=true
|
||||||
|
- GITEA__service__REQUIRE_SIGNIN_VIEW=false
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ./gitea/data:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
- "2222:22"
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=gitea
|
||||||
|
- POSTGRES_PASSWORD=gitea_secure_pass_2026
|
||||||
|
- POSTGRES_DB=gitea
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ./gitea/postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea:
|
||||||
|
external: false
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 6. Настройка firewall
|
||||||
|
echo -e "${YELLOW}[6/7] Настройка firewall...${NC}"
|
||||||
|
if command -v ufw &> /dev/null; then
|
||||||
|
ufw allow 3000/tcp
|
||||||
|
ufw allow 2222/tcp
|
||||||
|
echo -e "${GREEN}✓ Firewall настроен${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ UFW не установлен, убедитесь что порты 3000 и 2222 открыты${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. Запуск Gitea
|
||||||
|
echo -e "${YELLOW}[7/7] Запуск Gitea...${NC}"
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Ожидание запуска
|
||||||
|
echo -e "${YELLOW}Ожидание запуска сервисов...${NC}"
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Проверка статуса
|
||||||
|
if docker ps | grep -q gitea; then
|
||||||
|
echo -e "${GREEN}"
|
||||||
|
echo "╔════════════════════════════════════════════════════════════╗"
|
||||||
|
echo "║ ✓ Gitea успешно установлен и запущен! ║"
|
||||||
|
echo "╚════════════════════════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 Откройте браузер: http://85.208.139.84:3000"
|
||||||
|
echo ""
|
||||||
|
echo "📝 Первоначальная настройка:"
|
||||||
|
echo " - Database Type: PostgreSQL"
|
||||||
|
echo " - Host: db:5432"
|
||||||
|
echo " - Username: gitea"
|
||||||
|
echo " - Password: gitea_secure_pass_2026"
|
||||||
|
echo " - Database Name: gitea"
|
||||||
|
echo ""
|
||||||
|
echo "👤 Первый зарегистрированный пользователь = админ"
|
||||||
|
echo ""
|
||||||
|
echo "📊 Управление контейнерами:"
|
||||||
|
echo " docker-compose logs -f # Логи"
|
||||||
|
echo " docker-compose ps # Статус"
|
||||||
|
echo " docker-compose restart # Перезапуск"
|
||||||
|
echo " docker-compose down # Остановка"
|
||||||
|
echo "${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Ошибка запуска Gitea. Проверьте логи: docker-compose logs${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
78
update-server/nginx.conf
Normal file
78
update-server/nginx.conf
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Nginx конфигурация для Gitea с зеркалами
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
upstream gitea {
|
||||||
|
server gitea:3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Перенаправление HTTP → HTTPS
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name git.umbrix.net git-mirror1.umbrix.net git-mirror2.umbrix.net;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Основной домен
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name git.umbrix.net;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
|
||||||
|
client_max_body_size 512M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://gitea;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Зеркало 1
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name git-mirror1.umbrix.net;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/mirror1-fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/mirror1-privkey.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
|
||||||
|
client_max_body_size 512M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://gitea;
|
||||||
|
proxy_set_header Host git.umbrix.net; # Важно! Gitea думает что основной домен
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Зеркало 2 (аналогично)
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name git-mirror2.umbrix.net;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/mirror2-fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/mirror2-privkey.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
|
||||||
|
client_max_body_size 512M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://gitea;
|
||||||
|
proxy_set_header Host git.umbrix.net;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user