Update files

This commit is contained in:
glpshchn 2025-11-21 04:44:54 +03:00
parent 83fb27bee8
commit fb12c0626b
5 changed files with 698 additions and 23 deletions

323
MINIO_NGINX_SETUP.md Normal file
View File

@ -0,0 +1,323 @@
# 🌐 Настройка Nginx для MinIO с доменом
## Обзор
Эта инструкция поможет настроить Nginx reverse proxy для MinIO с SSL сертификатами.
**Результат:**
- MinIO API: `https://minio.glpshchn.ru`
- MinIO Console: `https://admin.minio.glpshchn.ru`
## Предварительные требования
1. ✅ MinIO запущен на порту 9000 (API) и 9001 (Console)
2. ✅ DNS записи настроены:
```
minio.glpshchn.ru A 103.80.87.247
admin.minio.glpshchn.ru A 103.80.87.247
```
3. ✅ Порты 80 и 443 открыты в firewall
## Быстрая установка (автоматически)
### Шаг 1: Скопируйте файлы на сервер
```bash
# На вашем компьютере
scp nginx-minio.conf setup-minio-nginx.sh root@103.80.87.247:/root/
# Подключитесь к серверу
ssh root@103.80.87.247
```
### Шаг 2: Отредактируйте email в скрипте
```bash
nano setup-minio-nginx.sh
# Измените строку:
EMAIL="your-email@example.com" # <- Ваш email для Let's Encrypt
```
### Шаг 3: Запустите скрипт
```bash
chmod +x setup-minio-nginx.sh
sudo ./setup-minio-nginx.sh
```
Скрипт автоматически:
- ✅ Установит Nginx и Certbot
- ✅ Получит SSL сертификаты от Let's Encrypt
- ✅ Настроит Nginx конфигурацию
- ✅ Настроит автообновление сертификатов
## Ручная установка
### Шаг 1: Установите Nginx
```bash
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx
```
### Шаг 2: Получите SSL сертификаты
```bash
# Создайте директорию для certbot
sudo mkdir -p /var/www/certbot
# Временный конфиг для получения сертификатов
sudo tee /etc/nginx/sites-available/minio-temp > /dev/null << 'EOF'
server {
listen 80;
server_name minio.glpshchn.ru admin.minio.glpshchn.ru;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
EOF
# Активируйте конфиг
sudo ln -sf /etc/nginx/sites-available/minio-temp /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
# Получите сертификаты
sudo certbot certonly --webroot \
-w /var/www/certbot \
-d minio.glpshchn.ru \
-d admin.minio.glpshchn.ru \
--email your-email@example.com \
--agree-tos \
--non-interactive
```
### Шаг 3: Установите конфигурацию
```bash
# Скопируйте конфиг
sudo cp nginx-minio.conf /etc/nginx/sites-available/minio.glpshchn.ru
# Активируйте
sudo ln -sf /etc/nginx/sites-available/minio.glpshchn.ru /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/minio-temp
# Проверьте и перезагрузите
sudo nginx -t
sudo systemctl reload nginx
```
### Шаг 4: Настройте автообновление SSL
```bash
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
```
## Проверка работы
### 1. Проверьте SSL
```bash
curl https://minio.glpshchn.ru/minio/health/live
# Должен вернуть: пустой ответ (это нормально)
# Проверьте сертификат
echo | openssl s_client -connect minio.glpshchn.ru:443 -servername minio.glpshchn.ru 2>/dev/null | openssl x509 -noout -dates
```
### 2. Проверьте доступ к файлам
```bash
# Загрузите тестовый файл через mc
mc cp test.txt myminio/nakama-media/test.txt
# Проверьте доступность через HTTPS
curl -I https://minio.glpshchn.ru/nakama-media/test.txt
# Должен вернуть: HTTP/2 200
```
### 3. Откройте Console
Откройте в браузере:
```
https://admin.minio.glpshchn.ru
```
Должен открыться веб-интерфейс MinIO.
## Обновите Nakama
### Шаг 1: Обновите .env
```bash
nano .env
# Измените MinIO настройки:
MINIO_ENABLED=true
MINIO_ENDPOINT=minio.glpshchn.ru # <- Теперь домен!
MINIO_PORT=443 # <- HTTPS порт
MINIO_USE_SSL=true # <- Включаем SSL
MINIO_ACCESS_KEY=ваш_ключ
MINIO_SECRET_KEY=ваш_секрет
MINIO_BUCKET=nakama-media
MINIO_PUBLIC_URL=https://minio.glpshchn.ru # <- Публичный URL
MINIO_PUBLIC_BUCKET=true
```
### Шаг 2: Обновите S3 клиент
В `backend/utils/minio.js` - уже настроено автоматически!
Код использует `config.minio.useSSL` для выбора протокола.
### Шаг 3: Перезапустите backend
```bash
docker-compose restart backend
# Проверьте логи
docker-compose logs backend | grep -i minio
```
Должно быть:
```
✅ MinIO успешно подключен
endpoint: minio.glpshchn.ru:443
ssl: true
```
## Устранение проблем
### Ошибка: "SSL certificate problem"
**Причина:** Сертификат не доверенный или истёк.
**Решение:**
```bash
# Обновите сертификаты
sudo certbot renew --force-renewal
sudo systemctl reload nginx
```
### Ошибка: "Connection refused"
**Причина:** MinIO не запущен или порты закрыты.
**Решение:**
```bash
# Проверьте MinIO
curl http://127.0.0.1:9000/minio/health/live
# Проверьте Nginx
sudo nginx -t
sudo systemctl status nginx
# Проверьте firewall
sudo ufw status
```
### Ошибка: "502 Bad Gateway"
**Причина:** Nginx не может подключиться к MinIO.
**Решение:**
```bash
# Проверьте что MinIO слушает на 127.0.0.1:9000
netstat -tulpn | grep 9000
# Проверьте логи Nginx
sudo tail -f /var/log/nginx/minio-error.log
# Проверьте логи MinIO
journalctl -u minio -f
```
### CORS ошибки в браузере
**Причина:** CORS заголовки не настроены.
**Решение:** Конфиг уже содержит все необходимые CORS заголовки.
Если проблема остаётся, проверьте что домен frontend добавлен.
## Мониторинг
### Проверка статуса
```bash
# Nginx
sudo systemctl status nginx
# Certbot timer
sudo systemctl status certbot.timer
# Логи доступа
sudo tail -f /var/log/nginx/minio-access.log
# Логи ошибок
sudo tail -f /var/log/nginx/minio-error.log
```
### Статистика использования
```bash
# Количество запросов за последний час
sudo grep "$(date '+%d/%b/%Y:%H')" /var/log/nginx/minio-access.log | wc -l
# Топ IP адресов
sudo awk '{print $1}' /var/log/nginx/minio-access.log | sort | uniq -c | sort -rn | head -10
```
## Автообновление SSL
Сертификаты обновляются автоматически через systemd timer.
Проверка:
```bash
# Статус таймера
sudo systemctl list-timers certbot.timer
# Тестовое обновление (dry-run)
sudo certbot renew --dry-run
# Ручное обновление (если нужно)
sudo certbot renew
sudo systemctl reload nginx
```
## Бонус: Оптимизация производительности
### Кеширование статических файлов
Добавьте в конфиг Nginx внутри `location /`:
```nginx
# Кеш для изображений
location ~* \.(jpg|jpeg|png|gif|webp)$ {
proxy_pass http://127.0.0.1:9000;
proxy_cache_valid 200 7d;
add_header X-Cache-Status $upstream_cache_status;
expires 7d;
}
```
### Сжатие
```nginx
# В http блоке /etc/nginx/nginx.conf
gzip on;
gzip_vary on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
```
## Итоговые URLs
После настройки:
- **MinIO API:** `https://minio.glpshchn.ru`
- **MinIO Console:** `https://admin.minio.glpshchn.ru`
- **Пример файла:** `https://minio.glpshchn.ru/nakama-media/posts/example.jpg`
Теперь все изображения будут загружаться через HTTPS! 🎉

