Migrate to Env Secret and Add Frontend Dockerfile
This commit is contained in:
@@ -106,19 +106,19 @@ DATABASE_BACKUP_PATH=/data/backups
|
|||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. Create Docker Secret
|
### 5. Generate JWT Secret
|
||||||
|
|
||||||
|
The JWT_SECRET is already included in your `.env` file. The secret is generated automatically when you create the `.env` file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generate secure JWT secret
|
# Already done in step 4, but if you need to regenerate:
|
||||||
openssl rand -base64 32 > ~/edh-stats/jwt_secret.txt
|
openssl rand -base64 32
|
||||||
|
|
||||||
# Create Docker secret (one-time setup)
|
# Copy the output and update JWT_SECRET in .env
|
||||||
docker secret create jwt_secret ~/edh-stats/jwt_secret.txt
|
|
||||||
|
|
||||||
# Verify
|
|
||||||
docker secret ls
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Your JWT secret is stored in the `.env` file which is protected by `.gitignore` (not committed to git).
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
### 1. Log in to GHCR
|
### 1. Log in to GHCR
|
||||||
@@ -351,9 +351,10 @@ docker update --memory 1G --cpus 1.0 edh-stats-backend-1
|
|||||||
## Security Best Practices
|
## Security Best Practices
|
||||||
|
|
||||||
1. **Secrets Management**
|
1. **Secrets Management**
|
||||||
- Never commit secrets to Git
|
- Never commit `.env` file to Git (already in .gitignore)
|
||||||
- Use Docker secrets for sensitive data
|
- Keep `.env` file secure on your server (chmod 600)
|
||||||
- Rotate JWT_SECRET periodically
|
- Rotate JWT_SECRET periodically by updating .env and restarting services
|
||||||
|
- Backup `.env` file securely (offsite)
|
||||||
|
|
||||||
2. **Environment Variables**
|
2. **Environment Variables**
|
||||||
- Set CORS_ORIGIN to your domain
|
- Set CORS_ORIGIN to your domain
|
||||||
|
|||||||
@@ -33,11 +33,14 @@ scp docker-compose.prod.deployed.yml user@server:~/edh-stats/
|
|||||||
ssh user@server
|
ssh user@server
|
||||||
cd ~/edh-stats
|
cd ~/edh-stats
|
||||||
|
|
||||||
# Create secret
|
# Create .env file with configuration
|
||||||
openssl rand -base64 32 > jwt_secret.txt
|
cat > .env << EOF
|
||||||
docker secret create jwt_secret jwt_secret.txt
|
JWT_SECRET=$(openssl rand -base64 32)
|
||||||
|
CORS_ORIGIN=https://yourdomain.com
|
||||||
|
ALLOW_REGISTRATION=false
|
||||||
|
EOF
|
||||||
|
|
||||||
# Start
|
# Start services
|
||||||
docker-compose -f docker-compose.prod.deployed.yml up -d
|
docker-compose -f docker-compose.prod.deployed.yml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -117,40 +120,25 @@ scp frontend/nginx.prod.conf user@your-server.com:~/edh-stats/
|
|||||||
|
|
||||||
**Create .env File on Server:**
|
**Create .env File on Server:**
|
||||||
```bash
|
```bash
|
||||||
cat > ~/.env << EOF
|
cat > .env << EOF
|
||||||
# Required
|
# Required - Generate secure JWT secret
|
||||||
|
JWT_SECRET=$(openssl rand -base64 32)
|
||||||
|
|
||||||
|
# Your domain for CORS
|
||||||
CORS_ORIGIN=https://yourdomain.com
|
CORS_ORIGIN=https://yourdomain.com
|
||||||
|
|
||||||
# Optional
|
# Optional - Allow user registration (default: false)
|
||||||
ALLOW_REGISTRATION=false
|
ALLOW_REGISTRATION=false
|
||||||
|
|
||||||
|
# Optional - Log level in production
|
||||||
LOG_LEVEL=warn
|
LOG_LEVEL=warn
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Keep this file safe! It contains your JWT_SECRET
|
||||||
|
chmod 600 .env
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Setup Docker Secrets
|
**Note:** The `.env` file is already in `.gitignore` so it won't be committed to git.
|
||||||
|
|
||||||
**Generate JWT Secret:**
|
|
||||||
```bash
|
|
||||||
# On server
|
|
||||||
openssl rand -base64 32 > jwt_secret.txt
|
|
||||||
cat jwt_secret.txt
|
|
||||||
# Save this somewhere safe for backups!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Create Docker Secret:**
|
|
||||||
```bash
|
|
||||||
docker secret create jwt_secret jwt_secret.txt
|
|
||||||
|
|
||||||
# Verify
|
|
||||||
docker secret ls
|
|
||||||
docker secret inspect jwt_secret
|
|
||||||
```
|
|
||||||
|
|
||||||
**Cleanup:**
|
|
||||||
```bash
|
|
||||||
# Remove local secret file after import
|
|
||||||
rm jwt_secret.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Start Services
|
### 5. Start Services
|
||||||
|
|
||||||
|
|||||||
17
deploy.sh
17
deploy.sh
@@ -167,7 +167,7 @@ EOF
|
|||||||
--file ./frontend/Dockerfile.prod \
|
--file ./frontend/Dockerfile.prod \
|
||||||
--tag "${FRONTEND_IMAGE}" \
|
--tag "${FRONTEND_IMAGE}" \
|
||||||
--tag "${FRONTEND_IMAGE_LATEST}" \
|
--tag "${FRONTEND_IMAGE_LATEST}" \
|
||||||
./
|
./frontend
|
||||||
|
|
||||||
print_success "Frontend image built successfully"
|
print_success "Frontend image built successfully"
|
||||||
}
|
}
|
||||||
@@ -255,6 +255,13 @@ generate_deployment_config() {
|
|||||||
# Version: ${VERSION}
|
# Version: ${VERSION}
|
||||||
# Generated: $(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
# Generated: $(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||||
# GitHub User: ${GITHUB_USER}
|
# GitHub User: ${GITHUB_USER}
|
||||||
|
#
|
||||||
|
# IMPORTANT: Create a .env file with these variables:
|
||||||
|
# JWT_SECRET=\$(openssl rand -base64 32)
|
||||||
|
# CORS_ORIGIN=https://yourdomain.com
|
||||||
|
# ALLOW_REGISTRATION=false
|
||||||
|
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
@@ -262,7 +269,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- DATABASE_PATH=/app/database/data/edh-stats.db
|
- DATABASE_PATH=/app/database/data/edh-stats.db
|
||||||
- JWT_SECRET_FILE=/run/secrets/jwt_secret
|
- JWT_SECRET=\${JWT_SECRET}
|
||||||
- CORS_ORIGIN=\${CORS_ORIGIN:-https://yourdomain.com}
|
- CORS_ORIGIN=\${CORS_ORIGIN:-https://yourdomain.com}
|
||||||
- LOG_LEVEL=warn
|
- LOG_LEVEL=warn
|
||||||
- RATE_LIMIT_WINDOW=15
|
- RATE_LIMIT_WINDOW=15
|
||||||
@@ -271,8 +278,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- sqlite_data:/app/database/data
|
- sqlite_data:/app/database/data
|
||||||
- app_logs:/app/logs
|
- app_logs:/app/logs
|
||||||
secrets:
|
|
||||||
- jwt_secret
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
@@ -307,10 +312,6 @@ volumes:
|
|||||||
app_logs:
|
app_logs:
|
||||||
driver: local
|
driver: local
|
||||||
|
|
||||||
secrets:
|
|
||||||
jwt_secret:
|
|
||||||
external: true
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
edh-stats-network:
|
edh-stats-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
16
frontend/Dockerfile.prod
Normal file
16
frontend/Dockerfile.prod
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Copy nginx configuration
|
||||||
|
COPY ./nginx.prod.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
|
# Copy frontend files
|
||||||
|
COPY ./public /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Expose ports
|
||||||
|
EXPOSE 80 443
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost/health.html || exit 1
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
Reference in New Issue
Block a user