This commit is contained in:
Andrey Kondratev
2025-08-28 16:50:32 +05:00
parent b8e2bf1090
commit 9d011cf4c5
6 changed files with 411 additions and 5 deletions

96
.github/DEPLOYMENT.md vendored Normal file
View File

@@ -0,0 +1,96 @@
# GitHub Actions Deployment Setup
## Required Secrets
Configure the following secrets in your GitHub repository settings:
### Production Deployment Secrets
1. **HOST** - Your server IP address or domain
```
123.456.789.123
```
2. **USERNAME** - SSH username (usually `root` or `ubuntu`)
```
root
```
3. **SSH_KEY** - Private SSH key for server access
```
-----BEGIN OPENSSH PRIVATE KEY-----
your_private_key_content_here
-----END OPENSSH PRIVATE KEY-----
```
4. **PORT** - SSH port (optional, defaults to 22)
```
22
```
## Server Prerequisites
Your production server should have:
1. **Docker & Docker Compose installed**
```bash
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
sudo usermod -aG docker $USER
```
2. **Project directory prepared**
```bash
sudo mkdir -p /opt/quixotic
sudo chown $USER:$USER /opt/quixotic
cd /opt/quixotic
git clone https://github.com/yourusername/quixotic.git .
```
3. **Environment file configured**
```bash
cp .env.docker.example .env.docker
nano .env.docker
# Set your domain and email
```
## Workflow Features
### CI Pipeline (`ci.yml`)
- ✅ **Test & Lint** - Runs on all PRs and pushes
- ✅ **Multi-platform build** - AMD64 and ARM64 support
- ✅ **Docker image caching** - Faster builds
- ✅ **Auto-deployment** - Deploys main branch to production
- ✅ **Zero-downtime deployment** - Rolling updates
### Security Pipeline (`security.yml`)
- ✅ **Dependency scanning** - npm audit for vulnerabilities
- ✅ **Code analysis** - GitHub CodeQL for security issues
- ✅ **Docker scanning** - Trivy for container vulnerabilities
- ✅ **Weekly scans** - Automated security checks
## Usage
1. **Development workflow:**
- Create feature branch: `git checkout -b feature/new-feature`
- Push changes: CI runs tests automatically
- Create PR: Full CI pipeline runs
2. **Production deployment:**
- Merge to main: Automatic build and deploy
- Monitor deployment: Check GitHub Actions tab
3. **Manual deployment:**
```bash
# On server
cd /opt/quixotic
git pull origin main
docker-compose --env-file .env.docker up -d --build
```
## Monitoring
- **GitHub Actions** - Build and deployment status
- **Traefik Dashboard** - `http://yourserver:8080`
- **Application Health** - `https://yourdomain.com/health`
- **Docker Logs** - `docker-compose logs -f quixotic-app`

125
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,125 @@
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
name: Test & Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Build project
run: npm run build
- name: Run validation
run: npm run validate
build:
name: Build Docker Image
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push'
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment: production
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.PORT }}
script: |
cd /opt/quixotic
git pull origin main
# Login to GitHub Container Registry
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
# Pull latest image
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Update docker-compose to use new image
sed -i 's|build:|#build:|g' docker-compose.yml
sed -i 's|context: .|#context: .|g' docker-compose.yml
sed -i 's|dockerfile: Dockerfile|#dockerfile: Dockerfile|g' docker-compose.yml
sed -i '/quixotic-app:/a \ \ \ \ image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest' docker-compose.yml
# Deploy with zero downtime
docker-compose --env-file .env.docker pull
docker-compose --env-file .env.docker up -d
# Cleanup old images
docker image prune -f

67
.github/workflows/security.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 6 * * 1' # Weekly on Monday at 6 AM
jobs:
security:
name: Security Vulnerability Scan
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level=high
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
docker-security:
name: Docker Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image for scanning
run: docker build -t quixotic:scan .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'quixotic:scan'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'

View File