View File

@ -268,15 +268,32 @@ router.delete('/posts/:id', authenticateModeration, requireModerationAccess, asy
return res.status(404).json({ error: 'Пост не найден' });
}
// Удалить локальные изображения
if (post.images && post.images.length) {
post.images.forEach((imagePath) => {
if (!imagePath.startsWith('/uploads')) return;
const fullPath = path.join(__dirname, '..', imagePath);
if (fs.existsSync(fullPath)) {
fs.unlink(fullPath, () => {});
// Удалить изображения из MinIO
try {
const { deleteFiles } = require('../utils/minio');
const filesToDelete = [];
if (post.images && post.images.length > 0) {
post.images.forEach(imageUrl => {
// Извлекаем имя файла из URL
const match = imageUrl.match(/nakama-media\/(.+)$/);
if (match) {
filesToDelete.push(match[1]);
}
});
} else if (post.imageUrl) {
const match = post.imageUrl.match(/nakama-media\/(.+)$/);
if (match) {
filesToDelete.push(match[1]);
}
});
}
if (filesToDelete.length > 0) {
await deleteFiles(filesToDelete);
console.log(`✅ Удалено ${filesToDelete.length} файлов из MinIO (modApp)`);
}
} catch (error) {
console.error('❌ Ошибка удаления файлов из MinIO:', error);
}
await Post.deleteOne({ _id: post._id });
@ -300,10 +317,16 @@ router.delete('/posts/:id/images/:index', authenticateModeration, requireModerat
post.imageUrl = post.images[0] || null;
await post.save();
if (removed && removed.startsWith('/uploads')) {
const fullPath = path.join(__dirname, '..', removed);
if (fs.existsSync(fullPath)) {
fs.unlink(fullPath, () => {});
// Удалить изображение из MinIO
if (removed) {
try {
const match = removed.match(/nakama-media\/(.+)$/);
if (match) {
await deleteFile(match[1]);
console.log(`✅ Удалено изображение из MinIO: ${match[1]}`);
}
} catch (error) {
console.error('❌ Ошибка удаления изображения из MinIO:', error);
}
}

View File

@ -313,19 +313,33 @@ router.delete('/:id', authenticate, async (req, res) => {
return res.status(403).json({ error: 'Нет прав на удаление' });
}
// Удалить изображения если есть
if (post.images && post.images.length > 0) {
post.images.forEach(imagePath => {
const fullPath = path.join(__dirname, '..', imagePath);
if (fs.existsSync(fullPath)) {
fs.unlinkSync(fullPath);
// Удалить изображения из MinIO
try {
const filesToDelete = [];
if (post.images && post.images.length > 0) {
post.images.forEach(imageUrl => {
// Извлекаем имя файла из URL
// https://minio.glpshchn.ru/nakama-media/posts/123456.jpg -> posts/123456.jpg
const match = imageUrl.match(/nakama-media\/(.+)$/);
if (match) {
filesToDelete.push(match[1]);
}
});
} else if (post.imageUrl) {
const match = post.imageUrl.match(/nakama-media\/(.+)$/);
if (match) {
filesToDelete.push(match[1]);
}
});
} else if (post.imageUrl) {
const imagePath = path.join(__dirname, '..', post.imageUrl);
if (fs.existsSync(imagePath)) {
fs.unlinkSync(imagePath);
}
if (filesToDelete.length > 0) {
await deleteFiles(filesToDelete);
console.log(`✅ Удалено ${filesToDelete.length} файлов из MinIO`);
}
} catch (error) {
console.error('❌ Ошибка удаления файлов из MinIO:', error);
// Продолжаем удаление поста даже если файлы не удалились
}
await Post.findByIdAndDelete(req.params.id);

156
nginx-minio.conf Normal file
View File

@ -0,0 +1,156 @@
# Nginx конфигурация для MinIO
# Сохраните как: /etc/nginx/sites-available/minio.glpshchn.ru
# Перенаправление HTTP -> HTTPS
server {
listen 80;
listen [::]:80;
server_name minio.glpshchn.ru;
# Certbot validation
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Redirect all HTTP to HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
# MinIO API (основной доступ к файлам)
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name minio.glpshchn.ru;
# SSL сертификаты (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/minio.glpshchn.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/minio.glpshchn.ru/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/minio.glpshchn.ru/chain.pem;
# SSL настройки (современные и безопасные)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_stapling_verify on;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
# Увеличенные лимиты для загрузки файлов
client_max_body_size 1000M;
client_body_timeout 300s;
client_header_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
send_timeout 300s;
# Игнорировать заголовки для кеширования от upstream
ignore_invalid_headers off;
# CORS заголовки (для доступа из браузера)
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS, HEAD' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Content-Length, Accept-Encoding, X-Requested-With, Range, Content-Disposition, Content-MD5, X-Amz-Content-Sha256, X-Amz-Date, X-Amz-User-Agent' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range, ETag' always;
add_header 'Access-Control-Max-Age' 1728000 always;
# Обработка preflight запросов
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS, HEAD';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Content-Length, Accept-Encoding, X-Requested-With, Range, Content-Disposition, Content-MD5, X-Amz-Content-Sha256, X-Amz-Date, X-Amz-User-Agent';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
# Логи
access_log /var/log/nginx/minio-access.log;
error_log /var/log/nginx/minio-error.log;
# Проксирование к MinIO API
location / {
proxy_set_header Host $http_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;
proxy_set_header X-NginX-Proxy true;
# Для корректной работы S3 API
proxy_set_header Connection "";
chunked_transfer_encoding off;
# Disable buffering для больших файлов
proxy_buffering off;
proxy_request_buffering off;
# Backend MinIO (порт 9000)
proxy_pass http://127.0.0.1:9000;
# WebSocket поддержка (если используется)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Health check endpoint
location /minio/health/live {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:9000;
}
}
# MinIO Console (опционально, для веб-интерфейса)
# Доступ через admin.minio.glpshchn.ru
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name admin.minio.glpshchn.ru;
# SSL сертификаты
ssl_certificate /etc/letsencrypt/live/admin.minio.glpshchn.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.minio.glpshchn.ru/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/admin.minio.glpshchn.ru/chain.pem;
# SSL настройки
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
# Security headers
add_header Strict-Transport-Security "max-age=31536000" always;
# Увеличенные лимиты
client_max_body_size 1000M;
# Логи
access_log /var/log/nginx/minio-console-access.log;
error_log /var/log/nginx/minio-console-error.log;
# Проксирование к MinIO Console
location / {
proxy_set_header Host $http_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;
# Backend MinIO Console (порт 9001)
proxy_pass http://127.0.0.1:9001;
# WebSocket для real-time updates
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

159
setup-minio-nginx.sh Normal file
View File

@ -0,0 +1,159 @@
#!/bin/bash
# Скрипт для настройки Nginx + SSL для MinIO
set -e
echo "🔧 Настройка Nginx для MinIO"
echo "======================================"
# Проверка root прав
if [[ $EUID -ne 0 ]]; then
echo "❌ Этот скрипт должен быть запущен с правами root (sudo)"
exit 1
fi
# Переменные
DOMAIN="minio.glpshchn.ru"
CONSOLE_DOMAIN="admin.minio.glpshchn.ru"
EMAIL="your-email@example.com" # Измените на ваш email для Let's Encrypt
echo ""
echo "Настройка для доменов:"
echo " API: https://$DOMAIN"
echo " Console: https://$CONSOLE_DOMAIN"
echo ""
# Установка Nginx (если не установлен)
if ! command -v nginx &> /dev/null; then
echo "📦 Установка Nginx..."
apt update
apt install -y nginx
fi
# Установка Certbot (если не установлен)
if ! command -v certbot &> /dev/null; then
echo "📦 Установка Certbot..."
apt install -y certbot python3-certbot-nginx
fi
# Создание директории для certbot
mkdir -p /var/www/certbot
# Временный конфиг для получения сертификатов
echo "📝 Создание временного конфига для получения SSL..."
cat > /etc/nginx/sites-available/minio-temp << 'EOF'
server {
listen 80;
server_name minio.glpshchn.ru admin.minio.glpshchn.ru;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 200 "MinIO setup in progress...";
add_header Content-Type text/plain;
}
}
EOF
# Активация временного конфига
ln -sf /etc/nginx/sites-available/minio-temp /etc/nginx/sites-enabled/minio-temp
# Удаление дефолтного конфига
rm -f /etc/nginx/sites-enabled/default
# Проверка конфигурации
echo "🔍 Проверка конфигурации Nginx..."
nginx -t
# Перезагрузка Nginx
echo "🔄 Перезагрузка Nginx..."
systemctl reload nginx
# Получение SSL сертификатов
echo ""
echo "🔒 Получение SSL сертификатов от Let's Encrypt..."
echo ""
certbot certonly --webroot \
-w /var/www/certbot \
-d $DOMAIN \
-d $CONSOLE_DOMAIN \
--email $EMAIL \
--agree-tos \
--non-interactive
if [ $? -ne 0 ]; then
echo "❌ Ошибка получения SSL сертификата"
echo "Проверьте:"
echo " 1. DNS записи A для $DOMAIN и $CONSOLE_DOMAIN указывают на этот сервер"
echo " 2. Порт 80 открыт в firewall"
echo " 3. Домены доступны из интернета"
exit 1
fi
echo ""
echo "✅ SSL сертификаты получены!"
# Копирование основного конфига
echo "📝 Установка основного конфига..."
cp nginx-minio.conf /etc/nginx/sites-available/minio.glpshchn.ru
# Активация конфига
ln -sf /etc/nginx/sites-available/minio.glpshchn.ru /etc/nginx/sites-enabled/minio.glpshchn.ru
# Удаление временного конфига
rm -f /etc/nginx/sites-enabled/minio-temp
# Проверка конфигурации
echo "🔍 Проверка финальной конфигурации..."
nginx -t
if [ $? -ne 0 ]; then
echo "❌ Ошибка в конфигурации Nginx"
exit 1
fi
# Перезагрузка Nginx
echo "🔄 Перезагрузка Nginx с новой конфигурацией..."
systemctl reload nginx
# Настройка автообновления сертификатов
echo "⏰ Настройка автообновления SSL сертификатов..."
systemctl enable certbot.timer
systemctl start certbot.timer
# Открытие портов в firewall (если используется ufw)
if command -v ufw &> /dev/null; then
echo "🔥 Настройка firewall..."
ufw allow 'Nginx Full'
ufw allow 443/tcp
ufw allow 80/tcp
fi
echo ""
echo "======================================"
echo "✅ Настройка завершена!"
echo ""
echo "MinIO API доступен по адресу:"
echo " https://$DOMAIN"
echo ""
echo "MinIO Console доступен по адресу:"
echo " https://$CONSOLE_DOMAIN"
echo ""
echo "Проверка:"
echo " curl https://$DOMAIN/minio/health/live"
echo ""
echo "Обновите .env в Nakama:"
echo " MINIO_ENDPOINT=$DOMAIN"
echo " MINIO_PORT=443"
echo " MINIO_USE_SSL=true"
echo " MINIO_PUBLIC_URL=https://$DOMAIN"
echo ""
echo "Перезапустите backend:"
echo " docker-compose restart backend"
echo "======================================"