Compare commits

..

3 Commits

Author SHA1 Message Date
Umbrix Developer
d74033605b chore: update libcore submodule URL to Gitea
Some checks are pending
CI / run (push) Waiting to run
- Changed from GitHub to update.umbrix.net
- Points to umbrix-libcore with extensionData fix (commit 8b6f4d6)
2026-01-19 18:10:52 +03:00
Umbrix Developer
796c223d44 feat: Windows support - auto-update system + proper app icon
Some checks failed
CI / run (push) Has been cancelled
- PowerShell silent installer with UAC elevation
- Smart asset detection (x64 priority for .exe)
- Cross-platform restart after update
- Auto-check updates on launch (5 sec delay)
- Multi-layer .ico with 6 sizes (16-256px)
- Windows build documentation added
2026-01-19 17:48:21 +03:00
Umbrix Developer
95383d09fc feat: update to v1.7.3 with smart asset detection and auto-install
Some checks failed
Upload store MSIX to release / upload-store-msix-to-release (push) Has been cancelled
CI / run (push) Has been cancelled
2026-01-18 20:14:19 +03:00
19 changed files with 1297 additions and 11 deletions

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "libcore"]
path = libcore
url = https://github.com/hiddify/hiddify-next-core
url = https://update.umbrix.net/vodorod/umbrix-libcore.git

View File

