update README.md
This commit is contained in:
@@ -1,443 +0,0 @@
|
||||
# Contributing to Ospabhost 8.1
|
||||
|
||||
Thank you for considering contributing to **Ospabhost 8.1**! This document provides guidelines for contributing.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [Coding Standards](#coding-standards)
|
||||
- [Commit Guidelines](#commit-guidelines)
|
||||
- [Pull Request Process](#pull-request-process)
|
||||
- [Testing Requirements](#testing-requirements)
|
||||
|
||||
---
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
### Our Pledge
|
||||
|
||||
We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity, level of experience, nationality, personal appearance, race, religion, sexual identity and orientation.
|
||||
|
||||
### Our Standards
|
||||
|
||||
**Positive behavior includes:**
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the project
|
||||
- Showing empathy towards other community members
|
||||
|
||||
**Unacceptable behavior includes:**
|
||||
- Trolling, insulting comments, personal attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information without permission
|
||||
|
||||
### Enforcement
|
||||
|
||||
Violations can be reported to:
|
||||
- **Email:** support@ospab.host
|
||||
- **Telegram:** @ospab_support
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you begin, ensure you have:
|
||||
|
||||
\\\ash
|
||||
# Node.js (v24.x or higher)
|
||||
node --version
|
||||
|
||||
# npm (v10.x or higher)
|
||||
npm --version
|
||||
|
||||
# MySQL (8.0 or higher)
|
||||
mysql --version
|
||||
|
||||
# Git
|
||||
git --version
|
||||
\\\
|
||||
|
||||
### Fork and Clone
|
||||
|
||||
1. **Fork the repository** on GitHub
|
||||
2. **Clone your fork locally:**
|
||||
\\\ash
|
||||
git clone https://github.com/YOUR_USERNAME/ospabhost8.1.git
|
||||
cd ospabhost8.1/ospabhost
|
||||
\\\
|
||||
|
||||
3. **Add upstream remote:**
|
||||
\\\ash
|
||||
git remote add upstream https://github.com/Ospab/ospabhost8.1.git
|
||||
\\\
|
||||
|
||||
### Setup Development Environment
|
||||
|
||||
#### Backend Setup
|
||||
|
||||
\\\ash
|
||||
cd backend
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Copy environment file
|
||||
cp .env.example .env
|
||||
|
||||
# Setup database
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Run in development mode
|
||||
npm run dev
|
||||
\\\
|
||||
|
||||
#### Frontend Setup
|
||||
|
||||
\\\ash
|
||||
cd frontend
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Copy environment file
|
||||
cp .env.example .env
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
\\\
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Create Feature Branch
|
||||
|
||||
\\\ash
|
||||
git checkout -b feature/your-feature-name
|
||||
# or for bug fixes:
|
||||
git checkout -b fix/bug-description
|
||||
\\\
|
||||
|
||||
### Make Changes
|
||||
|
||||
1. Make your changes following the coding standards below
|
||||
2. Ensure tests pass: \
|
||||
pm run test\
|
||||
3. Build successfully: \
|
||||
pm run build\
|
||||
|
||||
### Commit Changes
|
||||
|
||||
\\\ash
|
||||
# Stage your changes
|
||||
git add .
|
||||
|
||||
# Commit with a descriptive message
|
||||
git commit -m "feat: Add new storage feature"
|
||||
|
||||
# Push to your fork
|
||||
git push origin feature/your-feature-name
|
||||
\\\
|
||||
|
||||
### Create Pull Request
|
||||
|
||||
1. Go to your fork on GitHub
|
||||
2. Click "Compare & pull request"
|
||||
3. Write a clear description of your changes
|
||||
4. Reference any related issues: "Fixes #123"
|
||||
5. Submit the PR
|
||||
|
||||
---
|
||||
|
||||
## Coding Standards
|
||||
|
||||
### Backend (Express/TypeScript)
|
||||
|
||||
- Use **TypeScript** for type safety
|
||||
- Follow **camelCase** for variables and functions
|
||||
- Use **PascalCase** for classes and interfaces
|
||||
- Keep functions small and focused
|
||||
- Add JSDoc comments for public methods
|
||||
- Use async/await instead of promises
|
||||
|
||||
Example:
|
||||
\\\ ypescript
|
||||
/**
|
||||
* Generates a secure password for storage credentials
|
||||
* @param length - Password length (default: 16)
|
||||
* @returns Generated password
|
||||
*/
|
||||
async function generateSecurePassword(length: number = 16): Promise<string> {
|
||||
// Implementation
|
||||
}
|
||||
\\\
|
||||
|
||||
### Frontend (React/TypeScript)
|
||||
|
||||
- Use **functional components** with hooks
|
||||
- Use **TypeScript** for type safety
|
||||
- Follow **camelCase** for functions and variables
|
||||
- Use **PascalCase** for components
|
||||
- Extract reusable components
|
||||
- Keep components focused and small
|
||||
|
||||
Example:
|
||||
\\\ ypescript
|
||||
interface BucketProps {
|
||||
id: string;
|
||||
name: string;
|
||||
onDelete?: () => void;
|
||||
}
|
||||
|
||||
export const BucketCard: React.FC<BucketProps> = ({ id, name, onDelete }) => {
|
||||
return <div>{name}</div>;
|
||||
};
|
||||
\\\
|
||||
|
||||
### General Rules
|
||||
|
||||
- Use **4 spaces** for indentation
|
||||
- Add trailing commas in objects/arrays
|
||||
- Use semicolons
|
||||
- No console.log in production code
|
||||
- Use meaningful variable names
|
||||
|
||||
---
|
||||
|
||||
## Commit Guidelines
|
||||
|
||||
We follow [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
\\\
|
||||
feat: Add new feature (S3 storage, etc.)
|
||||
fix: Bug fixes
|
||||
docs: Documentation changes
|
||||
style: Code formatting (no logic changes)
|
||||
refactor: Code restructuring (no feature changes)
|
||||
test: Add or update tests
|
||||
chore: Dependency updates, configuration changes
|
||||
\\\
|
||||
|
||||
Examples:
|
||||
- \eat: Add presigned URL generation for S3 downloads\
|
||||
- \ix: Fix rate limiting for credential generation\
|
||||
- \docs: Update API documentation\
|
||||
- \ est: Add tests for storage service\
|
||||
|
||||
---
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
1. **Update your fork:**
|
||||
\\\ash
|
||||
git fetch upstream
|
||||
git rebase upstream/main
|
||||
\\\
|
||||
|
||||
2. **Resolve conflicts** if any
|
||||
|
||||
3. **Ensure tests pass:**
|
||||
\\\ash
|
||||
npm run test
|
||||
npm run lint
|
||||
npm run build
|
||||
\\\
|
||||
|
||||
4. **Push your changes:**
|
||||
\\\ash
|
||||
git push origin feature/your-feature-name
|
||||
\\\
|
||||
|
||||
5. **Create Pull Request** with:
|
||||
- Clear title describing your changes
|
||||
- Description of what and why you changed
|
||||
- Reference to any related issues
|
||||
- Screenshots if UI changes
|
||||
|
||||
6. **Address review feedback:**
|
||||
- Make requested changes
|
||||
- Push new commits
|
||||
- Request re-review
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
### Backend Tests
|
||||
|
||||
\\\ash
|
||||
# Run all tests
|
||||
npm run test
|
||||
|
||||
# Run with coverage
|
||||
npm run test:coverage
|
||||
|
||||
# Run specific test file
|
||||
npm run test -- storage.service.test.ts
|
||||
\\\
|
||||
|
||||
### Frontend Tests
|
||||
|
||||
\\\ash
|
||||
# Run tests
|
||||
npm run test
|
||||
|
||||
# Run with coverage
|
||||
npm run test -- --coverage
|
||||
\\\
|
||||
|
||||
### Code Quality
|
||||
|
||||
\\\ash
|
||||
# Lint code
|
||||
npm run lint
|
||||
|
||||
# Format code
|
||||
npm run format
|
||||
|
||||
# Type check
|
||||
npm run type-check
|
||||
\\\
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
\\\
|
||||
backend/src/modules/
|
||||
storage/ # S3 Object Storage
|
||||
auth/ # Authentication
|
||||
ticket/ # Support Tickets
|
||||
check/ # Payment Checks
|
||||
tariff/ # Tariff Plans
|
||||
notification/ # Notifications
|
||||
|
||||
frontend/src/
|
||||
pages/ # Route pages
|
||||
components/ # Reusable components
|
||||
context/ # React Context (Auth)
|
||||
lib/ # Utilities and API client
|
||||
App.tsx # Main component
|
||||
\\\
|
||||
|
||||
---
|
||||
|
||||
## File Upload Feature Development
|
||||
|
||||
### Upload Implementation
|
||||
|
||||
The frontend supports multiple upload methods in `frontend/src/pages/dashboard/storage-bucket.tsx`:
|
||||
|
||||
**1. Drag & Drop Upload**
|
||||
- Uses React's `DragEvent` handlers
|
||||
- Files extracted from `event.dataTransfer.files`
|
||||
- Triggers `performUpload()` callback
|
||||
|
||||
**2. File Selection**
|
||||
- Single input with `multiple` attribute
|
||||
- Handled via `handleUploadInput()` event
|
||||
- Converts FileList to File[] array
|
||||
|
||||
**3. Directory Upload**
|
||||
- Uses `webkitdirectory` and `mozdirectory` attributes
|
||||
- Creates recursive file upload maintaining folder structure
|
||||
- Path prefix combines with directory structure
|
||||
|
||||
**4. URI Upload**
|
||||
- `handleUriUpload()` fetches from remote URL
|
||||
- Creates File object from Blob response
|
||||
- Integrates with standard upload flow
|
||||
|
||||
### Progress Tracking
|
||||
|
||||
Upload progress is tracked via XMLHttpRequest:
|
||||
|
||||
\\\typescript
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener('progress', (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const elapsed = (Date.now() - startTime) / 1000;
|
||||
const speed = elapsed > 0 ? event.loaded / elapsed : 0;
|
||||
const percentage = Math.round((event.loaded / event.total) * 100);
|
||||
|
||||
setUploadProgress({
|
||||
loaded: event.loaded,
|
||||
total: event.total,
|
||||
speed,
|
||||
percentage
|
||||
});
|
||||
}
|
||||
});
|
||||
\\\
|
||||
|
||||
**Key Types:**
|
||||
- `UploadProgress`: Tracks individual file upload metrics
|
||||
- `uploadStats`: Displays current file and progress counter
|
||||
- `uploadAbortControllerRef`: Ref to AbortController for canceling uploads
|
||||
|
||||
---
|
||||
|
||||
## Upload Cancellation
|
||||
|
||||
Users can cancel ongoing uploads:
|
||||
|
||||
\\\typescript
|
||||
const handleCancelUpload = useCallback(() => {
|
||||
if (uploadAbortControllerRef.current) {
|
||||
uploadAbortControllerRef.current.abort();
|
||||
uploadAbortControllerRef.current = null;
|
||||
}
|
||||
setUploading(false);
|
||||
setUploadProgress({});
|
||||
setUploadStats({ currentFile: '', completedFiles: 0, totalFiles: 0 });
|
||||
addToast('Загрузка отменена', 'info');
|
||||
}, [addToast]);
|
||||
\\\
|
||||
|
||||
---
|
||||
|
||||
## URI Download via Proxy
|
||||
|
||||
To bypass CORS limitations, URI downloads use backend proxy:
|
||||
|
||||
\\\
|
||||
POST /api/storage/buckets/:id/objects/download-from-uri
|
||||
{
|
||||
"url": "https://example.com/file.zip"
|
||||
}
|
||||
\\\
|
||||
|
||||
Response:
|
||||
\\\json
|
||||
{
|
||||
"blob": "base64_encoded_file_data",
|
||||
"mimeType": "application/zip"
|
||||
}
|
||||
\\\
|
||||
|
||||
This avoids CORS errors by handling the request server-side.
|
||||
|
||||
---
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Read [README.md](./README.md)
|
||||
- Ask in [GitHub Discussions](https://github.com/Ospab/ospabhost8.1/discussions)
|
||||
- Report bugs in [GitHub Issues](https://github.com/Ospab/ospabhost8.1/issues)
|
||||
- Email: support@ospab.host
|
||||
|
||||
---
|
||||
|
||||
## Thank You!
|
||||
|
||||
Thank you for contributing to Ospabhost 8.1! Your efforts help make this project better for everyone.
|
||||
|
||||
**Happy Coding! **
|
||||
@@ -1,308 +0,0 @@
|
||||
# Система статистики и мониторинга серверов
|
||||
|
||||
## 📊 Что добавлено
|
||||
|
||||
### Backend (API):
|
||||
|
||||
1. **Новая модель Prisma**: `ServerMetric`
|
||||
- Хранит историю метрик каждого сервера
|
||||
- Поля: CPU, Memory, Disk, Network, Status, Uptime
|
||||
- Автоматическое удаление при удалении сервера (CASCADE)
|
||||
|
||||
2. **3 новых API endpoint'а**:
|
||||
- `GET /api/server/:id/metrics` - Получить текущие метрики (+ сохранение в БД)
|
||||
- `GET /api/server/:id/metrics/history?period=24h` - История за период (1h, 6h, 24h, 7d, 30d)
|
||||
- `GET /api/server/:id/metrics/summary` - Сводка за 24 часа (средние, макс, мин)
|
||||
|
||||
3. **Автоматическое сохранение**:
|
||||
- При каждом запросе текущих метрик данные сохраняются в БД
|
||||
- Создаётся точка для графиков
|
||||
|
||||
### Frontend (React):
|
||||
|
||||
1. **Компонент `ServerMetrics.tsx`**:
|
||||
- 4 карточки с текущими показателями (CPU, RAM, Disk, Network)
|
||||
- Цветовая индикация нагрузки (зелёный/жёлтый/красный)
|
||||
- Фильтр периода (1 час, 6 часов, 24 часа, 7 дней, 30 дней)
|
||||
- 3 интерактивных графика (Recharts):
|
||||
- CPU Usage (Area Chart)
|
||||
- Memory + Disk (Line Chart)
|
||||
- Network Traffic (Area Chart)
|
||||
- Автообновление каждую минуту
|
||||
|
||||
2. **Интеграция**:
|
||||
- Встроен в панель управления сервером
|
||||
- Вкладка "Мониторинг" теперь показывает реальные данные
|
||||
|
||||
## 🚀 Установка
|
||||
|
||||
### 1. SQL миграция:
|
||||
```bash
|
||||
cd /var/www/ospab-host/backend
|
||||
mysql -u root -p ospabhost < prisma/migrations/add_server_metrics.sql
|
||||
```
|
||||
|
||||
### 2. Обновление Prisma:
|
||||
```bash
|
||||
cd /var/www/ospab-host/backend
|
||||
npx prisma generate
|
||||
```
|
||||
|
||||
### 3. Сборка backend:
|
||||
```bash
|
||||
npm run build
|
||||
pm2 restart ospab-backend
|
||||
```
|
||||
|
||||
### 4. Сборка frontend:
|
||||
```bash
|
||||
cd /var/www/ospab-host/frontend
|
||||
npm install recharts
|
||||
npm run build
|
||||
# Деплой dist/
|
||||
```
|
||||
|
||||
## 📈 Как работает
|
||||
|
||||
### Сбор данных:
|
||||
1. Frontend запрашивает `/api/server/:id/metrics`
|
||||
2. Backend получает данные от Proxmox API
|
||||
3. Данные сохраняются в таблицу `server_metrics`
|
||||
4. Возвращаются пользователю
|
||||
|
||||
### Графики:
|
||||
1. Frontend запрашивает историю за период
|
||||
2. Backend агрегирует данные с интервалами:
|
||||
- 1h → каждую минуту
|
||||
- 6h → каждые 5 минут
|
||||
- 24h → каждые 15 минут
|
||||
- 7d → каждый час
|
||||
- 30d → каждые 6 часов
|
||||
3. Recharts строит интерактивные графики
|
||||
|
||||
### Автоочистка (рекомендуется):
|
||||
Добавьте cron-задачу для удаления старых метрик:
|
||||
```sql
|
||||
-- Удалять метрики старше 30 дней
|
||||
DELETE FROM server_metrics WHERE timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY);
|
||||
```
|
||||
|
||||
Или в crontab:
|
||||
```bash
|
||||
0 2 * * * mysql -u root -pПАРОЛЬ ospabhost -e "DELETE FROM server_metrics WHERE timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY);"
|
||||
```
|
||||
|
||||
## 🎨 Внешний вид
|
||||
|
||||
### Карточки метрик:
|
||||
- **CPU**: Процент загрузки с цветовой индикацией
|
||||
- **Память**: Процент + используемый объём / всего
|
||||
- **Диск**: Процент + используемый объём / всего
|
||||
- **Сеть**: Входящий/исходящий трафик + Uptime
|
||||
|
||||
### Графики:
|
||||
- **CPU**: Плавная заливка оранжевым
|
||||
- **Memory/Disk**: Двойной линейный график (синий/зелёный)
|
||||
- **Network**: Двойная заливка (фиолетовый/розовый)
|
||||
|
||||
## 🔧 API примеры
|
||||
|
||||
### Получить текущие метрики:
|
||||
```bash
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
http://localhost:5000/api/server/1/metrics
|
||||
```
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"vmid": 105,
|
||||
"status": "running",
|
||||
"uptime": 3600,
|
||||
"cpu": 0.15,
|
||||
"memory": {
|
||||
"used": 536870912,
|
||||
"max": 1073741824,
|
||||
"usage": 50.0
|
||||
},
|
||||
"disk": {
|
||||
"used": 2147483648,
|
||||
"max": 10737418240,
|
||||
"usage": 20.0
|
||||
},
|
||||
"network": {
|
||||
"in": 1048576,
|
||||
"out": 524288
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Получить историю:
|
||||
```bash
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
"http://localhost:5000/api/server/1/metrics/history?period=24h"
|
||||
```
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"period": "24h",
|
||||
"data": [
|
||||
{
|
||||
"timestamp": "2025-11-01T10:00:00.000Z",
|
||||
"cpuUsage": 15.2,
|
||||
"memoryUsage": 48.5,
|
||||
"diskUsage": 20.1,
|
||||
"networkIn": 1048576,
|
||||
"networkOut": 524288,
|
||||
"status": "running"
|
||||
}
|
||||
],
|
||||
"total": 96
|
||||
}
|
||||
```
|
||||
|
||||
### Получить сводку:
|
||||
```bash
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
http://localhost:5000/api/server/1/metrics/summary
|
||||
```
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"cpu": { "avg": 12.5, "max": 45.2, "min": 2.1 },
|
||||
"memory": { "avg": 48.3, "max": 72.1, "min": 35.2 },
|
||||
"disk": { "avg": 20.0, "max": 21.5, "min": 19.8 },
|
||||
"network": {
|
||||
"totalIn": 104857600,
|
||||
"totalOut": 52428800
|
||||
},
|
||||
"uptime": 86400
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔒 Безопасность
|
||||
|
||||
- ✅ Все endpoints требуют авторизации (authMiddleware)
|
||||
- ✅ Пользователь видит только метрики своих серверов
|
||||
- ✅ CASCADE DELETE - метрики удаляются вместе с сервером
|
||||
- ✅ Нет лимитов на количество запросов (можно добавить rate limiting)
|
||||
|
||||
## 📊 База данных
|
||||
|
||||
Структура таблицы:
|
||||
```sql
|
||||
CREATE TABLE `server_metrics` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`serverId` INT NOT NULL,
|
||||
`cpuUsage` DOUBLE DEFAULT 0,
|
||||
`memoryUsage` DOUBLE DEFAULT 0,
|
||||
`memoryUsed` BIGINT DEFAULT 0,
|
||||
`memoryMax` BIGINT DEFAULT 0,
|
||||
`diskUsage` DOUBLE DEFAULT 0,
|
||||
`diskUsed` BIGINT DEFAULT 0,
|
||||
`diskMax` BIGINT DEFAULT 0,
|
||||
`networkIn` BIGINT DEFAULT 0,
|
||||
`networkOut` BIGINT DEFAULT 0,
|
||||
`status` VARCHAR(191) DEFAULT 'unknown',
|
||||
`uptime` BIGINT DEFAULT 0,
|
||||
`timestamp` DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `server_metrics_serverId_timestamp_idx` (`serverId`, `timestamp`),
|
||||
FOREIGN KEY (`serverId`) REFERENCES `server`(`id`) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
Размер записи: ~100 байт
|
||||
При частоте 1 метрика/минуту: ~144 KB/день/сервер
|
||||
|
||||
## 🎯 Рекомендации
|
||||
|
||||
1. **Cron для сбора метрик**:
|
||||
Создайте задачу, которая каждые 5 минут запрашивает метрики всех серверов:
|
||||
```javascript
|
||||
// backend/src/cron/collectMetrics.ts
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { getContainerStats } from './modules/server/proxmoxApi';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function collectAllMetrics() {
|
||||
const servers = await prisma.server.findMany({
|
||||
where: { status: 'running' }
|
||||
});
|
||||
|
||||
for (const server of servers) {
|
||||
if (!server.proxmoxId) continue;
|
||||
try {
|
||||
const stats = await getContainerStats(server.proxmoxId);
|
||||
if (stats.status === 'success' && stats.data) {
|
||||
await prisma.serverMetric.create({ /* ... */ });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Ошибка сбора метрик для сервера ${server.id}:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Запускать каждые 5 минут
|
||||
setInterval(collectAllMetrics, 5 * 60 * 1000);
|
||||
```
|
||||
|
||||
2. **Партиционирование таблицы** (для высоких нагрузок):
|
||||
```sql
|
||||
ALTER TABLE server_metrics
|
||||
PARTITION BY RANGE (YEAR(timestamp) * 100 + MONTH(timestamp)) (
|
||||
PARTITION p202511 VALUES LESS THAN (202512),
|
||||
PARTITION p202512 VALUES LESS THAN (202601),
|
||||
PARTITION pmax VALUES LESS THAN MAXVALUE
|
||||
);
|
||||
```
|
||||
|
||||
3. **Кэширование**:
|
||||
Добавьте Redis для кэширования текущих метрик (TTL 30 секунд).
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
**1 ноября 2025**:
|
||||
- ✅ Добавлена модель ServerMetric в Prisma
|
||||
- ✅ Созданы 3 API endpoint'а для метрик
|
||||
- ✅ Реализован компонент ServerMetrics с графиками
|
||||
- ✅ Интегрирован в панель управления сервером
|
||||
- ✅ Установлена библиотека Recharts для графиков
|
||||
- ✅ Добавлена SQL миграция
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
**Проблема**: Графики не отображаются
|
||||
- Проверьте консоль браузера на ошибки API
|
||||
- Убедитесь, что сервер запущен и метрики собираются
|
||||
- Проверьте, что таблица `server_metrics` создана
|
||||
|
||||
**Проблема**: "Cannot read property 'cpu' of undefined"
|
||||
- Сервер ещё не имеет метрик в БД
|
||||
- Подождите 1-2 минуты после создания сервера
|
||||
- Вручную запросите `/api/server/:id/metrics`
|
||||
|
||||
**Проблема**: Слишком большая база данных
|
||||
- Настройте автоочистку старых метрик (см. выше)
|
||||
- Уменьшите частоту сбора данных
|
||||
- Используйте партиционирование
|
||||
|
||||
## 🎉 Готово!
|
||||
|
||||
Теперь у вас полноценная система мониторинга с:
|
||||
- ✅ Реал-тайм метриками
|
||||
- ✅ Интерактивными графиками
|
||||
- ✅ Историей данных
|
||||
- ✅ Красивым интерфейсом
|
||||
- ✅ Автоматическим обновлением
|
||||
|
||||
Пользователи могут отслеживать нагрузку на свои серверы в режиме реального времени! 🚀
|
||||
@@ -1,154 +0,0 @@
|
||||
# Nginx Deployment Guide for ospab.host
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ubuntu 20.04+ или Debian 11+
|
||||
- Nginx 1.18+
|
||||
- Node.js 18+
|
||||
- PM2 (для управления процессами)
|
||||
- Certbot (для SSL)
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Install Nginx
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install nginx -y
|
||||
```
|
||||
|
||||
### 2. Install Certbot
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx -y
|
||||
```
|
||||
|
||||
### 3. Setup SSL Certificate
|
||||
|
||||
```bash
|
||||
# Stop nginx temporarily
|
||||
sudo systemctl stop nginx
|
||||
|
||||
# Get certificate
|
||||
sudo certbot certonly --standalone -d ospab.host -d www.ospab.host
|
||||
|
||||
# Restart nginx
|
||||
sudo systemctl start nginx
|
||||
```
|
||||
|
||||
### 4. Deploy Nginx Configuration
|
||||
|
||||
```bash
|
||||
# Copy config
|
||||
sudo cp nginx.conf /etc/nginx/sites-available/ospab.host
|
||||
|
||||
# Create symlink
|
||||
sudo ln -s /etc/nginx/sites-available/ospab.host /etc/nginx/sites-enabled/
|
||||
|
||||
# Remove default config
|
||||
sudo rm /etc/nginx/sites-enabled/default
|
||||
|
||||
# Test configuration
|
||||
sudo nginx -t
|
||||
|
||||
# Reload nginx
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 5. Deploy Application
|
||||
|
||||
```bash
|
||||
# Create deployment directory
|
||||
sudo mkdir -p /var/www/ospab.host
|
||||
|
||||
# Clone repository
|
||||
cd /var/www/ospab.host
|
||||
git clone https://github.com/YOUR_REPO/ospabhost8.1.git .
|
||||
|
||||
# Build frontend
|
||||
cd frontend
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Build backend
|
||||
cd ../backend
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Start backend with PM2
|
||||
pm2 start dist/index.js --name "ospab-backend"
|
||||
pm2 save
|
||||
pm2 startup
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
/var/www/ospab.host/
|
||||
├── frontend/
|
||||
│ └── dist/ # React SPA build output
|
||||
├── backend/
|
||||
│ ├── dist/ # Compiled TypeScript
|
||||
│ └── uploads/ # Uploaded files
|
||||
└── nginx.conf # Nginx configuration
|
||||
```
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# Check nginx status
|
||||
sudo systemctl status nginx
|
||||
|
||||
# Reload nginx config
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
|
||||
# View logs
|
||||
sudo tail -f /var/log/nginx/ospab.host.access.log
|
||||
sudo tail -f /var/log/nginx/ospab.host.error.log
|
||||
|
||||
# PM2 commands
|
||||
pm2 status
|
||||
pm2 logs ospab-backend
|
||||
pm2 restart ospab-backend
|
||||
|
||||
# Renew SSL certificate
|
||||
sudo certbot renew --dry-run
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
- API endpoints: 10 requests/second (burst 20)
|
||||
- Login/Register: 5 requests/minute (burst 5)
|
||||
|
||||
## Security Features
|
||||
|
||||
- HSTS enabled
|
||||
- XSS Protection
|
||||
- Frame Options (SAMEORIGIN)
|
||||
- Content-Type sniffing prevention
|
||||
- Blocked access to .git, .env, node_modules
|
||||
- Blocked sensitive file extensions (.sql, .bak, .log)
|
||||
|
||||
## SSL Auto-Renewal
|
||||
|
||||
Add to crontab:
|
||||
|
||||
```bash
|
||||
sudo crontab -e
|
||||
# Add line:
|
||||
0 12 * * * /usr/bin/certbot renew --quiet
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 502 Bad Gateway
|
||||
- Check if backend is running: `pm2 status`
|
||||
- Check backend logs: `pm2 logs ospab-backend`
|
||||
|
||||
### 504 Gateway Timeout
|
||||
- Increase `proxy_read_timeout` in nginx config
|
||||
- Check backend performance
|
||||
|
||||
### SSL Issues
|
||||
- Check certificate: `sudo certbot certificates`
|
||||
- Renew if needed: `sudo certbot renew`
|
||||
@@ -1,259 +0,0 @@
|
||||
# Исправление Push-уведомлений
|
||||
|
||||
## Проблема
|
||||
|
||||
Push-уведомления не работали по следующим причинам:
|
||||
|
||||
### 1. **Кнопка "Включить уведомления" не зависела от состояния разрешения**
|
||||
|
||||
#### До:
|
||||
```tsx
|
||||
{!pushEnabled && 'Notification' in window && (
|
||||
<button onClick={handleEnablePush}>Включить уведомления</button>
|
||||
)}
|
||||
```
|
||||
|
||||
**Проблема:** Кнопка показывалась, даже если пользователь заблокировал уведомления (`Notification.permission === 'denied'`). Клик по ней приводил к ошибке, так как браузер не давал повторно запросить разрешение.
|
||||
|
||||
#### После:
|
||||
```tsx
|
||||
{!pushEnabled && 'Notification' in window && pushPermission !== 'denied' && (
|
||||
<button onClick={handleEnablePush}>Включить уведомления</button>
|
||||
)}
|
||||
|
||||
{pushPermission === 'denied' && (
|
||||
<div className="alert alert-warning">
|
||||
Push-уведомления заблокированы. Разрешите их в настройках браузера.
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
- Кнопка показывается только когда `pushPermission === 'default'` (не запрашивалось)
|
||||
- Если `pushPermission === 'denied'`, показывается предупреждение с инструкцией
|
||||
|
||||
### 2. **Service Worker мог не копироваться в dist при сборке**
|
||||
|
||||
#### До:
|
||||
```typescript
|
||||
// vite.config.ts
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
```
|
||||
|
||||
**Проблема:** Файл `public/service-worker.js` не копировался автоматически в `dist/` при сборке, что приводило к 404 ошибке при регистрации.
|
||||
|
||||
#### После:
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
{
|
||||
name: 'copy-service-worker',
|
||||
writeBundle() {
|
||||
copyFileSync(
|
||||
resolve(__dirname, 'public/service-worker.js'),
|
||||
resolve(__dirname, 'dist/service-worker.js')
|
||||
)
|
||||
console.log('✅ Service worker скопирован в dist/')
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
**Решение:** Добавлен плагин Vite, который автоматически копирует `service-worker.js` в корень `dist/` при каждой сборке.
|
||||
|
||||
### 3. **Недостаточная диагностика ошибок**
|
||||
|
||||
#### До:
|
||||
```typescript
|
||||
console.error('Ошибка подключения Push-уведомлений:', error);
|
||||
```
|
||||
|
||||
#### После:
|
||||
```typescript
|
||||
console.log('📝 Регистрируем Service Worker...');
|
||||
const registration = await navigator.serviceWorker.register('/service-worker.js');
|
||||
console.log('✅ Service Worker зарегистрирован:', registration);
|
||||
|
||||
console.log('📝 Получаем VAPID ключ...');
|
||||
const vapidPublicKey = await getVapidKey();
|
||||
console.log('✅ VAPID ключ получен:', vapidPublicKey.substring(0, 20) + '...');
|
||||
|
||||
console.log('📝 Создаём Push подписку...');
|
||||
const subscription = await registration.pushManager.subscribe({...});
|
||||
console.log('✅ Push подписка создана:', subscription.endpoint);
|
||||
```
|
||||
|
||||
**Решение:** Добавлены подробные логи на каждом этапе подключения Push-уведомлений для быстрой диагностики проблем.
|
||||
|
||||
## Архитектура Push-уведомлений
|
||||
|
||||
### Frontend (`notificationService.ts`)
|
||||
```
|
||||
1. Notification.requestPermission() → Запрос разрешения
|
||||
2. navigator.serviceWorker.register() → Регистрация SW
|
||||
3. GET /api/notifications/vapid-key → Получение публичного ключа
|
||||
4. registration.pushManager.subscribe() → Создание подписки
|
||||
5. POST /api/notifications/subscribe-push → Отправка подписки на сервер
|
||||
```
|
||||
|
||||
### Backend
|
||||
```
|
||||
1. GET /api/notifications/vapid-key → Возвращает VAPID_PUBLIC_KEY из .env
|
||||
2. POST /api/notifications/subscribe-push → Сохраняет подписку в PushSubscription
|
||||
3. Отправка уведомлений → webpush.sendNotification() для каждой подписки
|
||||
```
|
||||
|
||||
### Service Worker (`public/service-worker.js`)
|
||||
```javascript
|
||||
self.addEventListener('push', (event) => {
|
||||
const data = event.data.json();
|
||||
self.registration.showNotification(data.title, {
|
||||
body: data.body,
|
||||
icon: data.icon || '/favicon.svg',
|
||||
...
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Проверка работы
|
||||
|
||||
### 1. Проверка VAPID ключей
|
||||
```bash
|
||||
curl https://ospab.host:5000/api/notifications/vapid-key \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
Должен вернуть:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"publicKey": "BPtLNi3TY1ifUWTkgZrhxoEH6ihDgknFcgzc3xzFQg07PeuJ1TsJDQZqA32VqlxUo03g_mG0yKCKqADb4r5fnsM"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Проверка Service Worker
|
||||
Откройте `https://ospab.host` → DevTools → Application → Service Workers
|
||||
|
||||
Должен быть зарегистрирован: `/service-worker.js` со статусом **Activated**
|
||||
|
||||
### 3. Проверка подписки
|
||||
После нажатия "Включить уведомления" в консоли должны появиться:
|
||||
```
|
||||
📝 Запрашиваем разрешение на уведомления...
|
||||
📝 Результат запроса разрешения: granted
|
||||
📝 Регистрируем Service Worker...
|
||||
✅ Service Worker зарегистрирован: ServiceWorkerRegistration {...}
|
||||
📝 Ожидаем готовности Service Worker...
|
||||
✅ Service Worker готов
|
||||
📝 Получаем VAPID ключ...
|
||||
✅ VAPID ключ получен: BPtLNi3TY1ifUWTk...
|
||||
📝 Создаём Push подписку...
|
||||
✅ Push подписка создана: https://fcm.googleapis.com/fcm/send/...
|
||||
📝 Отправляем подписку на сервер...
|
||||
✅ Push-уведомления успешно подключены
|
||||
```
|
||||
|
||||
### 4. Проверка в базе данных
|
||||
```sql
|
||||
SELECT * FROM PushSubscription WHERE userId = YOUR_USER_ID;
|
||||
```
|
||||
|
||||
Должна быть запись с endpoint, p256dh, auth.
|
||||
|
||||
### 5. Тестовая отправка
|
||||
Можно создать тестовую отправку через backend:
|
||||
```typescript
|
||||
import { sendPushNotification } from './modules/notification/push.service';
|
||||
|
||||
await sendPushNotification(userId, {
|
||||
title: 'Тестовое уведомление',
|
||||
body: 'Push-уведомления работают!',
|
||||
icon: '/logo192.png'
|
||||
});
|
||||
```
|
||||
|
||||
## Состояния Notification.permission
|
||||
|
||||
| Состояние | Описание | UI |
|
||||
|-----------|----------|-----|
|
||||
| `default` | Разрешение не запрашивалось | Показывается синяя кнопка "Включить уведомления" |
|
||||
| `granted` | Разрешение получено | Кнопка скрыта, уведомления работают |
|
||||
| `denied` | Пользователь заблокировал | Показывается красное предупреждение с инструкцией |
|
||||
|
||||
## Разблокировка в браузерах
|
||||
|
||||
### Chrome/Edge
|
||||
1. Нажмите на иконку 🔒 (замок) слева от адресной строки
|
||||
2. Найдите "Уведомления"
|
||||
3. Выберите "Разрешить"
|
||||
4. Обновите страницу
|
||||
|
||||
### Firefox
|
||||
1. Откройте Настройки → Приватность и защита
|
||||
2. Прокрутите до раздела "Разрешения"
|
||||
3. Нажмите "Настройки" рядом с "Уведомления"
|
||||
4. Найдите `ospab.host` и измените на "Разрешить"
|
||||
|
||||
### Safari
|
||||
1. Safari → Настройки → Веб-сайты
|
||||
2. Выберите "Уведомления"
|
||||
3. Найдите `ospab.host` и выберите "Разрешить"
|
||||
|
||||
## Файлы изменены
|
||||
|
||||
1. ✅ `frontend/src/pages/dashboard/notifications.tsx`
|
||||
- Добавлено состояние `pushPermission`
|
||||
- Условный рендеринг кнопки/предупреждения
|
||||
- Обновление состояния после запроса
|
||||
|
||||
2. ✅ `frontend/src/services/notificationService.ts`
|
||||
- Добавлены подробные логи в `requestPushPermission()`
|
||||
- Эмодзи-маркеры для быстрого поиска в консоли
|
||||
|
||||
3. ✅ `frontend/vite.config.ts`
|
||||
- Плагин копирования `service-worker.js` в `dist/`
|
||||
|
||||
## Деплой
|
||||
|
||||
```bash
|
||||
# Frontend
|
||||
cd frontend
|
||||
npm run build
|
||||
# Скопируйте dist/ на production сервер
|
||||
|
||||
# Backend (если были изменения)
|
||||
cd backend
|
||||
npm run build
|
||||
pm2 restart ospab-backend
|
||||
```
|
||||
|
||||
## Возможные проблемы
|
||||
|
||||
### Service Worker не регистрируется
|
||||
- **Проверка:** DevTools → Application → Service Workers
|
||||
- **Причина:** Файл `service-worker.js` не доступен по адресу `https://ospab.host/service-worker.js`
|
||||
- **Решение:** Убедитесь, что файл скопирован в корень `dist/` и доступен через nginx
|
||||
|
||||
### 403 Forbidden при запросе VAPID ключа
|
||||
- **Проверка:** Network → `/api/notifications/vapid-key` → Response
|
||||
- **Причина:** Не передаётся токен авторизации
|
||||
- **Решение:** Проверьте, что в localStorage есть `access_token`
|
||||
|
||||
### Push-уведомления не приходят
|
||||
- **Проверка:** Console → Ошибки от `webpush.sendNotification()`
|
||||
- **Причина:** Неправильные VAPID ключи или подписка устарела
|
||||
- **Решение:** Перегенерируйте VAPID ключи (`npx web-push generate-vapid-keys`) и переподпишитесь
|
||||
|
||||
### Подписка создаётся, но не сохраняется в БД
|
||||
- **Проверка:** Console → Network → `/api/notifications/subscribe-push` → Response
|
||||
- **Причина:** Ошибка на backend при сохранении в Prisma
|
||||
- **Решение:** Проверьте логи backend (`pm2 logs ospab-backend`)
|
||||
|
||||
---
|
||||
|
||||
**Статус:** ✅ Исправлено и готово к тестированию
|
||||
**Дата:** 2025-01-20
|
||||
@@ -1,264 +0,0 @@
|
||||
# Тестовая отправка Push-уведомлений
|
||||
|
||||
## Что добавлено
|
||||
|
||||
В админ-панели теперь есть кнопка **"🧪 Тест Push-уведомления"** с подробным логированием всего процесса отправки.
|
||||
|
||||
### Backend endpoint
|
||||
|
||||
**POST** `/api/notifications/test-push`
|
||||
|
||||
- ✅ Требует авторизацию (Bearer token)
|
||||
- ✅ Требует права администратора (`isAdmin: true`)
|
||||
- ✅ Подробное логирование каждого шага
|
||||
|
||||
### Frontend кнопка
|
||||
|
||||
Расположена в **Админ-панели** (правый верхний угол).
|
||||
|
||||
## Логирование
|
||||
|
||||
### Backend логи (консоль сервера)
|
||||
|
||||
```
|
||||
🧪 [TEST PUSH] Запрос от пользователя: { userId: 1, username: 'admin' }
|
||||
✅ [TEST PUSH] Пользователь является админом, продолжаем...
|
||||
📊 [TEST PUSH] Найдено подписок для пользователя 1: 2
|
||||
📱 Подписка 1: { id: 123, endpoint: 'https://fcm.googleapis...', userAgent: 'Mozilla/5.0...', ... }
|
||||
📱 Подписка 2: { id: 124, endpoint: 'https://fcm.googleapis...', userAgent: 'Chrome...', ... }
|
||||
📝 [TEST PUSH] Создаём тестовое уведомление в БД...
|
||||
✅ [TEST PUSH] Уведомление создано в БД: 456
|
||||
📤 [TEST PUSH] Отправляем Push-уведомление...
|
||||
✅ [TEST PUSH] Push-уведомление успешно отправлено!
|
||||
```
|
||||
|
||||
### Frontend логи (консоль браузера)
|
||||
|
||||
```
|
||||
🧪 [FRONTEND] Начинаем тестовую отправку Push-уведомления...
|
||||
📝 [FRONTEND] Токен найден: Да
|
||||
📤 [FRONTEND] Отправляем запрос на: https://ospab.host:5000/api/notifications/test-push
|
||||
✅ [FRONTEND] Ответ от сервера: { success: true, message: '...', data: { notificationId: 456, subscriptionsCount: 2 } }
|
||||
📊 [FRONTEND] Детали: { notificationId: 456, subscriptionsCount: 2 }
|
||||
```
|
||||
|
||||
## Как использовать
|
||||
|
||||
### 1. Включите Push-уведомления
|
||||
|
||||
1. Перейдите в **Дашборд → Уведомления**
|
||||
2. Нажмите **"Включить уведомления"** (синяя кнопка)
|
||||
3. Разрешите уведомления в браузере
|
||||
4. Дождитесь сообщения **"Push-уведомления успешно подключены!"**
|
||||
|
||||
### 2. Откройте админ-панель
|
||||
|
||||
1. Перейдите в **Дашборд → Админ-панель** (👑 иконка в сайдбаре)
|
||||
2. В правом верхнем углу увидите кнопку **"🧪 Тест Push-уведомления"**
|
||||
|
||||
### 3. Нажмите кнопку
|
||||
|
||||
1. Откройте **DevTools → Console** (F12)
|
||||
2. Нажмите **"🧪 Тест Push-уведомления"**
|
||||
3. Следите за логами в консоли браузера
|
||||
|
||||
### 4. Проверьте сервер
|
||||
|
||||
Откройте консоль сервера (SSH):
|
||||
```bash
|
||||
pm2 logs ospab-backend --lines 50
|
||||
```
|
||||
|
||||
Увидите подробные логи с эмодзи-маркерами.
|
||||
|
||||
### 5. Проверьте результат
|
||||
|
||||
Через несколько секунд должно прийти Push-уведомление:
|
||||
- **Заголовок:** 🧪 Тестовое уведомление
|
||||
- **Текст:** Это тестовое Push-уведомление. Если вы его видите — всё работает отлично!
|
||||
- **Иконка:** /logo192.png
|
||||
- **Клик:** Перенаправляет на /dashboard/notifications
|
||||
|
||||
## Возможные ошибки
|
||||
|
||||
### ❌ "У вас нет прав администратора" (403)
|
||||
|
||||
**Причина:** Пользователь не является администратором.
|
||||
|
||||
**Решение:**
|
||||
```sql
|
||||
UPDATE User SET isAdmin = 1 WHERE id = YOUR_USER_ID;
|
||||
```
|
||||
|
||||
### ❌ "У вас нет активных Push-подписок" (400)
|
||||
|
||||
**Причина:** Push-уведомления не включены.
|
||||
|
||||
**Решение:**
|
||||
1. Перейдите в **Дашборд → Уведомления**
|
||||
2. Нажмите **"Включить уведомления"**
|
||||
3. Разрешите в браузере
|
||||
4. Попробуйте снова
|
||||
|
||||
### ❌ "Уведомление создано в БД, но ошибка при отправке Push" (500)
|
||||
|
||||
**Причины:**
|
||||
1. Неправильные VAPID ключи
|
||||
2. Подписка устарела
|
||||
3. Проблема с web-push библиотекой
|
||||
|
||||
**Решение:**
|
||||
|
||||
**Проверьте VAPID ключи:**
|
||||
```bash
|
||||
cd /var/www/ospab-host/backend
|
||||
cat .env | grep VAPID
|
||||
```
|
||||
|
||||
Должны быть заполнены:
|
||||
```
|
||||
VAPID_PUBLIC_KEY=BPtLNi3TY1ifUWTkgZrhxoEH6ihDgknFcgzc3xzFQg07PeuJ1TsJDQZqA32VqlxUo03g_mG0yKCKqADb4r5fnsM
|
||||
VAPID_PRIVATE_KEY=5uEJBxEzCLhcMBPyGEw_GDx9JDneb6poZiX8f3b0zNE
|
||||
VAPID_SUBJECT=mailto:support@ospab.host
|
||||
```
|
||||
|
||||
**Пересоздайте подписку:**
|
||||
1. Удалите старую: `DELETE FROM PushSubscription WHERE userId = YOUR_USER_ID;`
|
||||
2. Перейдите в **Дашборд → Уведомления**
|
||||
3. Включите уведомления заново
|
||||
|
||||
### ❌ 410 Gone - Подписка устарела
|
||||
|
||||
**Причина:** Push подписка больше недействительна (браузер её отозвал).
|
||||
|
||||
**Решение:** Сервис автоматически удаляет устаревшие подписки. Пересоздайте подписку (см. выше).
|
||||
|
||||
## Диагностика проблем
|
||||
|
||||
### Проверка подписок в БД
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
ps.id,
|
||||
ps.userId,
|
||||
ps.endpoint,
|
||||
ps.userAgent,
|
||||
ps.createdAt,
|
||||
ps.lastUsed,
|
||||
u.username
|
||||
FROM PushSubscription ps
|
||||
JOIN User u ON ps.userId = u.id
|
||||
ORDER BY ps.createdAt DESC;
|
||||
```
|
||||
|
||||
### Проверка уведомлений в БД
|
||||
|
||||
```sql
|
||||
SELECT * FROM Notification
|
||||
WHERE type = 'test'
|
||||
ORDER BY createdAt DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
### Проверка Service Worker
|
||||
|
||||
1. Откройте сайт в браузере
|
||||
2. DevTools (F12) → Application → Service Workers
|
||||
3. Должен быть зарегистрирован `/service-worker.js` со статусом **Activated**
|
||||
|
||||
### Проверка VAPID ключа через API
|
||||
|
||||
```bash
|
||||
curl https://ospab.host:5000/api/notifications/vapid-key \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
Должен вернуть:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"publicKey": "BPtLNi3TY1ifUWTkgZrhxoEH6ihDgknFcgzc3xzFQg07PeuJ1TsJDQZqA32VqlxUo03g_mG0yKCKqADb4r5fnsM"
|
||||
}
|
||||
```
|
||||
|
||||
## Что логируется
|
||||
|
||||
### Backend
|
||||
|
||||
| Эмодзи | Описание |
|
||||
|--------|----------|
|
||||
| 🧪 | Начало тестовой отправки |
|
||||
| ✅ | Успешный этап |
|
||||
| ❌ | Ошибка |
|
||||
| 📊 | Статистика/данные |
|
||||
| 📱 | Информация о подписке |
|
||||
| 📝 | Создание записи |
|
||||
| 📤 | Отправка |
|
||||
| ⚠️ | Предупреждение |
|
||||
|
||||
### Frontend
|
||||
|
||||
| Эмодзи | Описание |
|
||||
|--------|----------|
|
||||
| 🧪 | Начало процесса |
|
||||
| 📝 | Проверка данных |
|
||||
| 📤 | Отправка запроса |
|
||||
| ✅ | Успешный ответ |
|
||||
| ❌ | Ошибка |
|
||||
| 📊 | Детали ответа |
|
||||
| 📋 | Детали ошибки |
|
||||
|
||||
## Ручная отправка через код
|
||||
|
||||
Если нужно отправить тестовое уведомление программно:
|
||||
|
||||
```typescript
|
||||
import { sendPushNotification } from './modules/notification/push.service';
|
||||
|
||||
// В любом месте backend кода
|
||||
await sendPushNotification(userId, {
|
||||
title: 'Заголовок',
|
||||
body: 'Текст уведомления',
|
||||
icon: '/logo192.png',
|
||||
badge: '/favicon.svg',
|
||||
data: {
|
||||
notificationId: 123,
|
||||
actionUrl: '/dashboard'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Файлы изменены
|
||||
|
||||
1. ✅ `backend/src/modules/notification/notification.controller.ts`
|
||||
- Добавлен `testPushNotification()` с подробным логированием
|
||||
|
||||
2. ✅ `backend/src/modules/notification/notification.routes.ts`
|
||||
- Добавлен роут `POST /api/notifications/test-push`
|
||||
|
||||
3. ✅ `frontend/src/pages/dashboard/admin.tsx`
|
||||
- Добавлена кнопка тестовой отправки
|
||||
- Добавлен `handleTestPushNotification()` с логированием
|
||||
- Состояние `testingPush` для индикации загрузки
|
||||
|
||||
## Деплой
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd /var/www/ospab-host/backend
|
||||
npm run build
|
||||
pm2 restart ospab-backend
|
||||
|
||||
# Frontend
|
||||
cd /var/www/ospab-host/frontend
|
||||
npm run build
|
||||
# Скопируйте dist/ в web root
|
||||
|
||||
# Проверка логов
|
||||
pm2 logs ospab-backend --lines 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Статус:** ✅ Готово к тестированию
|
||||
**Дата:** 2025-11-01
|
||||
@@ -1,374 +0,0 @@
|
||||
# Где должно появиться Push-уведомление?
|
||||
|
||||
## 🎯 Правильный ответ: В СИСТЕМНЫХ УВЕДОМЛЕНИЯХ
|
||||
|
||||
Push-уведомления - это **НЕ уведомления на сайте**, а **системные уведомления браузера/ОС**.
|
||||
|
||||
### Windows
|
||||
- Появляются в **правом нижнем углу экрана** (Action Center)
|
||||
- Выглядят как обычные Windows уведомления
|
||||
- Звук уведомления (если включен)
|
||||
|
||||
### macOS
|
||||
- Появляются в **правом верхнем углу** экрана
|
||||
- Стиль нативных macOS уведомлений
|
||||
|
||||
### Linux
|
||||
- Зависит от DE (GNOME, KDE, etc.)
|
||||
- Обычно верхний правый или верхний центр
|
||||
|
||||
### Android/iOS (мобильные браузеры)
|
||||
- В панели уведомлений телефона
|
||||
- Как обычные push-уведомления приложений
|
||||
|
||||
---
|
||||
|
||||
## ❓ Почему уведомление может не появиться?
|
||||
|
||||
### 1. Уведомления заблокированы в браузере
|
||||
|
||||
**Проверка:**
|
||||
1. Откройте сайт
|
||||
2. Нажмите на **иконку замка** 🔒 слева от адресной строки
|
||||
3. Найдите "Уведомления"
|
||||
4. Должно быть **"Разрешить"** (Allow)
|
||||
|
||||
**Решение:**
|
||||
```
|
||||
Chrome/Edge: 🔒 → Уведомления → Разрешить → Обновить страницу
|
||||
Firefox: Меню → Настройки → Приватность → Разрешения → Уведомления
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Уведомления заблокированы в ОС
|
||||
|
||||
#### Windows 10/11
|
||||
1. **Параметры → Система → Уведомления и действия**
|
||||
2. Убедитесь, что уведомления **включены глобально**
|
||||
3. Найдите ваш браузер в списке приложений
|
||||
4. Убедитесь, что для браузера уведомления **разрешены**
|
||||
|
||||
#### macOS
|
||||
1. **System Preferences → Notifications**
|
||||
2. Найдите ваш браузер (Chrome, Firefox, Safari)
|
||||
3. Убедитесь, что уведомления **включены**
|
||||
|
||||
#### Linux (GNOME)
|
||||
```bash
|
||||
gnome-control-center notifications
|
||||
```
|
||||
Проверьте, что уведомления включены для браузера.
|
||||
|
||||
---
|
||||
|
||||
### 3. Режим "Не беспокоить"
|
||||
|
||||
#### Windows
|
||||
- Проверьте **Action Center** (Win + A)
|
||||
- Отключите "Фокусировка внимания" (Focus Assist)
|
||||
|
||||
#### macOS
|
||||
- Проверьте, что не включен **Do Not Disturb**
|
||||
- Notification Center → Отключите DND
|
||||
|
||||
---
|
||||
|
||||
### 4. Service Worker не зарегистрирован
|
||||
|
||||
**Проверка:**
|
||||
1. Откройте **DevTools** (F12)
|
||||
2. Вкладка **Application**
|
||||
3. Слева: **Service Workers**
|
||||
4. Должен быть зарегистрирован `/service-worker.js` со статусом **"activated and is running"**
|
||||
|
||||
**Если нет:**
|
||||
```javascript
|
||||
// В консоли браузера
|
||||
navigator.serviceWorker.getRegistrations().then(regs => {
|
||||
console.log('Registered Service Workers:', regs.length);
|
||||
regs.forEach(reg => console.log(reg));
|
||||
});
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
1. Перейдите в **Дашборд → Уведомления**
|
||||
2. Нажмите **"Включить уведомления"** снова
|
||||
3. Проверьте консоль на ошибки регистрации
|
||||
|
||||
---
|
||||
|
||||
### 5. Push подписка не создана
|
||||
|
||||
**Проверка в консоли браузера:**
|
||||
```javascript
|
||||
navigator.serviceWorker.ready.then(reg => {
|
||||
reg.pushManager.getSubscription().then(sub => {
|
||||
if (sub) {
|
||||
console.log('✅ Push подписка существует:', sub.endpoint);
|
||||
} else {
|
||||
console.log('❌ Push подписка отсутствует');
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
Включите уведомления заново на странице "Уведомления".
|
||||
|
||||
---
|
||||
|
||||
### 6. Ошибка на сервере при отправке
|
||||
|
||||
**Проверка логов backend:**
|
||||
```bash
|
||||
pm2 logs ospab-backend --lines 100 | grep "TEST PUSH"
|
||||
```
|
||||
|
||||
**Должны увидеть:**
|
||||
```
|
||||
✅ [TEST PUSH] Push-уведомление успешно отправлено!
|
||||
```
|
||||
|
||||
**Если ошибка:**
|
||||
```
|
||||
❌ [TEST PUSH] Ошибка при отправке Push: ...
|
||||
```
|
||||
|
||||
**Возможные причины:**
|
||||
- Неправильные VAPID ключи
|
||||
- Устаревшая подписка (410 Gone)
|
||||
- Проблемы с сетью
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Пошаговая диагностика
|
||||
|
||||
### Шаг 1: Проверьте разрешения браузера
|
||||
|
||||
```javascript
|
||||
// В консоли браузера
|
||||
console.log('Notification permission:', Notification.permission);
|
||||
// Должно быть: "granted"
|
||||
|
||||
if (Notification.permission !== 'granted') {
|
||||
console.log('❌ Уведомления не разрешены!');
|
||||
console.log('Перейдите в Дашборд → Уведомления → Включить уведомления');
|
||||
}
|
||||
```
|
||||
|
||||
### Шаг 2: Проверьте Service Worker
|
||||
|
||||
```javascript
|
||||
// В консоли браузера
|
||||
navigator.serviceWorker.getRegistrations().then(regs => {
|
||||
if (regs.length === 0) {
|
||||
console.log('❌ Service Worker не зарегистрирован!');
|
||||
} else {
|
||||
console.log('✅ Service Workers найдены:', regs.length);
|
||||
regs.forEach((reg, i) => {
|
||||
console.log(` SW ${i+1}:`, reg.active ? '✅ Активен' : '❌ Не активен');
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Шаг 3: Проверьте Push подписку
|
||||
|
||||
```javascript
|
||||
// В консоли браузера
|
||||
navigator.serviceWorker.ready.then(reg => {
|
||||
reg.pushManager.getSubscription().then(sub => {
|
||||
if (!sub) {
|
||||
console.log('❌ Push подписка не найдена!');
|
||||
console.log('Включите уведомления в разделе "Уведомления"');
|
||||
} else {
|
||||
console.log('✅ Push подписка активна');
|
||||
console.log(' Endpoint:', sub.endpoint);
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Шаг 4: Тестовое уведомление вручную
|
||||
|
||||
```javascript
|
||||
// В консоли браузера (для быстрой проверки)
|
||||
new Notification('Тест', {
|
||||
body: 'Это локальное тестовое уведомление',
|
||||
icon: '/logo192.png'
|
||||
});
|
||||
```
|
||||
|
||||
**Если это уведомление появилось:**
|
||||
- ✅ Браузер и ОС настроены правильно
|
||||
- ❌ Проблема в Push-подписке или на сервере
|
||||
|
||||
**Если не появилось:**
|
||||
- ❌ Проблема в настройках браузера/ОС
|
||||
- Проверьте разрешения (см. выше)
|
||||
|
||||
### Шаг 5: Проверьте консоль Service Worker
|
||||
|
||||
1. **DevTools → Application → Service Workers**
|
||||
2. Найдите ваш SW
|
||||
3. Кликните **"inspect"** или кнопку консоли
|
||||
4. Откроется отдельная консоль Service Worker
|
||||
5. Нажмите тестовую кнопку в админке
|
||||
6. Следите за логами:
|
||||
|
||||
```
|
||||
[Service Worker] Push-уведомление получено
|
||||
[Service Worker] Показываем уведомление: {...}
|
||||
```
|
||||
|
||||
### Шаг 6: Отправьте тестовое уведомление
|
||||
|
||||
1. **Админ-панель → 🧪 Тест Push-уведомления**
|
||||
2. Откройте **консоль браузера (F12)**
|
||||
3. Откройте **консоль сервера** (pm2 logs)
|
||||
4. Нажмите кнопку
|
||||
5. Проверьте логи в обеих консолях
|
||||
|
||||
**Браузер должен показать:**
|
||||
```
|
||||
🧪 [FRONTEND] Начинаем тестовую отправку...
|
||||
📝 [FRONTEND] Токен найден: Да
|
||||
📤 [FRONTEND] Отправляем запрос...
|
||||
✅ [FRONTEND] Ответ от сервера: {success: true, ...}
|
||||
```
|
||||
|
||||
**Сервер должен показать:**
|
||||
```
|
||||
🧪 [TEST PUSH] Запрос от пользователя: {...}
|
||||
✅ [TEST PUSH] Push-уведомление успешно отправлено!
|
||||
```
|
||||
|
||||
**Через 1-3 секунды** должно появиться системное уведомление.
|
||||
|
||||
---
|
||||
|
||||
## 🎬 Видео-пример того, где появляется уведомление
|
||||
|
||||
### Chrome на Windows
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🧪 Тестовое уведомление │
|
||||
│ Это тестовое Push-уведомление. │
|
||||
│ Если вы его видите — всё работает │
|
||||
│ │
|
||||
│ [Закрыть] [Открыть сайт] │
|
||||
└─────────────────────────────────────┘
|
||||
↑
|
||||
Появляется в правом нижнем углу
|
||||
```
|
||||
|
||||
### Firefox на Windows
|
||||
```
|
||||
┌──────────────────────────────┐
|
||||
│ 🧪 Тестовое уведомление │
|
||||
│ Это тестовое Push-уведомле │
|
||||
│ ние. Если вы его видите... │
|
||||
│ │
|
||||
│ [×] │
|
||||
└──────────────────────────────┘
|
||||
↑
|
||||
Правый нижний угол
|
||||
```
|
||||
|
||||
### Chrome на macOS
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ ospab.host │
|
||||
│ 🧪 Тестовое уведомление │
|
||||
│ Это тестовое Push-уведомление │
|
||||
└─────────────────────────────────┘
|
||||
↑
|
||||
Правый верхний угол
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Быстрое решение проблем
|
||||
|
||||
### "Уведомление не появляется вообще"
|
||||
|
||||
1. **Проверьте консоль браузера** на ошибки
|
||||
2. **Проверьте pm2 logs** на ошибки сервера
|
||||
3. **Попробуйте локальное уведомление:**
|
||||
```javascript
|
||||
new Notification('Тест', {body: 'Тест'});
|
||||
```
|
||||
4. Если локальное появилось → проблема в Push-подписке
|
||||
5. Если локальное не появилось → проблема в разрешениях
|
||||
|
||||
### "Ошибка 400 - нет активных подписок"
|
||||
|
||||
1. **Дашборд → Уведомления**
|
||||
2. **"Включить уведомления"**
|
||||
3. **Разрешить** в браузере
|
||||
4. Попробуйте снова
|
||||
|
||||
### "Ошибка 403 - нет прав администратора"
|
||||
|
||||
```sql
|
||||
UPDATE User SET isAdmin = 1 WHERE id = YOUR_USER_ID;
|
||||
```
|
||||
|
||||
### "Ошибка 500 при отправке Push"
|
||||
|
||||
```bash
|
||||
# Проверьте VAPID ключи
|
||||
cd /var/www/ospab-host/backend
|
||||
cat .env | grep VAPID
|
||||
|
||||
# Должны быть заполнены
|
||||
VAPID_PUBLIC_KEY=...
|
||||
VAPID_PRIVATE_KEY=...
|
||||
VAPID_SUBJECT=mailto:support@ospab.host
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Чеклист перед тестированием
|
||||
|
||||
- [ ] Уведомления разрешены в браузере (🔒 → Уведомления → Разрешить)
|
||||
- [ ] Уведомления разрешены в ОС (Windows: Параметры → Уведомления)
|
||||
- [ ] Режим "Не беспокоить" отключен
|
||||
- [ ] Service Worker зарегистрирован (DevTools → Application → Service Workers)
|
||||
- [ ] Push подписка создана (консоль: `navigator.serviceWorker.ready.then(...)`)
|
||||
- [ ] Вы являетесь администратором (isAdmin: true в БД)
|
||||
- [ ] Backend запущен (pm2 list → ospab-backend → online)
|
||||
- [ ] VAPID ключи настроены в .env
|
||||
|
||||
---
|
||||
|
||||
## 📞 Если ничего не помогает
|
||||
|
||||
1. **Очистите всё и начните заново:**
|
||||
|
||||
```javascript
|
||||
// В консоли браузера
|
||||
navigator.serviceWorker.getRegistrations().then(regs => {
|
||||
regs.forEach(reg => reg.unregister());
|
||||
console.log('Service Workers удалены');
|
||||
});
|
||||
|
||||
// Удалите из БД
|
||||
// DELETE FROM PushSubscription WHERE userId = YOUR_ID;
|
||||
|
||||
// Обновите страницу (Ctrl+Shift+R)
|
||||
// Включите уведомления заново
|
||||
```
|
||||
|
||||
2. **Попробуйте другой браузер** (Chrome vs Firefox)
|
||||
|
||||
3. **Попробуйте режим инкогнито** (чтобы исключить расширения)
|
||||
|
||||
4. **Проверьте файрвол** - может блокировать FCM (Firebase Cloud Messaging)
|
||||
|
||||
5. **Проверьте антивирус** - может блокировать уведомления
|
||||
|
||||
---
|
||||
|
||||
**Итог:** Push-уведомление должно появиться как **системное уведомление** в углу экрана, а **НЕ** на сайте как элемент интерфейса!
|
||||
@@ -1,139 +0,0 @@
|
||||
# Конфигурация сети и хранилища для Proxmox
|
||||
|
||||
## Обзор
|
||||
|
||||
Теперь вы можете настроить сетевой интерфейс и диск для контейнеров/VM через переменные окружения в `.env` файле.
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
### 1. Сетевой мост (Network Bridge)
|
||||
|
||||
```env
|
||||
PROXMOX_NETWORK_BRIDGE=vmbr0
|
||||
```
|
||||
|
||||
**Как узнать доступные мосты:**
|
||||
1. Войдите в Proxmox веб-интерфейс
|
||||
2. Перейдите: `Datacenter → Node (sv1) → Network`
|
||||
3. Посмотрите список доступных мостов (обычно `vmbr0`, `vmbr1`, `vmbr2`)
|
||||
|
||||
**Изменение:**
|
||||
- Просто измените значение в `.env` на нужный мост
|
||||
- Например: `PROXMOX_NETWORK_BRIDGE=vmbr1`
|
||||
|
||||
### 2. Хранилище для дисков (Storage)
|
||||
|
||||
```env
|
||||
PROXMOX_VM_STORAGE=local
|
||||
PROXMOX_BACKUP_STORAGE=local
|
||||
PROXMOX_ISO_STORAGE=local
|
||||
```
|
||||
|
||||
**Как узнать доступные хранилища:**
|
||||
1. Войдите в Proxmox веб-интерфейс
|
||||
2. Перейдите: `Datacenter → Storage`
|
||||
3. Посмотрите список доступных хранилищ (обычно `local`, `local-lvm`, `nfs-storage`)
|
||||
|
||||
**Изменение:**
|
||||
- Измените значения в `.env` на нужные хранилища
|
||||
- Например: `PROXMOX_VM_STORAGE=local-lvm`
|
||||
|
||||
## Применение изменений
|
||||
|
||||
После изменения `.env` файла:
|
||||
|
||||
### На локальной машине (разработка):
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
npm run build
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### На production сервере:
|
||||
|
||||
```bash
|
||||
cd /var/www/ospab-host/ospabhost/backend
|
||||
|
||||
# 1. Редактируем .env файл
|
||||
vim .env
|
||||
|
||||
# 2. Изменяем нужные переменные
|
||||
# PROXMOX_NETWORK_BRIDGE=vmbr1 # например, на другой мост
|
||||
# PROXMOX_VM_STORAGE=local-lvm # например, на другое хранилище
|
||||
|
||||
# 3. Пересобираем и перезапускаем
|
||||
npm run build
|
||||
pm2 restart ospab-backend
|
||||
|
||||
# 4. Проверяем логи
|
||||
pm2 logs ospab-backend --lines 30
|
||||
```
|
||||
|
||||
## Проверка настроек
|
||||
|
||||
После создания нового контейнера проверьте его конфигурацию:
|
||||
|
||||
```bash
|
||||
# SSH на Proxmox сервер
|
||||
ssh root@sv1.ospab.host
|
||||
|
||||
# Посмотреть конфигурацию контейнера (замените 100 на VMID)
|
||||
pct config 100
|
||||
|
||||
# Проверить сетевой интерфейс (должен показать ваш мост)
|
||||
# net0: name=eth0,bridge=vmbr0,ip=dhcp
|
||||
|
||||
# Проверить хранилище (должен показать ваше хранилище)
|
||||
# rootfs: local:100/vm-100-disk-0.raw,size=20G
|
||||
```
|
||||
|
||||
## Примеры конфигураций
|
||||
|
||||
### Конфигурация 1: Стандартная (по умолчанию)
|
||||
```env
|
||||
PROXMOX_NETWORK_BRIDGE=vmbr0
|
||||
PROXMOX_VM_STORAGE=local
|
||||
```
|
||||
|
||||
### Конфигурация 2: Отдельная сеть + LVM хранилище
|
||||
```env
|
||||
PROXMOX_NETWORK_BRIDGE=vmbr1
|
||||
PROXMOX_VM_STORAGE=local-lvm
|
||||
```
|
||||
|
||||
### Конфигурация 3: NFS хранилище
|
||||
```env
|
||||
PROXMOX_NETWORK_BRIDGE=vmbr0
|
||||
PROXMOX_VM_STORAGE=nfs-storage
|
||||
PROXMOX_BACKUP_STORAGE=nfs-storage
|
||||
```
|
||||
|
||||
## Решение проблем
|
||||
|
||||
### Ошибка: "storage 'xxx' does not exist"
|
||||
- Проверьте, что хранилище существует в Proxmox (Datacenter → Storage)
|
||||
- Убедитесь, что имя написано правильно (чувствительно к регистру)
|
||||
|
||||
### Ошибка: "bridge 'xxx' does not exist"
|
||||
- Проверьте, что мост существует в Proxmox (Node → Network)
|
||||
- Убедитесь, что имя написано правильно (обычно `vmbr0`, `vmbr1`)
|
||||
|
||||
### Контейнер создаётся, но не имеет сети
|
||||
- Проверьте, что мост активен и настроен правильно
|
||||
- Убедитесь, что DHCP работает в вашей сети (или используйте статический IP)
|
||||
|
||||
## Логирование
|
||||
|
||||
При создании контейнера в логах backend вы увидите:
|
||||
|
||||
```
|
||||
Создание LXC контейнера с параметрами: {
|
||||
...
|
||||
net0: 'name=eth0,bridge=vmbr0,ip=dhcp',
|
||||
rootfs: 'local:20',
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Проверьте эти значения, чтобы убедиться, что используются правильные настройки.
|
||||
@@ -1,132 +0,0 @@
|
||||
# PM2 Шпаргалка
|
||||
|
||||
## 🚀 Основные команды
|
||||
|
||||
```bash
|
||||
# Запуск
|
||||
pm2 start ecosystem.config.js --env production
|
||||
|
||||
# Остановка
|
||||
pm2 stop ospab-backend
|
||||
|
||||
# Перезапуск (без даунтайма)
|
||||
pm2 reload ospab-backend
|
||||
|
||||
# Полный перезапуск
|
||||
pm2 restart ospab-backend
|
||||
|
||||
# Удаление из PM2
|
||||
pm2 delete ospab-backend
|
||||
|
||||
# Список процессов
|
||||
pm2 list
|
||||
|
||||
# Детальная информация
|
||||
pm2 show ospab-backend
|
||||
```
|
||||
|
||||
## 📊 Мониторинг
|
||||
|
||||
```bash
|
||||
# Логи в реальном времени
|
||||
pm2 logs ospab-backend
|
||||
|
||||
# Последние 100 строк
|
||||
pm2 logs ospab-backend --lines 100
|
||||
|
||||
# Только ошибки
|
||||
pm2 logs ospab-backend --err
|
||||
|
||||
# Очистка логов
|
||||
pm2 flush
|
||||
|
||||
# Интерактивный мониторинг
|
||||
pm2 monit
|
||||
```
|
||||
|
||||
## 💾 Сохранение и автозапуск
|
||||
|
||||
```bash
|
||||
# Сохранить текущую конфигурацию
|
||||
pm2 save
|
||||
|
||||
# Настроить автозапуск при перезагрузке
|
||||
pm2 startup
|
||||
|
||||
# Отменить автозапуск
|
||||
pm2 unstartup
|
||||
|
||||
# Удалить сохранённую конфигурацию
|
||||
pm2 kill
|
||||
```
|
||||
|
||||
## 🔧 Управление через npm
|
||||
|
||||
```bash
|
||||
npm run pm2:start # Запуск
|
||||
npm run pm2:stop # Остановка
|
||||
npm run pm2:restart # Перезапуск
|
||||
npm run pm2:logs # Логи
|
||||
npm run pm2:monit # Мониторинг
|
||||
npm run pm2:status # Статус
|
||||
```
|
||||
|
||||
## 📦 Обновление PM2
|
||||
|
||||
```bash
|
||||
# Обновить PM2
|
||||
npm install -g pm2@latest
|
||||
|
||||
# Обновить процессы PM2
|
||||
pm2 update
|
||||
```
|
||||
|
||||
## 🐛 Отладка
|
||||
|
||||
```bash
|
||||
# Показать переменные окружения
|
||||
pm2 env 0
|
||||
|
||||
# Информация о системе
|
||||
pm2 info ospab-backend
|
||||
|
||||
# Метрики
|
||||
pm2 describe ospab-backend
|
||||
```
|
||||
|
||||
## ⚡ Быстрые сценарии
|
||||
|
||||
### Деплой нового кода
|
||||
```bash
|
||||
git pull origin main
|
||||
cd backend
|
||||
npm install
|
||||
npm run build
|
||||
pm2 reload ospab-backend
|
||||
pm2 save
|
||||
```
|
||||
|
||||
### Полный перезапуск системы
|
||||
```bash
|
||||
pm2 kill
|
||||
pm2 start ecosystem.config.js --env production
|
||||
pm2 save
|
||||
pm2 startup # Выполнить команду, которую выведет
|
||||
```
|
||||
|
||||
### Проверка статуса
|
||||
```bash
|
||||
pm2 list
|
||||
pm2 logs ospab-backend --lines 50
|
||||
curl http://localhost:5000
|
||||
```
|
||||
|
||||
## 🎯 Текущая конфигурация
|
||||
|
||||
- **Название**: ospab-backend
|
||||
- **Экземпляры**: 4
|
||||
- **Режим**: cluster
|
||||
- **Порт**: 5000
|
||||
- **Логи**: ./logs/pm2-error.log, ./logs/pm2-out.log
|
||||
- **Автоперезапуск**: Да
|
||||
- **Лимит памяти**: 500 MB/процесс
|
||||
@@ -1,186 +0,0 @@
|
||||
# 🚀 Быстрый старт PM2
|
||||
|
||||
## Запуск Backend в 4 экземплярах
|
||||
|
||||
### Через npm scripts (рекомендуется):
|
||||
|
||||
```bash
|
||||
# 1. Сборка проекта
|
||||
npm run build
|
||||
|
||||
# 2. Запуск PM2
|
||||
npm run pm2:start
|
||||
|
||||
# 3. Проверка статуса
|
||||
npm run pm2:status
|
||||
```
|
||||
|
||||
### Через скрипты:
|
||||
|
||||
```bash
|
||||
# Дать права на выполнение (только один раз)
|
||||
chmod +x start-pm2.sh restart-pm2.sh stop-pm2.sh
|
||||
|
||||
# Запуск
|
||||
./start-pm2.sh
|
||||
|
||||
# Перезапуск
|
||||
./restart-pm2.sh
|
||||
|
||||
# Перезапуск с пересборкой
|
||||
./restart-pm2.sh --build
|
||||
|
||||
# Перезапуск с обновлением из Git
|
||||
./restart-pm2.sh --update
|
||||
|
||||
# Остановка
|
||||
./stop-pm2.sh
|
||||
```
|
||||
|
||||
### Через PM2 напрямую:
|
||||
|
||||
```bash
|
||||
# Запуск
|
||||
pm2 start ecosystem.config.js --env production
|
||||
|
||||
# Сохранение конфигурации
|
||||
pm2 save
|
||||
|
||||
# Настройка автозапуска
|
||||
pm2 startup
|
||||
# Выполните команду, которую выведет pm2 startup
|
||||
```
|
||||
|
||||
## ⚙️ Настройка автозапуска
|
||||
|
||||
Чтобы backend автоматически запускался при перезагрузке сервера:
|
||||
|
||||
```bash
|
||||
# 1. Запустить процесс
|
||||
npm run pm2:start
|
||||
|
||||
# 2. Настроить автозапуск
|
||||
pm2 startup
|
||||
|
||||
# 3. Выполнить команду, которую выведет pm2 startup
|
||||
# Например:
|
||||
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u root --hp /root
|
||||
|
||||
# 4. Сохранить текущую конфигурацию
|
||||
pm2 save
|
||||
```
|
||||
|
||||
## 📊 Мониторинг
|
||||
|
||||
```bash
|
||||
# Просмотр логов
|
||||
npm run pm2:logs
|
||||
|
||||
# Интерактивный мониторинг
|
||||
npm run pm2:monit
|
||||
|
||||
# Статус всех процессов
|
||||
npm run pm2:status
|
||||
|
||||
# Детальная информация
|
||||
pm2 show ospab-backend
|
||||
```
|
||||
|
||||
## 🔄 Обновление кода
|
||||
|
||||
```bash
|
||||
# Вариант 1: Вручную
|
||||
git pull origin main
|
||||
npm install
|
||||
npm run build
|
||||
npm run pm2:restart
|
||||
|
||||
# Вариант 2: Через скрипт
|
||||
./restart-pm2.sh --update
|
||||
```
|
||||
|
||||
## 🛑 Остановка
|
||||
|
||||
```bash
|
||||
# Через npm
|
||||
npm run pm2:stop
|
||||
|
||||
# Через скрипт
|
||||
./stop-pm2.sh
|
||||
|
||||
# Напрямую
|
||||
pm2 stop ospab-backend
|
||||
pm2 delete ospab-backend
|
||||
pm2 save
|
||||
```
|
||||
|
||||
## 📝 Полезные команды
|
||||
|
||||
```bash
|
||||
# Логи в реальном времени
|
||||
pm2 logs ospab-backend --lines 100
|
||||
|
||||
# Очистка логов
|
||||
pm2 flush
|
||||
|
||||
# Перезапуск без даунтайма
|
||||
pm2 reload ospab-backend
|
||||
|
||||
# Обновление PM2
|
||||
npm install -g pm2@latest
|
||||
pm2 update
|
||||
|
||||
# Резервная копия конфигурации
|
||||
pm2 save --force
|
||||
```
|
||||
|
||||
## 🔍 Проверка работы
|
||||
|
||||
После запуска проверьте:
|
||||
|
||||
```bash
|
||||
# 1. Статус процессов (должно быть 4 инстанса "online")
|
||||
pm2 list
|
||||
|
||||
# 2. Backend доступен
|
||||
curl http://localhost:5000
|
||||
|
||||
# 3. Логи без ошибок
|
||||
pm2 logs ospab-backend --lines 50
|
||||
```
|
||||
|
||||
## ⚠️ Устранение проблем
|
||||
|
||||
### PM2 не запускается
|
||||
|
||||
```bash
|
||||
# Проверить версию Node.js
|
||||
node -v
|
||||
|
||||
# Переустановить PM2
|
||||
npm install -g pm2@latest
|
||||
|
||||
# Удалить старую конфигурацию
|
||||
pm2 kill
|
||||
rm -rf ~/.pm2
|
||||
|
||||
# Запустить заново
|
||||
npm run pm2:start
|
||||
```
|
||||
|
||||
### Процессы крашатся
|
||||
|
||||
```bash
|
||||
# Посмотреть ошибки
|
||||
pm2 logs ospab-backend --err
|
||||
|
||||
# Увеличить лимит памяти в ecosystem.config.js
|
||||
# max_memory_restart: '1G'
|
||||
|
||||
# Уменьшить количество инстансов
|
||||
# instances: 2
|
||||
```
|
||||
|
||||
## 📚 Подробная документация
|
||||
|
||||
См. [PM2_SETUP.md](./PM2_SETUP.md) для детальной информации.
|
||||
@@ -1,257 +0,0 @@
|
||||
# Настройка PM2 для Backend
|
||||
|
||||
## 📦 Установка PM2 (если ещё не установлен)
|
||||
|
||||
```bash
|
||||
# Глобальная установка PM2
|
||||
npm install -g pm2
|
||||
|
||||
# Проверка версии
|
||||
pm2 -v
|
||||
```
|
||||
|
||||
## 🚀 Запуск Backend в 4 экземплярах
|
||||
|
||||
### Шаг 1: Сборка проекта
|
||||
|
||||
```bash
|
||||
cd /var/www/ospab-host/backend
|
||||
# или локально:
|
||||
cd backend
|
||||
|
||||
# Установка зависимостей (если нужно)
|
||||
npm install
|
||||
|
||||
# Компиляция TypeScript
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Шаг 2: Создание папки для логов
|
||||
|
||||
```bash
|
||||
mkdir -p logs
|
||||
```
|
||||
|
||||
### Шаг 3: Запуск с помощью PM2
|
||||
|
||||
```bash
|
||||
# Запуск 4 экземпляров согласно ecosystem.config.js
|
||||
pm2 start ecosystem.config.js --env production
|
||||
|
||||
# Или напрямую (без конфига):
|
||||
pm2 start dist/src/index.js -i 4 --name ospab-backend
|
||||
```
|
||||
|
||||
### Шаг 4: Сохранение конфигурации для автозапуска
|
||||
|
||||
```bash
|
||||
# Сохранить текущий список процессов
|
||||
pm2 save
|
||||
|
||||
# Настроить автозапуск при перезагрузке сервера
|
||||
pm2 startup
|
||||
|
||||
# Выполните команду, которую выведет pm2 startup
|
||||
# Обычно это что-то вроде:
|
||||
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u root --hp /root
|
||||
```
|
||||
|
||||
## 📊 Управление процессами
|
||||
|
||||
### Просмотр статуса
|
||||
|
||||
```bash
|
||||
# Список всех процессов
|
||||
pm2 list
|
||||
|
||||
# Детальная информация о процессе
|
||||
pm2 show ospab-backend
|
||||
|
||||
# Мониторинг в реальном времени
|
||||
pm2 monit
|
||||
```
|
||||
|
||||
### Логи
|
||||
|
||||
```bash
|
||||
# Все логи
|
||||
pm2 logs
|
||||
|
||||
# Логи конкретного процесса
|
||||
pm2 logs ospab-backend
|
||||
|
||||
# Последние 100 строк
|
||||
pm2 logs ospab-backend --lines 100
|
||||
|
||||
# Очистка логов
|
||||
pm2 flush
|
||||
```
|
||||
|
||||
### Перезапуск
|
||||
|
||||
```bash
|
||||
# Перезапуск без даунтайма (рекомендуется)
|
||||
pm2 reload ospab-backend
|
||||
|
||||
# Полный перезапуск (с кратковременным даунтаймом)
|
||||
pm2 restart ospab-backend
|
||||
|
||||
# Остановка
|
||||
pm2 stop ospab-backend
|
||||
|
||||
# Удаление из PM2
|
||||
pm2 delete ospab-backend
|
||||
```
|
||||
|
||||
## 🔧 Обновление кода (деплой)
|
||||
|
||||
### Вариант 1: Автоматический деплой через PM2
|
||||
|
||||
```bash
|
||||
# Из корня проекта
|
||||
pm2 deploy ecosystem.config.js production
|
||||
```
|
||||
|
||||
### Вариант 2: Ручной деплой
|
||||
|
||||
```bash
|
||||
cd /var/www/ospab-host
|
||||
|
||||
# Обновление кода
|
||||
git pull origin main
|
||||
|
||||
# Переход в backend
|
||||
cd backend
|
||||
|
||||
# Установка зависимостей
|
||||
npm install
|
||||
|
||||
# Сборка
|
||||
npm run build
|
||||
|
||||
# Перезапуск без даунтайма
|
||||
pm2 reload ospab-backend
|
||||
|
||||
# Сохранение конфигурации
|
||||
pm2 save
|
||||
```
|
||||
|
||||
## 📈 Мониторинг и отладка
|
||||
|
||||
### Проверка памяти и CPU
|
||||
|
||||
```bash
|
||||
pm2 monit
|
||||
```
|
||||
|
||||
### Веб-интерфейс (опционально)
|
||||
|
||||
```bash
|
||||
# Установка PM2 Plus (бесплатно для мониторинга)
|
||||
pm2 link <secret_key> <public_key>
|
||||
|
||||
# Или просто веб-дашборд
|
||||
pm2 web
|
||||
# Откройте http://localhost:9615
|
||||
```
|
||||
|
||||
## ⚙️ Текущая конфигурация
|
||||
|
||||
- **Экземпляры**: 4 процесса в кластерном режиме
|
||||
- **Порт**: 5000 (балансировка внутри PM2)
|
||||
- **Автоперезапуск**: Да
|
||||
- **Лимит памяти**: 500 MB на процесс
|
||||
- **Логи**: `./logs/pm2-error.log` и `./logs/pm2-out.log`
|
||||
|
||||
## 🔍 Проверка автозапуска
|
||||
|
||||
После перезагрузки сервера:
|
||||
|
||||
```bash
|
||||
# Проверить, что PM2 запустился
|
||||
pm2 list
|
||||
|
||||
# Должен показать 4 экземпляра ospab-backend в статусе "online"
|
||||
```
|
||||
|
||||
## 🛠️ Устранение проблем
|
||||
|
||||
### PM2 не запускается при загрузке
|
||||
|
||||
```bash
|
||||
# Удалить старую конфигурацию
|
||||
pm2 unstartup
|
||||
|
||||
# Создать новую
|
||||
pm2 startup
|
||||
# Выполните команду, которую выведет
|
||||
|
||||
# Сохранить
|
||||
pm2 save
|
||||
```
|
||||
|
||||
### Процессы крашатся
|
||||
|
||||
```bash
|
||||
# Проверить логи ошибок
|
||||
pm2 logs ospab-backend --err
|
||||
|
||||
# Увеличить лимит памяти в ecosystem.config.js
|
||||
# max_memory_restart: '1G'
|
||||
|
||||
# Перезапустить
|
||||
pm2 reload ecosystem.config.js
|
||||
```
|
||||
|
||||
### Высокая нагрузка на CPU
|
||||
|
||||
```bash
|
||||
# Уменьшить количество экземпляров
|
||||
# В ecosystem.config.js:
|
||||
instances: 2
|
||||
|
||||
# Перезапустить
|
||||
pm2 reload ecosystem.config.js
|
||||
```
|
||||
|
||||
## 📝 Полезные команды
|
||||
|
||||
```bash
|
||||
# Обновить PM2 до последней версии
|
||||
npm install -g pm2@latest
|
||||
pm2 update
|
||||
|
||||
# Резервная копия конфигурации PM2
|
||||
pm2 save --force
|
||||
|
||||
# Информация о системе
|
||||
pm2 info ospab-backend
|
||||
|
||||
# Метрики производительности
|
||||
pm2 describe ospab-backend
|
||||
```
|
||||
|
||||
## 🎯 Быстрый старт (TL;DR)
|
||||
|
||||
```bash
|
||||
# 1. Перейти в папку backend
|
||||
cd backend
|
||||
|
||||
# 2. Собрать проект
|
||||
npm run build
|
||||
|
||||
# 3. Создать папку логов
|
||||
mkdir -p logs
|
||||
|
||||
# 4. Запустить PM2
|
||||
pm2 start ecosystem.config.js --env production
|
||||
|
||||
# 5. Сохранить и настроить автозапуск
|
||||
pm2 save
|
||||
pm2 startup
|
||||
|
||||
# 6. Проверить статус
|
||||
pm2 list
|
||||
```
|
||||
|
||||
Готово! Backend запущен в 4 экземплярах и будет автоматически запускаться при перезагрузке сервера. 🚀
|
||||
@@ -1,65 +0,0 @@
|
||||
# Решение проблемы Foreign Key при удалении тарифов
|
||||
|
||||
## Проблема
|
||||
При попытке удалить тариф через Prisma Studio появляется ошибка:
|
||||
```
|
||||
Foreign key constraint violated on the fields: (`tariffId`)
|
||||
```
|
||||
|
||||
## Причина
|
||||
Тариф используется серверами. MySQL не позволяет удалить тариф, если на него ссылаются записи в таблице `server`.
|
||||
|
||||
## Решение
|
||||
|
||||
### Способ 1: Безопасный (рекомендуется)
|
||||
Удаляет только неиспользуемые тарифы, сохраняет серверы.
|
||||
|
||||
```bash
|
||||
mysql -u root -p ospabhost < backend/prisma/safe_tariff_migration.sql
|
||||
```
|
||||
|
||||
### Способ 2: Полная очистка (только для dev!)
|
||||
Удаляет ВСЕ серверы и тарифы.
|
||||
|
||||
```bash
|
||||
# Сначала бэкап!
|
||||
mysqldump -u root -p ospabhost > backup.sql
|
||||
|
||||
# Потом очистка
|
||||
mysql -u root -p ospabhost < backend/prisma/clean_slate_migration.sql
|
||||
```
|
||||
|
||||
### Способ 3: Ручное удаление через SQL
|
||||
|
||||
```sql
|
||||
-- 1. Найти тарифы без серверов
|
||||
SELECT t.id, t.name, COUNT(s.id) as servers
|
||||
FROM tariff t
|
||||
LEFT JOIN server s ON s.tariffId = t.id
|
||||
GROUP BY t.id
|
||||
HAVING servers = 0;
|
||||
|
||||
-- 2. Удалить только неиспользуемые
|
||||
DELETE FROM tariff WHERE id IN (
|
||||
SELECT id FROM (
|
||||
SELECT t.id FROM tariff t
|
||||
LEFT JOIN server s ON s.tariffId = t.id
|
||||
GROUP BY t.id
|
||||
HAVING COUNT(s.id) = 0
|
||||
) as unused
|
||||
);
|
||||
|
||||
-- 3. Добавить категорию
|
||||
ALTER TABLE tariff ADD COLUMN category VARCHAR(50) NOT NULL DEFAULT 'vps';
|
||||
|
||||
-- 4. Добавить новые тарифы (см. safe_tariff_migration.sql)
|
||||
```
|
||||
|
||||
## Перезапуск backend
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
npm start
|
||||
```
|
||||
|
||||
Готово! 🎉
|
||||
@@ -1,149 +0,0 @@
|
||||
# Решение проблемы 501 "Method not implemented"
|
||||
|
||||
## Проблема
|
||||
|
||||
При смене root-пароля через Proxmox API получали ошибку:
|
||||
```
|
||||
AxiosError: Request failed with status code 501
|
||||
statusMessage: "Method 'POST /nodes/sv1/lxc/105/config' not implemented"
|
||||
```
|
||||
|
||||
## Причина
|
||||
|
||||
Proxmox API **не поддерживает POST** для изменения конфигурации контейнера.
|
||||
Правильный метод - **PUT**.
|
||||
|
||||
## Решение
|
||||
|
||||
### Было (неправильно):
|
||||
```typescript
|
||||
const response = await axios.post(
|
||||
`${PROXMOX_API_URL}/nodes/${PROXMOX_NODE}/lxc/${vmid}/config`,
|
||||
`password=${encodeURIComponent(newPassword)}`,
|
||||
...
|
||||
);
|
||||
```
|
||||
|
||||
### Стало (правильно):
|
||||
```typescript
|
||||
const response = await axios.put(
|
||||
`${PROXMOX_API_URL}/nodes/${PROXMOX_NODE}/lxc/${vmid}/config`,
|
||||
`password=${encodeURIComponent(newPassword)}`,
|
||||
...
|
||||
);
|
||||
```
|
||||
|
||||
## Правильные HTTP методы для Proxmox API
|
||||
|
||||
### LXC Container Config (`/nodes/{node}/lxc/{vmid}/config`)
|
||||
- `GET` - получить конфигурацию
|
||||
- `PUT` - **изменить конфигурацию** (в т.ч. пароль)
|
||||
- ❌ `POST` - не поддерживается
|
||||
|
||||
### LXC Container Status (`/nodes/{node}/lxc/{vmid}/status/{action}`)
|
||||
- `POST` - start/stop/restart/shutdown
|
||||
|
||||
### LXC Container Create (`/nodes/{node}/lxc`)
|
||||
- `POST` - создать новый контейнер
|
||||
|
||||
## Документация Proxmox VE API
|
||||
|
||||
Официальная документация: https://pve.proxmox.com/pve-docs/api-viewer/
|
||||
|
||||
Основные правила:
|
||||
1. **GET** - чтение данных
|
||||
2. **POST** - создание ресурсов, выполнение действий (start/stop)
|
||||
3. **PUT** - изменение существующих ресурсов
|
||||
4. **DELETE** - удаление ресурсов
|
||||
|
||||
## Тестирование
|
||||
|
||||
### Через curl:
|
||||
```bash
|
||||
# Получить конфигурацию (GET)
|
||||
curl -k -X GET \
|
||||
-H "Authorization: PVEAPIToken=user@pam!token=secret" \
|
||||
https://proxmox:8006/api2/json/nodes/nodename/lxc/100/config
|
||||
|
||||
# Изменить пароль (PUT)
|
||||
curl -k -X PUT \
|
||||
-H "Authorization: PVEAPIToken=user@pam!token=secret" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "password=NewPassword123" \
|
||||
https://proxmox:8006/api2/json/nodes/nodename/lxc/100/config
|
||||
```
|
||||
|
||||
### Через веб-интерфейс:
|
||||
1. Откройте панель управления сервером
|
||||
2. Вкладка "Настройки"
|
||||
3. Нажмите "Сменить root-пароль"
|
||||
4. Проверьте логи: `pm2 logs ospab-backend`
|
||||
|
||||
## Проверка прав API токена
|
||||
|
||||
Убедитесь, что API токен имеет права:
|
||||
```bash
|
||||
# В Proxmox WebUI
|
||||
# Datacenter → Permissions → API Tokens
|
||||
# Проверьте права токена:
|
||||
# - VM.Config.* (для изменения конфигурации)
|
||||
# - VM.PowerMgmt (для start/stop)
|
||||
```
|
||||
|
||||
Или через командную строку:
|
||||
```bash
|
||||
pveum user token permissions api-user@pve sv1-api-user
|
||||
```
|
||||
|
||||
## Fallback через SSH
|
||||
|
||||
Если API не работает, система автоматически использует SSH:
|
||||
```bash
|
||||
ssh root@proxmox "pct set {vmid} --password 'новый_пароль'"
|
||||
```
|
||||
|
||||
Для этого нужно:
|
||||
1. Настроить SSH ключи:
|
||||
```bash
|
||||
ssh-keygen -t rsa -b 4096
|
||||
ssh-copy-id root@proxmox_ip
|
||||
```
|
||||
|
||||
2. Проверить доступ:
|
||||
```bash
|
||||
ssh root@proxmox_ip "pct list"
|
||||
```
|
||||
|
||||
## Деплой исправления
|
||||
|
||||
```bash
|
||||
# На сервере
|
||||
cd /var/www/ospab-host/backend
|
||||
git pull
|
||||
npm run build
|
||||
pm2 restart ospab-backend
|
||||
|
||||
# Проверка логов
|
||||
pm2 logs ospab-backend --lines 50
|
||||
```
|
||||
|
||||
## Ожидаемые логи при успехе
|
||||
|
||||
```
|
||||
✅ Пароль успешно изменён для контейнера 105
|
||||
✅ Пароль успешно обновлён для сервера #17 (VMID: 105)
|
||||
```
|
||||
|
||||
## Ожидаемые логи при ошибке
|
||||
|
||||
```
|
||||
❌ Ошибка смены пароля через API: ...
|
||||
⚠️ Пробуем через SSH...
|
||||
✅ Пароль изменён через SSH для контейнера 105
|
||||
```
|
||||
|
||||
## Дополнительные ресурсы
|
||||
|
||||
- [Proxmox VE API Documentation](https://pve.proxmox.com/pve-docs/api-viewer/)
|
||||
- [Proxmox VE Administration Guide](https://pve.proxmox.com/pve-docs/pve-admin-guide.html)
|
||||
- [pct command reference](https://pve.proxmox.com/pve-docs/pct.1.html)
|
||||
@@ -1,144 +0,0 @@
|
||||
# Простые команды для создания нагрузки на сервер
|
||||
# Выполняйте их в консоли вашего LXC контейнера через noVNC или SSH
|
||||
|
||||
## 1. БЫСТРЫЙ ТЕСТ (без установки дополнительных пакетов)
|
||||
|
||||
### CPU нагрузка (запустить в фоне)
|
||||
# Создаёт 100% нагрузку на все ядра на 2 минуты
|
||||
yes > /dev/null &
|
||||
yes > /dev/null &
|
||||
yes > /dev/null &
|
||||
yes > /dev/null &
|
||||
|
||||
# Остановить через 2 минуты:
|
||||
# killall yes
|
||||
|
||||
|
||||
### Memory нагрузка
|
||||
# Заполнить 500MB оперативки
|
||||
cat <( </dev/zero head -c 500m) <(sleep 120) | tail &
|
||||
|
||||
# Для 1GB используйте:
|
||||
# cat <( </dev/zero head -c 1000m) <(sleep 120) | tail &
|
||||
|
||||
|
||||
### Disk I/O нагрузка
|
||||
# Создать файл 1GB и записать его несколько раз
|
||||
dd if=/dev/zero of=/tmp/testfile bs=1M count=1000 oflag=direct &
|
||||
|
||||
# Удалить после теста:
|
||||
# rm /tmp/testfile
|
||||
|
||||
|
||||
### Network нагрузка
|
||||
# Скачать большой файл
|
||||
wget -O /dev/null http://speedtest.tele2.net/100MB.zip &
|
||||
|
||||
# Или создать сетевой трафик:
|
||||
# ping -f 8.8.8.8 -c 10000 &
|
||||
|
||||
|
||||
|
||||
## 2. С УСТАНОВКОЙ STRESS-NG (рекомендуется)
|
||||
|
||||
# Установить stress-ng (один раз)
|
||||
apt-get update && apt-get install -y stress-ng
|
||||
|
||||
### Комплексный тест (5 минут)
|
||||
# CPU 50%, Memory 50%, Disk I/O
|
||||
stress-ng --cpu 2 --cpu-load 50 --vm 1 --vm-bytes 512M --hdd 1 --timeout 300s
|
||||
|
||||
### Только CPU (80% нагрузка, 3 минуты)
|
||||
stress-ng --cpu 4 --cpu-load 80 --timeout 180s
|
||||
|
||||
### Только Memory (заполнить 70%, 3 минуты)
|
||||
stress-ng --vm 2 --vm-bytes 70% --timeout 180s
|
||||
|
||||
### Только Disk I/O (3 минуты)
|
||||
stress-ng --hdd 4 --timeout 180s
|
||||
|
||||
|
||||
|
||||
## 3. PYTHON СКРИПТ (если Python установлен)
|
||||
|
||||
# Создать файл test_load.py:
|
||||
cat > /tmp/test_load.py << 'EOF'
|
||||
import time
|
||||
import threading
|
||||
|
||||
def cpu_load():
|
||||
"""CPU нагрузка"""
|
||||
end_time = time.time() + 180 # 3 минуты
|
||||
while time.time() < end_time:
|
||||
[x**2 for x in range(10000)]
|
||||
|
||||
def memory_load():
|
||||
"""Memory нагрузка"""
|
||||
data = []
|
||||
for i in range(100):
|
||||
data.append(' ' * 10000000) # ~10MB каждый
|
||||
time.sleep(1)
|
||||
|
||||
# Запустить в потоках
|
||||
threads = []
|
||||
for i in range(4): # 4 потока для CPU
|
||||
t = threading.Thread(target=cpu_load)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
# Memory нагрузка
|
||||
m = threading.Thread(target=memory_load)
|
||||
m.start()
|
||||
threads.append(m)
|
||||
|
||||
# Ждать завершения
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
print("Test completed!")
|
||||
EOF
|
||||
|
||||
# Запустить:
|
||||
python3 /tmp/test_load.py &
|
||||
|
||||
|
||||
|
||||
## 4. МОНИТОРИНГ НАГРУЗКИ
|
||||
|
||||
# Установить htop для визуального мониторинга
|
||||
apt-get install -y htop
|
||||
|
||||
# Запустить htop
|
||||
htop
|
||||
|
||||
# Или использовать стандартные команды:
|
||||
top # CPU и Memory
|
||||
iostat -x 1 # Disk I/O (нужно установить: apt install sysstat)
|
||||
free -h # Memory
|
||||
uptime # Load average
|
||||
|
||||
|
||||
|
||||
## 5. ОСТАНОВИТЬ ВСЕ ТЕСТЫ
|
||||
|
||||
# Остановить все процессы нагрузки
|
||||
killall stress-ng yes dd wget python3
|
||||
|
||||
# Очистить временные файлы
|
||||
rm -f /tmp/testfile /tmp/test_load.py
|
||||
|
||||
|
||||
|
||||
## КАК ПРОВЕРИТЬ РЕЗУЛЬТАТЫ
|
||||
|
||||
1. Откройте панель управления сервером в браузере
|
||||
2. Перейдите на вкладку "Мониторинг"
|
||||
3. Выберите период "1h" или "6h"
|
||||
4. Вы увидите графики:
|
||||
- CPU usage (оранжевый график)
|
||||
- Memory usage (синий график)
|
||||
- Disk usage (зеленый график)
|
||||
- Network In/Out (фиолетовый график)
|
||||
|
||||
5. Обновите страницу через 1-2 минуты после запуска теста
|
||||
6. Используйте кнопки периодов (1h, 6h, 24h) для изменения масштаба
|
||||
@@ -1,168 +0,0 @@
|
||||
# Тестирование смены root-пароля
|
||||
|
||||
## Как это работает
|
||||
|
||||
Система использует **3 метода** смены пароля с автоматическим fallback:
|
||||
|
||||
### Метод 1: Proxmox API (основной)
|
||||
```
|
||||
POST /api/nodes/{node}/lxc/{vmid}/config
|
||||
Body: password=новый_пароль
|
||||
```
|
||||
- Самый быстрый и надёжный
|
||||
- Работает через API токен
|
||||
- Не требует SSH доступа
|
||||
|
||||
### Метод 2: SSH + pct set (fallback)
|
||||
```bash
|
||||
ssh root@proxmox "pct set {vmid} --password 'новый_пароль'"
|
||||
```
|
||||
- Запасной вариант если API не работает
|
||||
- Требует SSH доступа от backend к Proxmox
|
||||
- Настраивается через `.env`
|
||||
|
||||
### Метод 3: Exec внутри контейнера (последний fallback)
|
||||
```
|
||||
POST /api/nodes/{node}/lxc/{vmid}/exec
|
||||
Body: { command: ["bash", "-c", "echo 'root:пароль' | chpasswd"] }
|
||||
```
|
||||
- Выполняет команду внутри контейнера
|
||||
- Работает если контейнер запущен
|
||||
- Не требует SSH
|
||||
|
||||
## Как протестировать
|
||||
|
||||
### 1. Через веб-интерфейс
|
||||
|
||||
1. Откройте панель управления сервером
|
||||
2. Перейдите на вкладку "Настройки"
|
||||
3. Нажмите кнопку "Сменить root-пароль"
|
||||
4. Подтвердите действие
|
||||
5. Новый пароль появится на вкладке "Обзор"
|
||||
|
||||
### 2. Через API (curl)
|
||||
|
||||
```bash
|
||||
# Получить токен (замените email и password)
|
||||
TOKEN=$(curl -X POST https://ospab.host:5000/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"user@example.com","password":"yourpassword"}' \
|
||||
| jq -r '.token')
|
||||
|
||||
# Сменить пароль (замените {id} на ID сервера)
|
||||
curl -X POST https://ospab.host:5000/api/server/{id}/password \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
| jq
|
||||
```
|
||||
|
||||
### 3. Проверка нового пароля
|
||||
|
||||
#### Через noVNC консоль:
|
||||
1. Откройте консоль сервера
|
||||
2. Войдите как `root`
|
||||
3. Введите новый пароль из панели
|
||||
|
||||
#### Через SSH:
|
||||
```bash
|
||||
ssh root@IP_СЕРВЕРА
|
||||
# Введите новый пароль
|
||||
```
|
||||
|
||||
## Логи и отладка
|
||||
|
||||
### Backend логи
|
||||
```bash
|
||||
# Просмотр логов в реальном времени
|
||||
pm2 logs ospab-backend
|
||||
|
||||
# Или если запущен напрямую
|
||||
tail -f /var/www/ospab-host/backend/logs/pm2-out.log
|
||||
```
|
||||
|
||||
### Что искать в логах:
|
||||
|
||||
**Успешная смена:**
|
||||
```
|
||||
✅ Пароль успешно изменён для контейнера 123
|
||||
✅ Пароль успешно обновлён для сервера #5 (VMID: 123)
|
||||
```
|
||||
|
||||
**Ошибки:**
|
||||
```
|
||||
❌ Ошибка смены пароля через API: ...
|
||||
⚠️ Основной метод не сработал, пробуем через exec...
|
||||
❌ Ошибка смены пароля через SSH: ...
|
||||
```
|
||||
|
||||
## Возможные проблемы
|
||||
|
||||
### Проблема 1: "Не удалось изменить пароль"
|
||||
|
||||
**Причина:** Нет доступа к Proxmox API или SSH
|
||||
|
||||
**Решение:**
|
||||
```bash
|
||||
# Проверьте переменные окружения
|
||||
cat /var/www/ospab-host/backend/.env | grep PROXMOX
|
||||
|
||||
# Должны быть установлены:
|
||||
PROXMOX_API_URL=https://IP:8006/api2/json
|
||||
PROXMOX_TOKEN_ID=root@pam!your-token-name
|
||||
PROXMOX_TOKEN_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
PROXMOX_NODE=proxmox
|
||||
```
|
||||
|
||||
### Проблема 2: SSH метод не работает
|
||||
|
||||
**Причина:** Нет SSH ключей или доступа
|
||||
|
||||
**Решение:**
|
||||
```bash
|
||||
# Настройте SSH ключи (на сервере с backend)
|
||||
ssh-keygen -t rsa -b 4096
|
||||
ssh-copy-id root@PROXMOX_IP
|
||||
|
||||
# Проверьте доступ
|
||||
ssh root@PROXMOX_IP "pct list"
|
||||
```
|
||||
|
||||
### Проблема 3: Контейнер не запущен
|
||||
|
||||
**Причина:** Exec метод работает только для запущенных контейнеров
|
||||
|
||||
**Решение:**
|
||||
1. Запустите контейнер
|
||||
2. Подождите 30 секунд
|
||||
3. Попробуйте снова сменить пароль
|
||||
|
||||
## Автоматическое скрытие пароля
|
||||
|
||||
Пароль автоматически скрывается через **30 минут** после:
|
||||
- Создания сервера
|
||||
- Смены пароля
|
||||
|
||||
### Как проверить:
|
||||
1. Создайте сервер или смените пароль
|
||||
2. Пароль виден на вкладке "Обзор"
|
||||
3. Через 30 минут пароль будет заменён на "••••••••"
|
||||
4. Кнопка "Показать пароль" перестанет работать
|
||||
|
||||
### Как показать снова:
|
||||
Нажмите "Сменить root-пароль" - будет сгенерирован новый пароль и снова виден 30 минут.
|
||||
|
||||
## Частые вопросы
|
||||
|
||||
**Q: Как часто можно менять пароль?**
|
||||
A: Без ограничений. Каждая смена генерирует новый случайный пароль.
|
||||
|
||||
**Q: Можно ли задать свой пароль?**
|
||||
A: Нет, система генерирует случайный пароль 16 символов для безопасности.
|
||||
|
||||
**Q: Пароль сохраняется в базе?**
|
||||
A: Да, в зашифрованном виде в таблице `server.rootPassword`.
|
||||
|
||||
**Q: Что если я потерял пароль?**
|
||||
A: Просто нажмите "Сменить root-пароль" - будет сгенерирован новый.
|
||||
|
||||
**Q: Работает ли для KVM виртуалок?**
|
||||
A: Эта реализация для LXC контейнеров. Для KVM нужна доработка.
|
||||
Reference in New Issue
Block a user