Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# MinIO Credentials
|
||||
MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=change-this-password-please
|
||||
MINIO_BUCKET=course-plat
|
||||
@@ -0,0 +1,157 @@
|
||||
# MinIO + Backup Setup
|
||||
|
||||
Setup completo do MinIO com scripts de backup para VPS e download local.
|
||||
|
||||
## 📁 Estrutura
|
||||
|
||||
```
|
||||
docker/minio/
|
||||
├── docker-compose.yml # Serviço MinIO
|
||||
├── backup-minio.sh # Script de backup (roda no servidor)
|
||||
├── pull-backup.sh # Script para baixar backup (roda no seu PC)
|
||||
└── .env.example # Variáveis de ambiente
|
||||
```
|
||||
|
||||
## 🔒 Segurança
|
||||
|
||||
**Bucket é PRIVADO** por padrão. Arquivos são servidos via proxy da aplicação (`/api/files/...`), o que permite:
|
||||
- Controle de autenticação
|
||||
- Verificação de permissões
|
||||
- Logs de acesso
|
||||
|
||||
## 🚀 Setup Inicial
|
||||
|
||||
### 1. Criar arquivo .env
|
||||
|
||||
```bash
|
||||
cd docker/minio
|
||||
cat > .env << 'EOF'
|
||||
MINIO_ROOT_USER=admin
|
||||
MINIO_ROOT_PASSWORD=sua-senha-forte-aqui
|
||||
MINIO_BUCKET=course-plat
|
||||
EOF
|
||||
```
|
||||
|
||||
### 2. Iniciar MinIO
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 3. Acessar
|
||||
|
||||
- **Console (UI)**: http://seu-servidor:9001
|
||||
- **API**: http://seu-servidor:9000
|
||||
|
||||
## 💾 Backup Automático
|
||||
|
||||
### No Servidor (VPS)
|
||||
|
||||
1. Copiar o script para o servidor:
|
||||
```bash
|
||||
chmod +x backup-minio.sh
|
||||
sudo cp backup-minio.sh /usr/local/bin/
|
||||
```
|
||||
|
||||
2. Testar manualmente:
|
||||
```bash
|
||||
/usr/local/bin/backup-minio.sh
|
||||
```
|
||||
|
||||
3. Adicionar ao crontab (backup todo dia às 2h da manhã):
|
||||
```bash
|
||||
crontab -e
|
||||
# Adicionar linha:
|
||||
0 2 * * * /usr/local/bin/backup-minio.sh >> /var/log/minio-backup.log 2>&1
|
||||
```
|
||||
|
||||
### No Seu PC
|
||||
|
||||
1. Editar `pull-backup.sh` com seus dados:
|
||||
```bash
|
||||
SERVER_USER="seu-usuario"
|
||||
SERVER_HOST="seu-servidor.com"
|
||||
```
|
||||
|
||||
2. Dar permissão e testar:
|
||||
```bash
|
||||
chmod +x pull-backup.sh
|
||||
./pull-backup.sh
|
||||
```
|
||||
|
||||
3. Agendar no crontab do SEU PC (todo dia às 3h):
|
||||
```bash
|
||||
crontab -e
|
||||
# Adicionar linha:
|
||||
0 3 * * * /caminho/para/pull-backup.sh
|
||||
```
|
||||
|
||||
## 🔄 Como Funciona
|
||||
|
||||
```
|
||||
┌─────────────────┐ 02:00 ┌──────────────────┐
|
||||
│ Servidor VPS │ ────────────────▶│ Backup Local │
|
||||
│ (MinIO) │ backup-minio.sh│ (/var/backups/) │
|
||||
└─────────────────┘ └──────────────────┘
|
||||
│
|
||||
│ 03:00
|
||||
│ pull-backup.sh
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Seu PC │
|
||||
│ (Backup final) │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
## 📦 Restaurar Backup
|
||||
|
||||
### No servidor:
|
||||
```bash
|
||||
# Parar MinIO
|
||||
docker compose down
|
||||
|
||||
# Restaurar volume
|
||||
docker run --rm \
|
||||
-v course-plat_minio_data:/data \
|
||||
-v /var/backups/minio:/backup \
|
||||
alpine tar xzf /backup/minio-backup-YYYYMMDD-HHMMSS.tar.gz -C /data
|
||||
|
||||
# Reiniciar
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## ⚠️ Considerações
|
||||
|
||||
| Aspecto | Nota |
|
||||
|---------|------|
|
||||
| **Segurança** | Use chaves SSH para o rsync |
|
||||
| **Backup external** | Considere também mandar para S3/Backblaze |
|
||||
| **Teste** | Teste restaurar pelo menos uma vez |
|
||||
| **Logs** | Verifique `/var/log/minio-backup.log` regularmente |
|
||||
|
||||
## 🔧 Variáveis do backup-minio.sh
|
||||
|
||||
```bash
|
||||
BACKUP_DIR="/var/backups/minio" # Onde salvar no servidor
|
||||
RETENTION_DAYS=7 # Dias para manter backup
|
||||
VOLUME_NAME="course-plat_minio_data" # Nome do volume
|
||||
```
|
||||
|
||||
## 🔧 Variáveis do pull-backup.sh
|
||||
|
||||
```bash
|
||||
SERVER_USER="usuario" # Usuário SSH
|
||||
SERVER_HOST="seu-servidor.com" # Host do servidor
|
||||
SERVER_BACKUP_DIR="/var/backups/minio"
|
||||
LOCAL_BACKUP_DIR="$HOME/backups/minio"
|
||||
KEEP_LOCAL_DAYS=30 # Dias para manter localmente
|
||||
```
|
||||
|
||||
## 🔗 URLs de Arquivos
|
||||
|
||||
| Onde | Formato |
|
||||
|------|---------|
|
||||
| **Banco de dados** | `proxy://iciv/ClassTypes/arquivo.pdf` |
|
||||
| **Front-end** | `/api/files/iciv/ClassTypes/arquivo.pdf` |
|
||||
|
||||
Use `getFileUrl(url)` do `@/app/lib/utils/storage/fileUrl` para converter.
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
# backup-minio.sh - Script de backup do MinIO no servidor
|
||||
# Uso: ./backup-minio.sh
|
||||
# Agendar no crontab: 0 2 * * * /caminho/para/backup-minio.sh
|
||||
|
||||
set -e
|
||||
|
||||
# ============ CONFIGURAÇÃO ============
|
||||
BACKUP_DIR="/var/backups/minio" # Onde salvar os backups no servidor
|
||||
RETENTION_DAYS=7 # Quantos dias manter
|
||||
VOLUME_NAME="course-plat_minio_data" # Nome do volume Docker
|
||||
COMPRESSION="gzip" # gzip ou none
|
||||
|
||||
# Criar diretório de backup se não existir
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Data atual para o nome do arquivo
|
||||
DATE=$(date +%Y%m%d-%H%M%S)
|
||||
BACKUP_FILE="$BACKUP_DIR/minio-backup-$DATE.tar.gz"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Backup MinIO iniciado em: $(date)"
|
||||
echo "=========================================="
|
||||
|
||||
# ============ FAZER BACKUP ============
|
||||
echo "Criando backup do volume $VOLUME_NAME..."
|
||||
|
||||
if [ "$COMPRESSION" = "gzip" ]; then
|
||||
docker run --rm \
|
||||
-v "$VOLUME_NAME:/data:ro" \
|
||||
-v "$BACKUP_DIR:/backup" \
|
||||
alpine tar czf "/backup/$(basename "$BACKUP_FILE")" -C /data .
|
||||
else
|
||||
docker run --rm \
|
||||
-v "$VOLUME_NAME:/data:ro" \
|
||||
-v "$BACKUP_DIR:/backup" \
|
||||
alpine tar cf "/backup/$(basename "$BACKUP_FILE")" -C /data .
|
||||
fi
|
||||
|
||||
# ============ VERIFICAR ============
|
||||
if [ -f "$BACKUP_FILE" ]; then
|
||||
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
||||
echo "✓ Backup criado: $BACKUP_FILE ($SIZE)"
|
||||
else
|
||||
echo "✗ ERRO: Backup não foi criado!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ============ LIMPAR BACKUPS ANTIGOS ============
|
||||
echo "Limpando backups com mais de $RETENTION_DAYS dias..."
|
||||
find "$BACKUP_DIR" -name "minio-backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||||
|
||||
# ============ LISTAR BACKUPS RESTANTES ============
|
||||
echo ""
|
||||
echo "Backups disponíveis:"
|
||||
ls -lh "$BACKUP_DIR"/minio-backup-*.tar.gz 2>/dev/null || echo "Nenhum backup encontrado."
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Backup concluído em: $(date)"
|
||||
echo "=========================================="
|
||||
@@ -0,0 +1,39 @@
|
||||
services:
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
container_name: course-plat-minio
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9000:9000" # API
|
||||
- "9001:9001" # Console (UI)
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
command: server /data --console-address ":9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
|
||||
# Opcional: cria bucket automaticamente ao iniciar
|
||||
minio-init:
|
||||
image: minio/mc:latest
|
||||
container_name: course-plat-minio-init
|
||||
depends_on:
|
||||
- minio
|
||||
entrypoint: >
|
||||
sh -c "
|
||||
sleep 5 &&
|
||||
mc alias set myminio http://minio:9000 ${MINIO_ROOT_USER:-minioadmin} ${MINIO_ROOT_PASSWORD:-minioadmin} &&
|
||||
mc mb myminio/${MINIO_BUCKET:-course-plat} --ignore-existing &&
|
||||
mc anonymous set none myminio/${MINIO_BUCKET:-course-plat} &&
|
||||
echo 'MinIO initialized! Bucket is private.'
|
||||
"
|
||||
restart: "no"
|
||||
|
||||
volumes:
|
||||
minio_data:
|
||||
driver: local
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
# pull-backup.sh - Script para baixar backups do servidor para seu PC
|
||||
# Uso: ./pull-backup.sh
|
||||
# Agendar no crontab do SEU PC: 0 3 * * * /caminho/para/pull-backup.sh
|
||||
|
||||
set -e
|
||||
|
||||
# ============ CONFIGURAÇÃO ============
|
||||
# Preencha com seus dados
|
||||
SERVER_USER="usuario" # Usuário SSH no servidor
|
||||
SERVER_HOST="seu-servidor.com" # IP ou domínio do servidor
|
||||
SERVER_BACKUP_DIR="/var/backups/minio" # Mesmo diretório do backup-minio.sh
|
||||
LOCAL_BACKUP_DIR="$HOME/backups/minio" # Onde salvar no seu PC
|
||||
KEEP_LOCAL_DAYS=30 # Quanto tempo manter no seu PC
|
||||
|
||||
# ============ CÓDIGO ============
|
||||
mkdir -p "$LOCAL_BACKUP_DIR"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Baixando backups do MinIO"
|
||||
echo "De: $SERVER_USER@$SERVER_HOST:$SERVER_BACKUP_DIR"
|
||||
echo "Para: $LOCAL_BACKUP_DIR"
|
||||
echo "Iniciado em: $(date)"
|
||||
echo "=========================================="
|
||||
|
||||
# Baixar backups (somente os que ainda não temos)
|
||||
echo "Sincronizando arquivos..."
|
||||
rsync -avz --progress \
|
||||
-e "ssh -o StrictHostKeyChecking=no" \
|
||||
"$SERVER_USER@$SERVER_HOST:$SERVER_BACKUP_DIR/" \
|
||||
"$LOCAL_BACKUP_DIR/"
|
||||
|
||||
# ============ LIMPAR BACKUPS ANTIGOS (LOCAL) ============
|
||||
echo ""
|
||||
echo "Limpando backups locais com mais de $KEEP_LOCAL_DAYS dias..."
|
||||
find "$LOCAL_BACKUP_DIR" -name "minio-backup-*.tar.gz" -mtime +$KEEP_LOCAL_DAYS -delete
|
||||
|
||||
# ============ RESUMO ============
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Backups locais:"
|
||||
ls -lh "$LOCAL_BACKUP_DIR"/minio-backup-*.tar.gz 2>/dev/null | tail -5
|
||||
echo ""
|
||||
echo "Espaço usado:"
|
||||
du -sh "$LOCAL_BACKUP_DIR"
|
||||
echo ""
|
||||
echo "Concluído em: $(date)"
|
||||
echo "=========================================="
|
||||
|
||||
# ============ ALERTAS ============
|
||||
BACKUP_COUNT=$(ls -1 "$LOCAL_BACKUP_DIR"/minio-backup-*.tar.gz 2>/dev/null | wc -l)
|
||||
if [ "$BACKUP_COUNT" -eq 0 ]; then
|
||||
echo "⚠️ ATENÇÃO: Nenhum backup encontrado localmente!"
|
||||
fi
|
||||
@@ -0,0 +1,55 @@
|
||||
# Multi-stage Dockerfile para Produção
|
||||
# Uso: docker build -f docker/production/Dockerfile -t course-plat .
|
||||
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
# Instalar dependências apenas para produção
|
||||
FROM base AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Copiar package files
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm ci --only=production
|
||||
|
||||
# Build da aplicação
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Build Next.js
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
RUN npm run build
|
||||
|
||||
# Imagem final de produção
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Criar usuário não-root
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copiar arquivos necessários
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
|
||||
# Criar diretório para storage local
|
||||
RUN mkdir -p /app/storage/uploads && chown -R nextjs:nodejs /app/storage
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
# ==========================================
|
||||
# BACKUP MONGODB - PRODUÇÃO
|
||||
# ==========================================
|
||||
# Suporta MongoDB nativo ou Docker
|
||||
# Uso: ./backup-mongodb.sh
|
||||
#
|
||||
# Adicionar ao crontab (deployuser):
|
||||
# 0 2 * * * cd /var/www/iciv && ./docker/production/backup-mongodb.sh >> ~/backup-mongodb.log 2>&1
|
||||
|
||||
set -e
|
||||
|
||||
# ==========================================
|
||||
# CONFIGURAÇÕES
|
||||
# ==========================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
BACKUP_DIR="${BACKUP_DIR:-$PROJECT_DIR/backups/mongodb}"
|
||||
|
||||
RETENTION_DAYS="${RETENTION_DAYS:-7}"
|
||||
|
||||
CONTAINER_NAME="${MONGO_CONTAINER:-course-plat-mongodb}"
|
||||
|
||||
ENV_FILE="${ENV_FILE:-$PROJECT_DIR/.env.production}"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
set -a
|
||||
source <(grep -v '^\s*#' "$ENV_FILE")
|
||||
set +a
|
||||
fi
|
||||
|
||||
MONGO_USERNAME="${MONGO_USERNAME:-admin}"
|
||||
MONGO_PASSWORD="${MONGO_PASSWORD:-password}"
|
||||
MONGO_DB="${MONGO_DB:-course-plat}"
|
||||
|
||||
# ==========================================
|
||||
# FUNÇÕES
|
||||
# ==========================================
|
||||
|
||||
log() {
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
log "ERROR: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
build_mongo_uri() {
|
||||
if [ -n "$MONGO_USERNAME" ] && [ -n "$MONGO_PASSWORD" ]; then
|
||||
echo "mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@127.0.0.1:27017/${MONGO_DB}?authSource=admin"
|
||||
else
|
||||
echo "mongodb://127.0.0.1:27017/${MONGO_DB}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ==========================================
|
||||
# DETECÇÃO: Docker ou nativo
|
||||
# ==========================================
|
||||
|
||||
DOCKER_CMD="$(command -v docker 2>/dev/null || true)"
|
||||
|
||||
USE_DOCKER=false
|
||||
if [ -n "$DOCKER_CMD" ] && "$DOCKER_CMD" ps 2>/dev/null | grep -q "$CONTAINER_NAME"; then
|
||||
USE_DOCKER=true
|
||||
log "Modo: Docker (container: $CONTAINER_NAME)"
|
||||
else
|
||||
MONGODUMP="$(command -v mongodump 2>/dev/null || true)"
|
||||
if [ -z "$MONGODUMP" ]; then
|
||||
error "mongodump nao encontrado. Instale: sudo apt install mongo-tools"
|
||||
fi
|
||||
log "Modo: MongoDB nativo"
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# INÍCIO
|
||||
# ==========================================
|
||||
|
||||
log "Iniciando backup do MongoDB..."
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
BACKUP_FILE="$BACKUP_DIR/mongodb-$TIMESTAMP.gz"
|
||||
|
||||
MONGO_URI=$(build_mongo_uri)
|
||||
log "Executando mongodump..."
|
||||
|
||||
if [ "$USE_DOCKER" = true ]; then
|
||||
"$DOCKER_CMD" exec "$CONTAINER_NAME" mongodump \
|
||||
--uri="$MONGO_URI" \
|
||||
--archive \
|
||||
--gzip \
|
||||
> "$BACKUP_FILE" 2>&1 || error "Falha no mongodump (docker)"
|
||||
else
|
||||
"$MONGODUMP" \
|
||||
--uri="$MONGO_URI" \
|
||||
--archive="$BACKUP_FILE" \
|
||||
--gzip \
|
||||
2>&1 || error "Falha no mongodump"
|
||||
fi
|
||||
|
||||
if [ ! -f "$BACKUP_FILE" ]; then
|
||||
error "Arquivo de backup nao foi criado"
|
||||
fi
|
||||
|
||||
BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
||||
log "Backup concluido: $BACKUP_FILE ($BACKUP_SIZE)"
|
||||
|
||||
# ==========================================
|
||||
# LIMPEZA
|
||||
# ==========================================
|
||||
|
||||
log "Removendo backups antigos (mais de $RETENTION_DAYS dias)..."
|
||||
|
||||
REMOVED=$(find "$BACKUP_DIR" \
|
||||
-name "mongodb-*.gz" \
|
||||
-type f \
|
||||
-mtime +$RETENTION_DAYS \
|
||||
-print -delete 2>/dev/null | wc -l)
|
||||
|
||||
log "Backups removidos: $REMOVED"
|
||||
|
||||
# ==========================================
|
||||
# RESUMO
|
||||
# ==========================================
|
||||
|
||||
TOTAL_BACKUPS=$(find "$BACKUP_DIR" -name "mongodb-*.gz" -type f | wc -l)
|
||||
TOTAL_SIZE=$(du -sh "$BACKUP_DIR" 2>/dev/null | cut -f1)
|
||||
|
||||
log "Resumo:"
|
||||
log " - Backup atual: $BACKUP_FILE"
|
||||
log " - Total de backups: $TOTAL_BACKUPS"
|
||||
log " - Tamanho total: $TOTAL_SIZE"
|
||||
log "Backup do MongoDB concluido com sucesso!"
|
||||
@@ -0,0 +1,125 @@
|
||||
# Docker Compose para Produção
|
||||
# Uso: docker compose -f docker/production/docker-compose.yml up -d
|
||||
#
|
||||
# Antes de usar:
|
||||
# 1. Copiar .env.example para .env.production
|
||||
# 2. Preencher todas as variáveis de ambiente
|
||||
# 3. Buildar a imagem da aplicação: docker build -t course-plat .
|
||||
# 4. Ou usar build automático com compose (descomentar build section)
|
||||
|
||||
services:
|
||||
# Aplicação Next.js
|
||||
app:
|
||||
image: course-plat:latest
|
||||
# Para build automático, descomente abaixo:
|
||||
# build:
|
||||
# context: ../..
|
||||
# dockerfile: docker/production/Dockerfile
|
||||
container_name: course-plat-app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${APP_PORT:-3000}:3000"
|
||||
environment:
|
||||
# Node
|
||||
NODE_ENV: production
|
||||
|
||||
# Next.js
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL}
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
||||
|
||||
# MongoDB
|
||||
MONGO_URI: mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb:27017/${MONGO_DB}?authSource=admin
|
||||
|
||||
# Storage
|
||||
STORAGE_TYPE: ${STORAGE_TYPE:-s3}
|
||||
LOCAL_STORAGE_PATH: /app/storage/uploads
|
||||
S3_ENDPOINT: ${S3_ENDPOINT}
|
||||
S3_REGION: ${S3_REGION:-us-east-1}
|
||||
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
|
||||
S3_SECRET_KEY: ${S3_SECRET_KEY}
|
||||
S3_BUCKET: ${S3_BUCKET}
|
||||
volumes:
|
||||
- app_storage:/app/storage/uploads
|
||||
depends_on:
|
||||
- mongodb
|
||||
- minio
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- course-plat-network
|
||||
|
||||
# MongoDB - Banco de dados
|
||||
mongodb:
|
||||
image: mongo:8
|
||||
container_name: course-plat-mongodb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME}
|
||||
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
|
||||
MONGO_INITDB_DATABASE: ${MONGO_DB}
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
- mongodb_config:/data/configdb
|
||||
- ./backups/mongodb:/backups # Para restore
|
||||
healthcheck:
|
||||
test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
networks:
|
||||
- course-plat-network
|
||||
|
||||
# MinIO - Armazenamento de arquivos
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
container_name: course-plat-minio
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
command: server /data --console-address ":9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
networks:
|
||||
- course-plat-network
|
||||
|
||||
# Nginx (opcional) - Reverse Proxy
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: course-plat-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./ssl:/etc/nginx/ssl:ro
|
||||
- nginx_logs:/var/log/nginx
|
||||
depends_on:
|
||||
- app
|
||||
networks:
|
||||
- course-plat-network
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
driver: local
|
||||
mongodb_config:
|
||||
driver: local
|
||||
minio_data:
|
||||
driver: local
|
||||
app_storage:
|
||||
driver: local
|
||||
nginx_logs:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
course-plat-network:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,131 @@
|
||||
# Nginx Reverse Proxy para Course Plat
|
||||
# Uso: Copiar para docker/production/nginx.conf ou /etc/nginx/sites-available/course-plat
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
# Performance
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/json application/javascript application/xml+rss
|
||||
application/rss+xml font/truetype font/opentype
|
||||
application/vnd.ms-fontobject image/svg+xml;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
|
||||
|
||||
# Upstream da aplicação
|
||||
upstream app_backend {
|
||||
server app:3000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# HTTP -> HTTPS redirect (descomentar em prod com SSL)
|
||||
# server {
|
||||
# listen 80;
|
||||
# server_name seu-dominio.com.br;
|
||||
# return 301 https://$server_name$request_uri;
|
||||
# }
|
||||
|
||||
# Server principal
|
||||
server {
|
||||
listen 80;
|
||||
# listen 443 ssl http2; # Descomentar para SSL
|
||||
server_name _;
|
||||
|
||||
# SSL Configuration (descomentar para production)
|
||||
# ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
# ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
# ssl_protocols TLSv1.2 TLSv1.3;
|
||||
# ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
|
||||
# Client body size limit (uploads)
|
||||
client_max_body_size 500M;
|
||||
|
||||
# Proxy settings
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Next.js static files (com cache)
|
||||
location /_next/static {
|
||||
alias /var/www/.next/static;
|
||||
expires 365d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
location /static {
|
||||
alias /var/www/public;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
# API routes (sem cache, com rate limit)
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://app_backend;
|
||||
}
|
||||
|
||||
# Auth endpoints (rate limit mais estrito)
|
||||
location /api/auth/ {
|
||||
limit_req zone=login burst=5 nodelay;
|
||||
proxy_pass http://app_backend;
|
||||
}
|
||||
|
||||
# File downloads (proxy)
|
||||
location /api/files/ {
|
||||
proxy_pass http://app_backend;
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
}
|
||||
|
||||
# Todas as outras requests
|
||||
location / {
|
||||
proxy_pass http://app_backend;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_connect_timeout 75s;
|
||||
}
|
||||
|
||||
# Health check
|
||||
location /health {
|
||||
access_log off;
|
||||
proxy_pass http://app_backend/api/health;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user