@@ -14,6 +14,7 @@ import 'package:umbrix/core/preferences/general_preferences.dart';
import 'package:umbrix/core/preferences/preferences_migration.dart';
import 'package:umbrix/core/preferences/preferences_provider.dart';
import 'package:umbrix/features/app/widget/app.dart';
import 'package:umbrix/features/app_update/notifier/app_update_notifier.dart';
import 'package:umbrix/features/auto_start/notifier/auto_start_notifier.dart';
import 'package:umbrix/features/common/custom_splash_screen.dart';
import 'package:umbrix/features/deep_link/notifier/deep_link_notifier.dart';
@@ -153,6 +154,13 @@ Future<void> _performBootstrap(
() => container.read(systemTrayNotifierProvider.future),
timeout: 1000,
);
// Автопроверка обновлений при запуске (отложенная)
_safeInit(
"auto check updates",
() => container.read(appUpdateNotifierProvider.notifier).checkSilently(),
timeout: 5000,
);
}
if (Platform.isAndroid) {

View File

@@ -1,8 +1,8 @@
abstract class Constants {
static const appName = "Umbrix";
static const githubUrl = "https://github.com/umbrix-app/umbrix";
static const githubReleasesApiUrl = "https://api.github.com/repos/umbrix-app/umbrix/releases";
static const githubLatestReleaseUrl = "https://github.com/umbrix-app/umbrix/releases/latest";
static const githubUrl = "https://update.umbrix.net/vodorod/umbrix";
static const githubReleasesApiUrl = "https://update.umbrix.net/api/v1/repos/vodorod/umbrix/releases";
static const githubLatestReleaseUrl = "https://update.umbrix.net/vodorod/umbrix/releases/latest";
static const appCastUrl = "http://localhost:8000/api/appcast.xml";
static const telegramChannelUrl = "https://t.me/umbrix_app";
static const privacyPolicyUrl = "https://umbrix.net/privacy.html";
@@ -18,12 +18,14 @@ abstract class Constants {
// 🖥️ Для Linux десктопа используйте: "http://localhost:8000/api/appcast.xml"
// 📱 Для Android эмулятора используйте: "http://10.0.2.2:8000/api/appcast.xml"
// См. документацию в папке: update-server/README.md
static const customUpdateServerUrl = "http://localhost:8000/api/appcast.xml";
// ТЕСТ: Используем httpbin.org для демонстрации (возвращает тестовые данные)
static const customUpdateServerUrl = "https://httpbin.org/json";
// Использовать собственный сервер обновлений вместо GitHub
// true = использовать customUpdateServerUrl (для приватного репозитория)
// false = использовать GitHub Releases (для публичного репозитория)
static const useCustomUpdateServer = true;
static const useCustomUpdateServer = false;
}
const kAnimationDuration = Duration(milliseconds: 250);

View File

@@ -23,6 +23,20 @@ abstract class GithubReleaseParser {
}
final preRelease = json["prerelease"] as bool;
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(
version: version,
buildNumber: buildNumber,
@@ -31,6 +45,7 @@ abstract class GithubReleaseParser {
url: json["html_url"] as String,
publishedAt: publishedAt,
flavor: flavor,
assets: assets,
);
}
}

View File

@@ -15,8 +15,88 @@ class RemoteVersionEntity with _$RemoteVersionEntity {
required String url,
required DateTime publishedAt,
required Environment flavor,
@Default([]) List<ReleaseAsset> assets,
}) = _RemoteVersionEntity;
String get presentVersion =>
flavor == Environment.prod ? version : "$version ${flavor.name}";
String get presentVersion => flavor == Environment.prod ? version : "$version ${flavor.name}";
/// Найти asset по расширению файла с умным определением
String? findAssetByExtension(String extension) {
try {
// Для Linux используем приоритет: .deb > .rpm > .AppImage
if (extension == '.deb' || extension == '.rpm' || extension == '.AppImage') {
final priorities = ['.deb', '.rpm', '.AppImage'];
for (final ext in priorities) {
try {
final asset = assets.firstWhere((asset) => asset.name.endsWith(ext));
return asset.downloadUrl;
} catch (_) {
continue;
}
}
return null;
}
// Для Windows - ищем .exe с приоритетом x64
if (extension == '.exe') {
// Сначала ищем x64 setup/installer
for (final pattern in ['x64', 'amd64', 'win64', 'setup', 'installer']) {
try {
final asset = assets.firstWhere(
(asset) => asset.name.toLowerCase().contains(pattern) && asset.name.endsWith('.exe'),
);
return asset.downloadUrl;
} catch (_) {
continue;
}
}
// Если не нашли специфичный - берём любой .exe
try {
final asset = assets.firstWhere((asset) => asset.name.endsWith('.exe'));
return asset.downloadUrl;
} catch (_) {
return null;
}
}
// Для macOS - ищем .dmg
if (extension == '.dmg') {
// Сначала ищем universal или arm64 (для M1/M2)
for (final pattern in ['universal', 'arm64', 'apple-silicon']) {
try {
final asset = assets.firstWhere(
(asset) => asset.name.toLowerCase().contains(pattern) && asset.name.endsWith('.dmg'),
);
return asset.downloadUrl;
} catch (_) {
continue;
}
}
// Если не нашли - берём любой .dmg
try {
final asset = assets.firstWhere((asset) => asset.name.endsWith('.dmg'));
return asset.downloadUrl;
} catch (_) {
return null;
}
}
// Для других расширений - прямой поиск
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;
}

View File

@@ -84,4 +84,21 @@ class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
await _ignoreReleasePref.write(version.version);
state = AppUpdateStateIgnored(version);
}
/// Тихая проверка обновлений (без изменения UI состояния если нет обновлений)
/// Используется при запуске приложения
Future<void> checkSilently() async {
loggy.debug("silent update check");
final result = await check();
// Если доступно обновление - показываем уведомление в tray
if (result is AppUpdateStateAvailable) {
_showUpdateNotification(result.versionInfo);
}
}
void _showUpdateNotification(RemoteVersionEntity version) {
// TODO: Реализовать уведомление через system tray
loggy.info("new version available: ${version.version}");
}
}

View File