@@ -0,0 +1,81 @@
# Complete Docker + Traefik + SSL Setup for Quixotic
## Files Created/Modified
### Docker Configuration
- `docker-compose.yml` - Main orchestration with Traefik v3.0 + Certbot
- `Dockerfile` - Multi-stage build, fixed ARM64 ffmpeg compatibility
- `.env.docker` - Environment variables for production
- `traefik.yml` - Static Traefik configuration
- `.dockerignore` - Docker build exclusions
- `Dockerfile.base` - Base image (created but not used)
### SSL Setup
- `ssl-setup.sh` - Automated SSL setup script for domains
- Traefik configured for HTTP challenge (not TLS challenge)
- Certbot service for additional certificate management
- Auto-renewal every 12 hours
## Key Features Implemented
### Traefik Reverse Proxy
- Automatic HTTPS with Let's Encrypt
- HTTP to HTTPS redirect
- Dashboard on port 8080 with basic auth
- Docker provider with label-based routing
### Docker Optimization
- Multi-stage build for smaller images
- Health checks for application
- Persistent volumes for SSL certs and downloads
- Non-root user for security
### SSL/TLS
- HTTP challenge for certificate validation
- Automatic certificate renewal
- Domain-based configuration via environment
### Architecture Fixes
- Fixed ffmpeg ARM64 compatibility issue
- Changed from copied binaries to Alpine packages
- Proper paths: `/usr/bin/ffmpeg` instead of `/usr/local/bin/ffmpeg`
## Usage Commands
```bash
# Local development
docker-compose --env-file .env.docker up -d
# Production with SSL
./ssl-setup.sh yourdomain.com your-email@domain.com
# Management
npm run docker:up
npm run docker:down
npm run docker:logs
npm run docker:rebuild
```
## Access Points
- App: https://yourdomain.com (or http://localhost)
- Traefik dashboard: http://localhost:8080
- Health check: /health endpoint
## Issues Resolved
1. ❌ ffmpeg architecture mismatch (ARM vs x86_64)
✅ Fixed with Alpine packages instead of copied binaries
2. ❌ npm ci lockfile sync issues
✅ Changed to npm install + npm prune
3. ❌ SSL certificate complexity
✅ Automated with Traefik + Let's Encrypt + HTTP challenge
4. ❌ Verbose logging in SoundCloud service
✅ Removed debug console.log statements
## Current Status
- ✅ Docker builds successfully
- ✅ Traefik proxy working
- ✅ SSL automation ready
- ⚠️ ffmpeg conversion still needs testing after ARM64 fix

View File

@@ -13,9 +13,10 @@ services:
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.myresolver.acme.tlschallenge=true
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL:-admin@example.com}
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL:-admin@example.com}
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --log.level=INFO
ports:
- "80:80"
@@ -50,7 +51,7 @@ services:
- "traefik.enable=true"
- "traefik.http.routers.quixotic.rule=Host(`${DOMAIN:-localhost}`)"
- "traefik.http.routers.quixotic.entrypoints=websecure"
- "traefik.http.routers.quixotic.tls.certresolver=myresolver"
- "traefik.http.routers.quixotic.tls.certresolver=letsencrypt"
- "traefik.http.routers.quixotic.service=quixotic"
- "traefik.http.services.quixotic.loadbalancer.server.port=3000"
# HTTP to HTTPS redirect
@@ -69,4 +70,4 @@ volumes:
networks:
quixotic:
driver: bridge
driver: bridge

36
ssl-setup.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/bash
# SSL Setup Script for Quixotic with Certbot
set -e
DOMAIN=${1:-localhost}
EMAIL=${2:-admin@example.com}
echo "Setting up SSL for domain: $DOMAIN"
echo "Email: $EMAIL"
# Update .env.docker with provided values
sed -i.bak "s/DOMAIN=.*/DOMAIN=$DOMAIN/" .env.docker
sed -i.bak "s/ACME_EMAIL=.*/ACME_EMAIL=$EMAIL/" .env.docker
echo "Updated .env.docker with new values"
# Start services
echo "Starting Traefik and application..."
docker-compose --env-file .env.docker up -d traefik quixotic-app
echo "Waiting for services to be ready..."
sleep 10
# Test domain accessibility (optional)
if [ "$DOMAIN" != "localhost" ]; then
echo "Testing HTTP access to $DOMAIN..."
curl -f http://$DOMAIN/health || echo "Warning: HTTP test failed"
echo "SSL certificate will be automatically obtained by Traefik"
echo "Check https://$DOMAIN in a few minutes"
fi
echo "SSL setup complete!"
echo "Traefik dashboard: http://localhost:8080"
echo "Application: https://$DOMAIN"