@@ -25,6 +25,19 @@ class NewVersionDialog extends HookConsumerWidget with PresLogger {
static final _dialogKey = GlobalKey(debugLabel: 'new version dialog');
/// Перезапуск приложения (кроссплатформенный метод)
void _restartApplication() {
final executable = Platform.resolvedExecutable;
loggy.info('Restarting application: $executable');
// Запускаем новый процесс и завершаем текущий
Process.start(executable, []).then((_) {
exit(0);
}).catchError((e) {
loggy.error('Failed to restart application', e);
});
}
Future<void> show(BuildContext context) async {
if (_dialogKey.currentContext == null) {
return showDialog(
@@ -57,23 +70,103 @@ class NewVersionDialog extends HookConsumerWidget with PresLogger {
downloadProgress.value = 0.0;
final tempDir = await getTemporaryDirectory();
// Определяем нужное расширение файла
String fileExt = '';
if (Platform.isWindows)
fileExt = '.exe';
else if (Platform.isMacOS)
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 file = File(savePath);
if (await file.exists()) await file.delete();
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;
});
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();
}
// Автоматический перезапуск после небольшой задержки
Future.delayed(const Duration(seconds: 2), () {
_restartApplication();
});
return;
}
} catch (e) {
loggy.warning('Failed to install via pkexec apt: $e');
}
}
// Для Windows EXE - запускаем тихую установку
if (Platform.isWindows && fileExt == '.exe') {
try {
if (context.mounted) {
CustomToast('Установка обновления...', type: AlertType.info).show(context);
}
// Запускаем установщик в тихом режиме с правами администратора
// /VERYSILENT - без UI, /SUPPRESSMSGBOXES - без диалогов
// /NORESTART - не перезагружать систему
final result = await Process.run(
'powershell',
[
'-Command',
'Start-Process',
'-FilePath',
'"$savePath"',
'-ArgumentList',
'"/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART"',
'-Verb',
'RunAs',
'-Wait'
],
);
if (result.exitCode == 0) {
if (context.mounted) {
CustomToast.success('Обновление установлено! Приложение перезагрузится...').show(context);
context.pop();
}
// Автоматический перезапуск после небольшой задержки
Future.delayed(const Duration(seconds: 2), () {
_restartApplication();
});
return;
}
} catch (e) {
loggy.warning('Failed to install via PowerShell: $e');
}
}
// Для других платформ или если автоустановка не сработала - просто открываем файл
final result = await OpenFile.open(savePath);
if (result.type != ResultType.done && context.mounted) {

View File

@@ -1,7 +1,7 @@
name: umbrix
description: Cross Platform Multi Protocol Proxy Frontend.
publish_to: "none"
version: 1.7.0+170
version: 1.7.3+173
environment:
sdk: ">=3.3.0 <4.0.0"

View 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!

View 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

View File

@@ -0,0 +1,207 @@
# Windows Build & Update Instructions
## Система автообновлений для Windows
### Требования для Windows EXE сборки
1. **Inno Setup** - для создания установщика
- Скачать: https://jrsoftware.org/isdl.php
- Версия: 6.x или новее
2. **Flutter** на Windows машине
- Flutter SDK установлен
- Visual Studio 2022 с C++ компонентами
### 1. Сборка Windows приложения
```powershell
# Сборка Release версии
flutter build windows --release
# Результат: build/windows/x64/runner/Release/
```
### 2. Создание Inno Setup скрипта
Создайте файл `windows/installer.iss`:
```inno
#define MyAppName "Umbrix"
#define MyAppVersion "1.7.3"
#define MyAppPublisher "Umbrix Team"
#define MyAppURL "https://umbrix.net"
#define MyAppExeName "umbrix.exe"
[Setup]
AppId={{YOUR-GUID-HERE}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputDir=..\dist
OutputBaseFilename=umbrix-{#MyAppVersion}-windows-setup
Compression=lzma2/max
SolidCompression=yes
PrivilegesRequired=admin
ArchitecturesInstallIn64BitMode=x64
; Параметры для тихой установки (поддержка автообновления)
[Code]
function InitializeSetup(): Boolean;
var
ResultCode: Integer;
begin
// Закрыть запущенное приложение перед установкой
if FileExists(ExpandConstant('{autopf}\{#MyAppName}\{#MyAppExeName}')) then
begin
Exec('taskkill', '/F /IM umbrix.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
Result := True;
end;
[Files]
Source: "..\build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "Launch {#MyAppName}"; Flags: nowait postinstall skipifsilent
```
### 3. Компиляция установщика
```powershell
# В папке windows/
iscc installer.iss
# Результат: dist/umbrix-1.7.3-windows-setup.exe
```
### 4. Загрузка в Gitea
```powershell
# Загрузка в релиз через API
$token = "YOUR_GITEA_TOKEN"
$file = "dist/umbrix-1.7.3-windows-setup.exe"
curl -X POST "https://update.umbrix.net/api/v1/repos/vodorod/umbrix/releases/1/assets?name=umbrix-1.7.3-windows-setup.exe" `
-H "Authorization: token $token" `
-H "Content-Type: application/octet-stream" `
--data-binary "@$file"
```
## Как работает автообновление на Windows
### 1. Автопроверка при запуске
- Приложение проверяет обновления через 5 секунд после запуска
- Запрос к API: `https://update.umbrix.net/api/v1/repos/vodorod/umbrix/releases`
### 2. Обнаружение обновления
- Парсит JSON с assets
- Ищет файл с расширением `.exe`
- Показывает диалог "Доступно обновление"
### 3. Автоматическая установка
При нажатии "Обновить":
1. **Скачивание** - файл загружается в `%TEMP%\umbrix-1.7.3.exe`
2. **Установка** - запускается через PowerShell:
```powershell
Start-Process -FilePath "umbrix-1.7.3.exe" `
-ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART" `
-Verb RunAs -Wait
```
3. **Перезапуск** - приложение автоматически перезапускается через 2 секунды
### Параметры тихой установки Inno Setup
- `/VERYSILENT` - установка без UI
- `/SUPPRESSMSGBOXES` - без диалоговых окон
- `/NORESTART` - не перезагружать систему
- `-Verb RunAs` - запрос прав администратора (UAC)
### Тестирование
1. Соберите версию 1.7.0
2. Установите: `umbrix-1.7.0-windows-setup.exe`
3. Соберите версию 1.7.3, загрузите в Gitea
4. Запустите приложение 1.7.0
5. Должно появиться уведомление об обновлении
6. Нажмите "Обновить" → автоустановка → автоперезапуск
### Troubleshooting
**Ошибка: "PowerShell не найден"**
- PowerShell должен быть установлен (входит в Windows)
- Проверьте: `powershell --version`
**Ошибка: "Access denied"**
- Установщик требует прав администратора
- UAC запросит подтверждение
**Установка не запускается автоматически**
- Проверьте антивирус - может блокировать
- Запустите вручную скачанный `.exe`
## Альтернатива: MSI установщик
Если нужен MSI вместо EXE:
1. Используйте WiX Toolset: https://wixtoolset.org/
2. Создайте `.wxs` файл с описанием установки
3. Скомпилируйте: `candle installer.wxs && light installer.wixobj`
4. Результат: `umbrix-1.7.3.msi`
5. Установка: `msiexec /i umbrix-1.7.3.msi /qn` (silent)
## Continuous Integration
Для автоматизации сборки Windows версии на GitHub Actions:
```yaml
name: Build Windows
on:
push:
tags:
- 'v*'
jobs:
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.0'
- name: Build Windows
run: flutter build windows --release
- name: Download Inno Setup
run: |
Invoke-WebRequest -Uri "https://jrsoftware.org/download.php/is.exe" -OutFile "inno-setup.exe"
./inno-setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART
- name: Build Installer
run: iscc windows/installer.iss
- name: Upload to Gitea
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
$file = "dist/umbrix-${{ github.ref_name }}-windows-setup.exe"
curl -X POST "https://update.umbrix.net/api/v1/repos/vodorod/umbrix/releases/assets" `
-H "Authorization: token $env:GITEA_TOKEN" `
--data-binary "@$file"
```
## Заключение
Теперь система автообновлений работает одинаково на:
- ✅ **Linux** - DEB пакеты через `apt install`
-**Windows** - EXE установщики через PowerShell
-**Автопроверка** - при запуске для всех платформ
-**Автоперезагрузка** - после установки для всех платформ

View 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
View 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"
}

View 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);

View File

@@ -0,0 +1 @@
Тестовый .deb для версии 1.7.3

View 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
View 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
View 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;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 206 KiB