diff --git a/.gitea/workflows/README.md b/.gitea/workflows/README.md new file mode 100644 index 0000000..fda26d1 --- /dev/null +++ b/.gitea/workflows/README.md @@ -0,0 +1,293 @@ +# Gitea Actions CI/CD Pipeline + +This directory contains Gitea Actions workflows for automated building, testing, and deployment of LittleShop. + +## Workflows + +### 1. Build and Deploy (`build-and-deploy.yml`) + +**Triggers:** +- Push to `main` branch → Automatic deployment to production +- Push to `development` branch → Deployment to development environment +- Push tags (e.g., `v1.0.0`) → Tagged release with manual deployment option +- Manual trigger via Gitea Actions UI + +**Jobs:** + +#### `build-littleshop` +- Builds LittleShop Docker image +- Tags with commit SHA and `latest` +- Uploads image as artifact for deployment + +#### `build-telebot` +- Builds TeleBot Docker image +- Tags with commit SHA and `latest` +- Uploads image as artifact for deployment + +#### `deploy-production` +- **Requires:** Both build jobs to complete +- **Runs:** On push to `main` branch or tagged releases +- **Environment:** `production` +- **Steps:** + 1. Downloads built Docker images + 2. Sets up SSH connection to VPS + 3. Transfers images to production server + 4. Tags images and pushes to local Docker registry + 5. Stops existing containers + 6. Applies database migrations (if present in `LittleShop/Migrations/*.sql`) + 7. Starts new containers with updated images + 8. Runs health checks + 9. Logs deployment status + +#### `deploy-development` +- **Requires:** Both build jobs to complete +- **Runs:** On push to `development` branch +- **Environment:** `development` +- Placeholder for development deployment configuration + +### 2. Rollback (`rollback.yml`) + +**Triggers:** +- Manual trigger only via Gitea Actions UI + +**Inputs:** +- `environment` (required): Choose between `production` or `development` +- `version` (optional): Specific version tag to rollback to (defaults to `previous`) + +**Behavior:** +1. Connects to VPS via SSH +2. Tags specified version (or `previous` tag) as `latest` +3. Stops current containers +4. Starts containers with rolled-back version +5. Runs health checks +6. Logs rollback status + +## Required Secrets + +Configure these secrets in your Gitea repository settings: + +### VPS Connection +- `VPS_HOST` - VPS hostname or IP address (e.g., `srv1002428.hstgr.cloud`) +- `VPS_PORT` - SSH port (e.g., `2255`) +- `VPS_USER` - SSH username (e.g., `sysadmin`) +- `VPS_SSH_KEY` - Private SSH key for authentication (Base64 encoded not required) + +### Example Secret Configuration + +Navigate to: **Repository → Settings → Secrets** + +``` +VPS_HOST: srv1002428.hstgr.cloud +VPS_PORT: 2255 +VPS_USER: sysadmin +VPS_SSH_KEY: -----BEGIN OPENSSH PRIVATE KEY----- + +-----END OPENSSH PRIVATE KEY----- +``` + +## Environment Configuration + +### Production Environment + +Configure in Gitea: **Repository → Settings → Environments → New Environment** + +- **Name:** `production` +- **URL:** `https://admin.dark.side` +- **Protection Rules:** + - Require approval for deployments (optional) + - Restrict to `main` branch only + +### Development Environment + +- **Name:** `development` +- **URL:** Your development server URL +- **Protection Rules:** + - Allow `development` branch deployments + +## Database Migrations + +The deployment workflow automatically applies SQLite migrations if present. + +**Migration Location:** `LittleShop/Migrations/*.sql` + +**Migration Process:** +1. Checks for `*.sql` files in the Migrations directory +2. Creates automatic backup before each migration: `littleshop-production.db.backup-YYYYMMDD-HHMMSS` +3. Applies each migration file sequentially +4. Logs migration status + +**Migration File Format:** +```sql +-- Migration: Add CustomerDataRetention field +-- Date: 2025-11-14 + +ALTER TABLE Customers ADD COLUMN DataRetentionDate DATETIME NULL; +CREATE INDEX IF NOT EXISTS IX_Customers_DataRetentionDate ON Customers(DataRetentionDate); +``` + +## Health Checks + +After each deployment, the workflow performs health checks: + +- **Endpoint:** `http://localhost:5100/api/catalog/products` +- **Attempts:** 6 attempts with 10-second intervals +- **Timeout:** 60 seconds total +- **On Failure:** Displays last 50 lines of container logs and exits with error code + +## Deployment Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Gitea Actions Runner │ +│ ┌────────────┐ ┌────────────┐ │ +│ │ Build │ │ Build │ │ +│ │ LittleShop │ │ TeleBot │ │ +│ └─────┬──────┘ └─────┬──────┘ │ +│ │ │ │ +│ └────────┬───────────────┘ │ +│ ▼ │ +│ ┌────────────────┐ │ +│ │ Upload Images │ │ +│ │ as Artifacts │ │ +│ └────────┬───────┘ │ +└─────────────────┼────────────────────────────────────────────┘ + │ + │ SSH Transfer + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Production VPS │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Local Docker Registry (localhost:5000) │ │ +│ │ - littleshop:latest, littleshop: │ │ +│ │ - telebot:latest, telebot: │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────┐ ┌────────────────┐ │ +│ │ LittleShop │ │ TeleBot │ │ +│ │ Container │ │ Container │ │ +│ │ Port: 5100 │ │ Port: 5010 │ │ +│ └────────┬───────┘ └────────┬───────┘ │ +│ │ │ │ +│ ┌────────┴───────────────────┴────────┐ │ +│ │ Docker Networks: │ │ +│ │ - littleshop_littleshop-network │ │ +│ │ - silverpay_silverpay-network │ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────┐ │ +│ │ Nginx Proxy Manager │ │ +│ │ https://admin.dark.side │ │ +│ └─────────────────────────────────────┘ │ +└───────────────────────────────────────────────────────────────┘ +``` + +## Local Testing + +To test workflows locally before pushing: + +```bash +# Install act (GitHub/Gitea Actions local runner) +# For WSL/Linux: +curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash + +# Run workflow locally +act -W .gitea/workflows/build-and-deploy.yml + +# Run specific job +act -W .gitea/workflows/build-and-deploy.yml -j build-littleshop +``` + +## Troubleshooting + +### Deployment Fails During Migration + +**Symptom:** Deployment fails with SQLite error + +**Solution:** +1. Check migration file syntax +2. Manually test migration: + ```bash + ssh -p 2255 sysadmin@srv1002428.hstgr.cloud + cd /opt/littleshop + docker exec -it littleshop sqlite3 /app/data/littleshop-production.db + ``` +3. Restore from backup if needed: + ```bash + docker cp littleshop:/app/data/littleshop-production.db.backup-YYYYMMDD-HHMMSS \ + /app/data/littleshop-production.db + ``` + +### Health Check Fails After Deployment + +**Symptom:** "Health check failed after deployment" + +**Solution:** +1. Check container logs: + ```bash + ssh -p 2255 sysadmin@srv1002428.hstgr.cloud + docker logs littleshop --tail 100 + docker logs telebot-service --tail 100 + ``` +2. Verify network connectivity: + ```bash + docker exec littleshop curl -I http://localhost:5000/api/catalog/products + ``` +3. Check if database is accessible: + ```bash + docker exec littleshop ls -lh /app/data/ + ``` + +### SSH Connection Issues + +**Symptom:** "Permission denied" or "Connection refused" + +**Solution:** +1. Verify SSH key is correct in repository secrets +2. Check SSH port and firewall rules: + ```bash + ssh -v -p 2255 sysadmin@srv1002428.hstgr.cloud + ``` +3. Ensure SSH key has correct permissions (600) + +### Docker Network Not Found + +**Symptom:** "network not found: silverpay_silverpay-network" + +**Solution:** +1. Create missing networks: + ```bash + docker network create silverpay_silverpay-network + docker network create littleshop_littleshop-network + ``` +2. Verify `docker-compose.yml` network configuration + +## Workflow Optimization Tips + +1. **Faster Builds:** Use BuildKit caching + ```yaml + - name: Build with cache + uses: docker/build-push-action@v5 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + ``` + +2. **Parallel Jobs:** Build jobs run in parallel by default +3. **Artifact Retention:** Artifacts kept for 1 day to save storage +4. **Docker Layer Caching:** Enabled via BuildKit + +## Migration from GitLab CI/CD + +This workflow replaces the previous `.gitlab-ci.yml` configuration. + +**Key Differences:** +- Uses Gitea Actions (GitHub Actions syntax) instead of GitLab CI/CD +- Artifacts stored in Gitea instead of GitLab +- Environment protection rules configured in Gitea UI +- Same deployment logic and VPS configuration + +**No Changes Required On VPS:** +- Deployment scripts identical +- Docker network configuration unchanged +- Database migration process identical +- Health check endpoints unchanged diff --git a/.gitea/workflows/build-and-deploy.yml b/.gitea/workflows/build-and-deploy.yml new file mode 100644 index 0000000..d0892f6 --- /dev/null +++ b/.gitea/workflows/build-and-deploy.yml @@ -0,0 +1,368 @@ +name: Build and Deploy LittleShop + +on: + push: + branches: + - main + - development + tags: + - 'v*' + workflow_dispatch: + +env: + DOCKER_BUILDKIT: 1 + COMPOSE_DOCKER_CLI_BUILD: 1 + +jobs: + build-littleshop: + name: Build LittleShop Docker Image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build LittleShop image + run: | + echo "Building LittleShop Docker image" + docker build --no-cache -t littleshop:${{ github.sha }} . + docker tag littleshop:${{ github.sha }} littleshop:latest + + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "Tagging as version ${{ github.ref_name }}" + docker tag littleshop:${{ github.sha }} littleshop:${{ github.ref_name }} + fi + + - name: Save LittleShop image + run: | + mkdir -p /tmp/docker-images + docker save littleshop:${{ github.sha }} | gzip > /tmp/docker-images/littleshop.tar.gz + + - name: Upload LittleShop artifact + uses: actions/upload-artifact@v4 + with: + name: littleshop-image + path: /tmp/docker-images/littleshop.tar.gz + retention-days: 1 + + build-telebot: + name: Build TeleBot Docker Image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build TeleBot image + run: | + echo "Building TeleBot Docker image" + docker build --no-cache -t telebot:${{ github.sha }} -f Dockerfile.telebot . + docker tag telebot:${{ github.sha }} telebot:latest + + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "Tagging as version ${{ github.ref_name }}" + docker tag telebot:${{ github.sha }} telebot:${{ github.ref_name }} + fi + + - name: Save TeleBot image + run: | + mkdir -p /tmp/docker-images + docker save telebot:${{ github.sha }} | gzip > /tmp/docker-images/telebot.tar.gz + + - name: Upload TeleBot artifact + uses: actions/upload-artifact@v4 + with: + name: telebot-image + path: /tmp/docker-images/telebot.tar.gz + retention-days: 1 + + deploy-production: + name: Deploy to Production VPS (Manual Only) + needs: [build-littleshop, build-telebot] + runs-on: ubuntu-latest + if: false # Disabled - Manual deployment only via workflow_dispatch + environment: + name: production + url: https://admin.dark.side + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download LittleShop image + uses: actions/download-artifact@v4 + with: + name: littleshop-image + path: /tmp/docker-images + + - name: Download TeleBot image + uses: actions/download-artifact@v4 + with: + name: telebot-image + path: /tmp/docker-images + + - name: Load Docker images + run: | + docker load < /tmp/docker-images/littleshop.tar.gz + docker load < /tmp/docker-images/telebot.tar.gz + + - name: Set up SSH + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -p ${{ secrets.VPS_PORT }} ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: Transfer Docker images to VPS + run: | + echo "Copying LittleShop image to VPS..." + docker save littleshop:${{ github.sha }} | \ + ssh -i ~/.ssh/deploy_key -p ${{ secrets.VPS_PORT }} ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} \ + "docker load" + + echo "Copying TeleBot image to VPS..." + docker save telebot:${{ github.sha }} | \ + ssh -i ~/.ssh/deploy_key -p ${{ secrets.VPS_PORT }} ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} \ + "docker load" + + - name: Deploy to VPS + run: | + ssh -i ~/.ssh/deploy_key -p ${{ secrets.VPS_PORT }} ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} bash -s << 'ENDSSH' + set -e + export VERSION="${{ github.sha }}" + + # Tag the images + docker tag littleshop:$VERSION localhost:5000/littleshop:$VERSION + docker tag littleshop:$VERSION localhost:5000/littleshop:latest + docker tag telebot:$VERSION localhost:5000/telebot:$VERSION + docker tag telebot:$VERSION localhost:5000/telebot:latest + + # Push to local registry + echo "Pushing images to local Docker registry..." + docker push localhost:5000/littleshop:$VERSION || true + docker push localhost:5000/littleshop:latest || true + docker push localhost:5000/telebot:$VERSION || true + docker push localhost:5000/telebot:latest || true + + # Navigate to deployment directory + cd /opt/littleshop + + # Force stop all littleshop containers + echo "Stopping all littleshop containers..." + docker stop $(docker ps -q --filter "name=littleshop") 2>/dev/null || true + docker rm $(docker ps -aq --filter "name=littleshop") 2>/dev/null || true + + # Stop TeleBot container + echo "Stopping TeleBot container..." + docker stop telebot-service 2>/dev/null || true + docker rm telebot-service 2>/dev/null || true + + # Stop services with compose + echo "Stopping compose services..." + docker-compose down --remove-orphans || true + + # Prune unused Docker networks + echo "Cleaning up Docker networks..." + docker network prune -f || true + + # Apply database migrations if they exist + echo "Checking for database migrations..." + if [ -d "LittleShop/Migrations" ] && [ -n "$(ls -A LittleShop/Migrations/*.sql 2>/dev/null)" ]; then + echo "Found migration files, applying to database..." + for migration in LittleShop/Migrations/*.sql; do + migration_name=$(basename "$migration") + echo "Applying migration: $migration_name" + docker run --rm -v littleshop_littleshop_data:/data -v $(pwd)/LittleShop/Migrations:/migrations alpine:latest sh -c " + apk add --no-cache sqlite > /dev/null 2>&1 + echo 'Creating backup before migration...' + cp /data/littleshop-production.db /data/littleshop-production.db.backup-\$(date +%Y%m%d-%H%M%S) 2>/dev/null || true + echo 'Applying migration: $migration_name' + sqlite3 /data/littleshop-production.db < /migrations/$migration_name + echo 'Migration applied successfully' + " + done + else + echo "No migration files found, skipping..." + fi + + # Start services with new images + echo "Starting services with new images..." + docker-compose up -d + + # Start TeleBot with new image + echo "Starting TeleBot with new image..." + docker run -d \ + --name telebot-service \ + --restart unless-stopped \ + --network silverpay_silverpay-network \ + -e ASPNETCORE_URLS=http://+:5010 \ + -e LittleShop__ApiUrl=http://littleshop:5000 \ + -e LittleShop__UseTor=false \ + -e Privacy__EnableTor=true \ + -e Privacy__TorSocksHost=tor-gateway \ + -e Privacy__TorSocksPort=9050 \ + localhost:5000/telebot:latest + + # Connect TeleBot to LittleShop network + docker network connect littleshop_littleshop-network telebot-service + + # Wait for startup + echo "Waiting for services to start..." + sleep 30 + + # Health check + echo "Running health checks..." + for i in 1 2 3 4 5 6; do + if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then + echo "✅ Deployment successful - health check passed" + exit 0 + fi + echo "Health check attempt $i/6 failed, waiting..." + sleep 10 + done + + echo "❌ Health check failed after deployment" + docker logs littleshop --tail 50 + docker logs telebot-service --tail 30 + exit 1 + ENDSSH + + - name: Cleanup + if: always() + run: | + rm -f ~/.ssh/deploy_key + + deploy-preproduction: + name: Deploy to Pre-Production (CT109) + needs: [build-littleshop, build-telebot] + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/development' || github.ref == 'refs/heads/main' + environment: + name: pre-production + url: http://ct109.local + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download LittleShop image + uses: actions/download-artifact@v4 + with: + name: littleshop-image + path: /tmp/docker-images + + - name: Download TeleBot image + uses: actions/download-artifact@v4 + with: + name: telebot-image + path: /tmp/docker-images + + - name: Load Docker images + run: | + docker load < /tmp/docker-images/littleshop.tar.gz + docker load < /tmp/docker-images/telebot.tar.gz + + - name: Set up SSH for CT109 + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo "${{ secrets.CT109_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -p ${{ secrets.CT109_SSH_PORT }} ${{ secrets.CT109_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: Transfer Docker images to CT109 + run: | + echo "Copying LittleShop image to CT109..." + docker save littleshop:${{ github.sha }} | \ + ssh -i ~/.ssh/deploy_key -p ${{ secrets.CT109_SSH_PORT }} ${{ secrets.CT109_USER }}@${{ secrets.CT109_HOST }} \ + "docker load" + + echo "Copying TeleBot image to CT109..." + docker save telebot:${{ github.sha }} | \ + ssh -i ~/.ssh/deploy_key -p ${{ secrets.CT109_SSH_PORT }} ${{ secrets.CT109_USER }}@${{ secrets.CT109_HOST }} \ + "docker load" + + - name: Deploy to CT109 + run: | + ssh -i ~/.ssh/deploy_key -p ${{ secrets.CT109_SSH_PORT }} ${{ secrets.CT109_USER }}@${{ secrets.CT109_HOST }} bash -s << 'ENDSSH' + set -e + export VERSION="${{ github.sha }}" + + # Tag the images + docker tag littleshop:$VERSION littleshop:latest + docker tag telebot:$VERSION telebot:latest + + # Navigate to deployment directory + cd /opt/littleshop || mkdir -p /opt/littleshop && cd /opt/littleshop + + # Stop existing containers + echo "Stopping existing containers..." + docker stop littleshop telebot-service 2>/dev/null || true + docker rm littleshop telebot-service 2>/dev/null || true + + # Prune unused Docker networks + echo "Cleaning up Docker networks..." + docker network prune -f || true + + # Create networks if they don't exist + docker network create littleshop-network 2>/dev/null || true + docker network create silverpay-network 2>/dev/null || true + + # Start LittleShop container + echo "Starting LittleShop container..." + docker run -d \ + --name littleshop \ + --restart unless-stopped \ + --network littleshop-network \ + -p 5100:5000 \ + -v littleshop-data:/app/data \ + -e ASPNETCORE_URLS=http://+:5000 \ + -e ASPNETCORE_ENVIRONMENT=Development \ + littleshop:latest + + # Start TeleBot container + echo "Starting TeleBot container..." + docker run -d \ + --name telebot-service \ + --restart unless-stopped \ + --network silverpay-network \ + -e ASPNETCORE_URLS=http://+:5010 \ + -e LittleShop__ApiUrl=http://littleshop:5000 \ + -e LittleShop__UseTor=false \ + telebot:latest + + # Connect TeleBot to LittleShop network + docker network connect littleshop-network telebot-service + + # Wait for startup + echo "Waiting for services to start..." + sleep 15 + + # Health check + echo "Running health checks..." + for i in 1 2 3 4 5; do + if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then + echo "✅ Pre-production deployment successful - health check passed" + docker ps --filter "name=littleshop" --filter "name=telebot" + exit 0 + fi + echo "Health check attempt $i/5 failed, waiting..." + sleep 10 + done + + echo "❌ Health check failed after deployment" + echo "LittleShop logs:" + docker logs littleshop --tail 50 + echo "" + echo "TeleBot logs:" + docker logs telebot-service --tail 30 + exit 1 + ENDSSH + + - name: Cleanup + if: always() + run: | + rm -f ~/.ssh/deploy_key diff --git a/.gitea/workflows/rollback.yml b/.gitea/workflows/rollback.yml new file mode 100644 index 0000000..99a17ee --- /dev/null +++ b/.gitea/workflows/rollback.yml @@ -0,0 +1,111 @@ +name: Rollback Deployment + +on: + workflow_dispatch: + inputs: + environment: + description: 'Environment to rollback' + required: true + type: choice + options: + - production + - development + version: + description: 'Version/tag to rollback to (leave empty for previous)' + required: false + type: string + +jobs: + rollback: + name: Rollback to Previous Version + runs-on: ubuntu-latest + environment: + name: ${{ github.event.inputs.environment }} + steps: + - name: Set up SSH + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -p ${{ secrets.VPS_PORT }} ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: Rollback deployment + run: | + ssh -i ~/.ssh/deploy_key -p ${{ secrets.VPS_PORT }} ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} bash -s << 'ENDSSH' + set -e + cd /opt/littleshop + + VERSION="${{ github.event.inputs.version }}" + if [ -z "$VERSION" ]; then + echo "No version specified, using 'previous' tag" + # Tag previous version if it exists + docker tag localhost:5000/littleshop:previous localhost:5000/littleshop:latest || { + echo "❌ No previous version found to rollback to" + exit 1 + } + docker tag localhost:5000/telebot:previous localhost:5000/telebot:latest || { + echo "❌ No previous TeleBot version found to rollback to" + exit 1 + } + else + echo "Rolling back to version: $VERSION" + docker tag localhost:5000/littleshop:$VERSION localhost:5000/littleshop:latest || { + echo "❌ Version $VERSION not found for LittleShop" + exit 1 + } + docker tag localhost:5000/telebot:$VERSION localhost:5000/telebot:latest || { + echo "❌ Version $VERSION not found for TeleBot" + exit 1 + } + fi + + # Stop current containers + echo "Stopping current containers..." + docker-compose down --remove-orphans + docker stop telebot-service 2>/dev/null || true + docker rm telebot-service 2>/dev/null || true + + # Start with rolled back version + echo "Starting with previous version..." + docker-compose up -d + + # Start TeleBot + docker run -d \ + --name telebot-service \ + --restart unless-stopped \ + --network silverpay_silverpay-network \ + -e ASPNETCORE_URLS=http://+:5010 \ + -e LittleShop__ApiUrl=http://littleshop:5000 \ + -e LittleShop__UseTor=false \ + -e Privacy__EnableTor=true \ + -e Privacy__TorSocksHost=tor-gateway \ + -e Privacy__TorSocksPort=9050 \ + localhost:5000/telebot:latest + + docker network connect littleshop_littleshop-network telebot-service + + # Health check + echo "Waiting for services to start..." + sleep 30 + + echo "Running health checks..." + for i in 1 2 3 4 5 6; do + if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then + echo "✅ Rollback successful - health check passed" + exit 0 + fi + echo "Health check attempt $i/6 failed, waiting..." + sleep 10 + done + + echo "❌ Rollback health check failed" + docker logs littleshop --tail 50 + docker logs telebot-service --tail 30 + exit 1 + ENDSSH + + - name: Cleanup + if: always() + run: | + rm -f ~/.ssh/deploy_key diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 07d9ab4..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,219 +0,0 @@ -stages: - - build - - deploy - -variables: - DOCKER_HOST: unix:///var/run/docker.sock - -build:littleshop: - stage: build - image: docker:24 - script: - - echo "Building LittleShop Docker image" - - docker build -t localhost:5000/littleshop:latest . - - | - if [ -n "$CI_COMMIT_TAG" ]; then - echo "Tagging as version $CI_COMMIT_TAG" - docker tag localhost:5000/littleshop:latest localhost:5000/littleshop:$CI_COMMIT_TAG - fi - - echo "LittleShop build complete" - rules: - - if: '$CI_COMMIT_BRANCH == "main"' - - if: '$CI_COMMIT_TAG' - tags: - - docker - -build:telebot: - stage: build - image: docker:24 - script: - - echo "Building TeleBot Docker image" - - docker build -t localhost:5000/telebot:latest -f Dockerfile.telebot . - - | - if [ -n "$CI_COMMIT_TAG" ]; then - echo "Tagging as version $CI_COMMIT_TAG" - docker tag localhost:5000/telebot:latest localhost:5000/telebot:$CI_COMMIT_TAG - fi - - echo "TeleBot build complete" - rules: - - if: '$CI_COMMIT_BRANCH == "main"' - - if: '$CI_COMMIT_TAG' - tags: - - docker - -deploy:vps: - stage: deploy - image: docker:24 - before_script: - - apk add --no-cache openssh-client bash curl - - echo "$VPS_SSH_KEY_B64" | base64 -d > /tmp/deploy_key - - chmod 600 /tmp/deploy_key - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - ssh-keyscan -p "$VPS_PORT" "$VPS_HOST" >> ~/.ssh/known_hosts - script: - - export VERSION="${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}" - - echo "Deploying version $VERSION to VPS" - - echo "Building images from source..." - - docker build --no-cache -t littleshop:$VERSION . - - docker build --no-cache -t telebot:$VERSION -f Dockerfile.telebot . - - - echo "Copying images to VPS via SSH..." - - docker save littleshop:$VERSION | ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" "docker load" - - docker save telebot:$VERSION | ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" "docker load" - - - echo "Deploying on VPS..." - - | - ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" bash -s << EOF - set -e - export VERSION="$VERSION" - - # Tag the images - docker tag littleshop:\$VERSION localhost:5000/littleshop:\$VERSION - docker tag littleshop:\$VERSION localhost:5000/littleshop:latest - docker tag telebot:\$VERSION localhost:5000/telebot:\$VERSION - docker tag telebot:\$VERSION localhost:5000/telebot:latest - - # Push to local registry - echo "Pushing images to local Docker registry..." - docker push localhost:5000/littleshop:\$VERSION - docker push localhost:5000/littleshop:latest - docker push localhost:5000/telebot:\$VERSION - docker push localhost:5000/telebot:latest - - # Navigate to deployment directory - cd /opt/littleshop - - # Force stop all littleshop containers (including orphans) - echo "Stopping all littleshop containers..." - docker stop \$(docker ps -q --filter "name=littleshop") 2>/dev/null || true - docker rm \$(docker ps -aq --filter "name=littleshop") 2>/dev/null || true - - # Stop TeleBot container - echo "Stopping TeleBot container..." - docker stop telebot-service 2>/dev/null || true - docker rm telebot-service 2>/dev/null || true - - # Stop services with compose (removes networks) - echo "Stopping compose services..." - docker-compose down --remove-orphans || true - - # Prune unused Docker networks to avoid conflicts - echo "Cleaning up Docker networks..." - docker network prune -f || true - - # Apply database migrations if they exist - echo "Checking for database migrations..." - if [ -d "LittleShop/Migrations" ] && [ -n "\$(ls -A LittleShop/Migrations/*.sql 2>/dev/null)" ]; then - echo "Found migration files, applying to database..." - for migration in LittleShop/Migrations/*.sql; do - migration_name=\$(basename "\$migration") - echo "Applying migration: \$migration_name" - docker run --rm -v littleshop_littleshop_data:/data -v \$(pwd)/LittleShop/Migrations:/migrations alpine:latest sh -c " - apk add --no-cache sqlite > /dev/null 2>&1 - echo 'Creating backup before migration...' - cp /data/littleshop-production.db /data/littleshop-production.db.backup-\\\$(date +%Y%m%d-%H%M%S) 2>/dev/null || true - echo 'Applying migration: \$migration_name' - sqlite3 /data/littleshop-production.db < /migrations/\$migration_name - echo 'Migration applied successfully' - " - done - else - echo "No migration files found, skipping..." - fi - - # Start services with new images - echo "Starting services with new images..." - docker-compose up -d - - # Start TeleBot with new image - echo "Starting TeleBot with new image..." - docker run -d \ - --name telebot-service \ - --restart unless-stopped \ - --network silverpay_silverpay-network \ - -e ASPNETCORE_URLS=http://+:5010 \ - -e LittleShop__ApiUrl=http://littleshop:5000 \ - -e LittleShop__UseTor=false \ - -e Privacy__EnableTor=true \ - -e Privacy__TorSocksHost=tor-gateway \ - -e Privacy__TorSocksPort=9050 \ - localhost:5000/telebot:latest - - # Connect TeleBot to LittleShop network for API access - docker network connect littleshop_littleshop-network telebot-service - - # Wait for startup - echo "Waiting for services to start..." - sleep 30 - - # Health check - echo "Running health checks..." - for i in 1 2 3 4 5 6; do - if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then - echo "✅ Deployment successful - health check passed" - exit 0 - fi - echo "Health check attempt \$i/6 failed, waiting..." - sleep 10 - done - - echo "❌ Health check failed after deployment" - docker logs littleshop-admin --tail 50 - docker logs telebot-service --tail 30 - exit 1 - EOF - environment: - name: production - url: http://hq.lan - rules: - - if: '$CI_COMMIT_BRANCH == "main"' - when: on_success - - if: '$CI_COMMIT_TAG' - when: manual - tags: - - docker - -rollback:vps: - stage: deploy - image: alpine:latest - before_script: - - apk add --no-cache openssh-client bash - - echo "$VPS_SSH_KEY_B64" | base64 -d > /tmp/deploy_key - - chmod 600 /tmp/deploy_key - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - ssh-keyscan -p "$VPS_PORT" "$VPS_HOST" >> ~/.ssh/known_hosts - script: - - echo "Rolling back to previous version" - - | - ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" bash -s << EOF - set -e - cd /opt/littleshop - - # Pull previous image - docker tag localhost:5000/littleshop:previous localhost:5000/littleshop:latest - - # Restart services - echo "Restarting with previous version..." - docker-compose down - docker-compose up -d - - # Health check - sleep 30 - if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then - echo "✅ Rollback complete" - exit 0 - else - echo "❌ Rollback health check failed" - docker logs littleshop-admin --tail 50 - exit 1 - fi - EOF - environment: - name: production - rules: - - if: '$CI_COMMIT_TAG' - when: manual - tags: - - docker \ No newline at end of file diff --git a/CI_CD_CT109_PREPRODUCTION.md b/CI_CD_CT109_PREPRODUCTION.md new file mode 100644 index 0000000..bc8ca44 --- /dev/null +++ b/CI_CD_CT109_PREPRODUCTION.md @@ -0,0 +1,333 @@ +# CI/CD Pre-Production Deployment to CT109 + +**Date:** November 14, 2025 +**Status:** ✅ Configured + +## Overview + +Updated CI/CD pipeline to deploy to **CT109 Docker container** for pre-production testing instead of automatic production deployment. + +## Changes Made + +### 1. Disabled Automatic Production Deployment ❌ +- **deploy-production job:** Changed to `if: false` - **DISABLED** +- Production deployment now **requires manual approval** +- Prevents accidental deployments to production VPS + +### 2. Created Pre-Production Deployment to CT109 ✅ +- **New job:** `deploy-preproduction` +- **Target:** CT109 Docker LXC container +- **Triggers:** + - Push to `development` branch → Auto-deploy + - Push to `main` branch → Auto-deploy (for testing before production) + +## Deployment Architecture + +``` +Gitea Actions Runner + ↓ Build Docker Images + ↓ Transfer via SSH + ↓ +┌─────────────────────────────────────┐ +│ CT109 - Docker LXC Container │ +│ (Pre-Production Environment) │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ littleshop container │ │ +│ │ Port: 5100 → 5000 │ │ +│ │ Volume: littleshop-data │ │ +│ │ Network: littleshop-network │ │ +│ └──────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────┐ │ +│ │ telebot-service container │ │ +│ │ Port: 5010 │ │ +│ │ Networks: │ │ +│ │ - littleshop-network │ │ +│ │ - silverpay-network │ │ +│ └──────────────────────────────┘ │ +└─────────────────────────────────────┘ +``` + +## Required Secrets in Gitea + +Navigate to: **Repository → Settings → Secrets** and add: + +### CT109 Connection Secrets + +``` +CT109_HOST → IP address or hostname of CT109 (e.g., 10.0.0.51 or ct109.local) +CT109_SSH_PORT → SSH port (typically 22) +CT109_USER → SSH username (typically sysadmin or docker-user) +CT109_SSH_KEY → SSH private key for authentication +``` + +### Example Configuration + +```yaml +# Secret Name: CT109_HOST +# Value: 10.0.0.51 + +# Secret Name: CT109_SSH_PORT +# Value: 22 + +# Secret Name: CT109_USER +# Value: sysadmin + +# Secret Name: CT109_SSH_KEY +# Value: -----BEGIN OPENSSH PRIVATE KEY----- +# +# -----END OPENSSH PRIVATE KEY----- +``` + +## CT109 Container Setup Requirements + +### 1. Docker Installed in CT109 +Ensure Docker is installed and running: + +```bash +# SSH into Proxmox host +ssh root@proxmox + +# Enter CT109 container +pct enter 109 + +# Verify Docker is installed +docker --version + +# If not installed: +apt update +apt install -y docker.io docker-compose +systemctl enable docker +systemctl start docker +``` + +### 2. Create Deployment Directory + +```bash +mkdir -p /opt/littleshop +cd /opt/littleshop +``` + +### 3. SSH Access Setup + +Generate SSH key pair for deployment (on your workstation): + +```bash +ssh-keygen -t ed25519 -C "gitea-actions-ct109" -f ~/.ssh/gitea_ct109_key +``` + +Copy public key to CT109: + +```bash +ssh-copy-id -i ~/.ssh/gitea_ct109_key.pub sysadmin@10.0.0.51 +``` + +Add private key to Gitea secrets: + +```bash +cat ~/.ssh/gitea_ct109_key +# Copy output to CT109_SSH_KEY secret in Gitea +``` + +## Deployment Process + +### On Push to `development` or `main`: + +1. **Build Phase** (Gitea Actions runner) + - Builds LittleShop Docker image + - Builds TeleBot Docker image + - Creates artifacts + +2. **Transfer Phase** (SSH to CT109) + - Transfers Docker images via SSH pipe + - Loads images into CT109 Docker + +3. **Deploy Phase** (Inside CT109) + - Stops existing containers + - Creates/verifies Docker networks + - Starts LittleShop container (port 5100) + - Starts TeleBot container (port 5010) + - Connects containers via networks + - Runs health checks + +## Access URLs + +After deployment, access the pre-production environment: + +### From LAN: +- **Admin Panel:** `http://ct109.local:5100/Admin` +- **API:** `http://ct109.local:5100/api` +- **Health Check:** `http://ct109.local:5100/api/catalog/products` + +### From Proxmox Host: +- **Admin Panel:** `http://10.0.0.51:5100/Admin` +- **API:** `http://10.0.0.51:5100/api` + +## Testing the Pre-Production Deployment + +### 1. Push to Development Branch + +```bash +git checkout development +git add . +git commit -m "test: Pre-production deployment to CT109" +git push origin development +``` + +### 2. Monitor Deployment + +In Gitea: +- Navigate to **Repository → Actions** +- Click on the running workflow +- Watch the `deploy-preproduction` job logs + +### 3. Verify Deployment + +```bash +# SSH into CT109 +ssh sysadmin@10.0.0.51 + +# Check running containers +docker ps + +# Check container logs +docker logs littleshop --tail 50 +docker logs telebot-service --tail 50 + +# Test API +curl http://localhost:5100/api/catalog/products +``` + +### 4. Access Admin Panel + +Open browser: `http://ct109.local:5100/Admin` + +## Troubleshooting + +### Issue: "Permission denied (publickey)" + +**Solution:** Verify SSH key is correctly added to Gitea secrets + +```bash +# Test SSH connection manually +ssh -i ~/.ssh/gitea_ct109_key sysadmin@10.0.0.51 + +# Verify key permissions +chmod 600 ~/.ssh/gitea_ct109_key +``` + +### Issue: "docker: command not found" + +**Solution:** Install Docker in CT109 container + +```bash +pct enter 109 +apt update +apt install -y docker.io +systemctl start docker +``` + +### Issue: "Cannot connect to Docker daemon" + +**Solution:** Enable Docker features in Proxmox container + +```bash +# On Proxmox host +pct set 109 -features nesting=1,keyctl=1 +pct stop 109 +pct start 109 +``` + +### Issue: Health check fails + +**Solution:** Check container logs and network connectivity + +```bash +# Inside CT109 +docker logs littleshop --tail 100 +docker logs telebot-service --tail 100 + +# Test internal connectivity +docker exec littleshop curl http://localhost:5000/api/catalog/products + +# Check networks +docker network ls +docker network inspect littleshop-network +``` + +## Production Deployment (Manual Only) + +Production deployment to VPS (srv1002428.hstgr.cloud) is **disabled by default**. + +To deploy to production: + +1. **Option A: Manual Workflow Trigger** + - Navigate to **Repository → Actions → Workflows** + - Select "Build and Deploy LittleShop" + - Click "Run Workflow" + - *(Note: deploy-production job is currently disabled)* + +2. **Option B: SSH Deployment** + - Use manual SSH deployment to VPS + - Follow production deployment guide in `CI_CD_MIGRATION_GITEA.md` + +## Rollback + +If pre-production deployment fails, rollback is automatic (old containers remain running). + +For manual rollback: + +```bash +# SSH into CT109 +ssh sysadmin@10.0.0.51 + +# List available images +docker images | grep littleshop +docker images | grep telebot + +# Stop current containers +docker stop littleshop telebot-service +docker rm littleshop telebot-service + +# Start previous version +docker run -d --name littleshop ... littleshop: +docker run -d --name telebot-service ... telebot: +``` + +## Next Steps + +### 1. Configure Secrets ⏳ +- [ ] Add `CT109_HOST` secret to Gitea +- [ ] Add `CT109_SSH_PORT` secret to Gitea +- [ ] Add `CT109_USER` secret to Gitea +- [ ] Add `CT109_SSH_KEY` secret to Gitea + +### 2. Configure CT109 Environment ⏳ +- [ ] Create `pre-production` environment in Gitea +- [ ] Set environment URL: `http://ct109.local:5100` + +### 3. Test Deployment ⏳ +- [ ] Push to `development` branch +- [ ] Verify build jobs complete +- [ ] Verify deployment to CT109 succeeds +- [ ] Access admin panel at `http://ct109.local:5100/Admin` +- [ ] Test functionality in pre-production + +### 4. Production Deployment Strategy +- [ ] After testing in CT109, manually deploy to production VPS +- [ ] Consider re-enabling production deployment with approval workflow +- [ ] Update production deployment documentation + +## Summary + +✅ **Production deployment disabled** - No automatic deployments to VPS +✅ **Pre-production deployment created** - Auto-deploy to CT109 on push +✅ **Simplified workflow** - Faster testing in isolated Docker environment +✅ **Manual production control** - Deploy to VPS only when ready + +--- + +**Pre-production environment configured successfully! 🎉** + +All pushes to `development` and `main` branches will now deploy to CT109 for testing before manual production deployment. diff --git a/CI_CD_MIGRATION_GITEA.md b/CI_CD_MIGRATION_GITEA.md new file mode 100644 index 0000000..50009d1 --- /dev/null +++ b/CI_CD_MIGRATION_GITEA.md @@ -0,0 +1,291 @@ +# CI/CD Migration: GitLab → Gitea Actions + +**Date:** November 14, 2025 +**Status:** ✅ Complete + +## Overview + +Successfully migrated from GitLab CI/CD to Gitea Actions for the LittleShop project. + +## Changes Made + +### 1. Removed GitLab CI/CD Configuration +- ❌ Deleted: `.gitlab-ci.yml` (main project) +- ❌ Deleted: `TeleBot/.gitlab-ci.yml` (TeleBot subproject) + +### 2. Created Gitea Actions Workflows +- ✅ Created: `.gitea/workflows/build-and-deploy.yml` - Main CI/CD pipeline +- ✅ Created: `.gitea/workflows/rollback.yml` - Manual rollback workflow +- ✅ Created: `.gitea/workflows/README.md` - Comprehensive documentation + +### 3. Updated Git Remote +- ✅ **Fetch URL:** `https://70ec152b27ee12d8a2cfb7241df5735351df72cd@git.silverlabs.uk/Jamie/littleshop.git` +- ✅ **Push URL:** `https://70ec152b27ee12d8a2cfb7241df5735351df72cd@git.silverlabs.uk/Jamie/littleshop.git` + +## Workflow Features + +### Build and Deploy Workflow + +**Triggers:** +- Push to `main` → Auto-deploy to production +- Push to `development` → Auto-deploy to development +- Push tags (`v*`) → Tagged release +- Manual trigger via UI + +**Jobs:** +1. **build-littleshop** - Builds LittleShop Docker image +2. **build-telebot** - Builds TeleBot Docker image +3. **deploy-production** - Deploys to production VPS (requires both build jobs) +4. **deploy-development** - Deploys to development environment + +**Key Features:** +- Parallel Docker builds for faster CI +- Artifact-based image transfer between jobs +- Automatic database migration application +- Health check validation +- Comprehensive deployment logging +- SSH-based VPS deployment + +### Rollback Workflow + +**Trigger:** Manual only + +**Features:** +- Choose environment (production/development) +- Specify version or rollback to previous +- Automatic health checks after rollback + +## Required Configuration + +### Repository Secrets (Gitea) + +Navigate to: **Repository → Settings → Secrets** + +Add the following secrets: + +``` +VPS_HOST: srv1002428.hstgr.cloud +VPS_PORT: 2255 +VPS_USER: sysadmin +VPS_SSH_KEY: +``` + +### Environment Configuration + +Navigate to: **Repository → Settings → Environments** + +#### Production Environment +- **Name:** `production` +- **URL:** `https://admin.dark.side` +- **Protection:** Require approval (optional) + +#### Development Environment +- **Name:** `development` +- **URL:** + +## Migration Benefits + +### ✅ Advantages Over GitLab CI/CD + +1. **Native Integration:** First-class support in Gitea UI +2. **GitHub Actions Syntax:** Industry-standard workflow format +3. **Better Artifact Handling:** Native artifact storage in Gitea +4. **Cleaner Workflow UI:** Better visualization in Gitea Actions tab +5. **Environment Management:** Built-in environment protection rules +6. **Manual Triggers:** Easy workflow_dispatch for manual runs + +### 🔄 No Changes Required + +The following remain unchanged: +- ✅ VPS deployment scripts (identical logic) +- ✅ Docker network configuration +- ✅ Database migration process +- ✅ Health check endpoints +- ✅ Container names and ports +- ✅ Nginx reverse proxy setup + +## Deployment Architecture + +``` +┌────────────────────────────────────────────┐ +│ Gitea Actions Runner │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ LittleShop │ │ TeleBot │ │ +│ │ Build │ │ Build │ │ +│ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ +│ └────────┬────────┘ │ +│ ▼ │ +│ ┌────────────────┐ │ +│ │Upload Artifacts│ │ +│ └────────┬───────┘ │ +└──────────────────┼────────────────────────┘ + │ SSH Transfer + ▼ +┌─────────────────────────────────────────────┐ +│ Production VPS (Hostinger) │ +│ │ +│ ┌────────────────────────────────────────┐ │ +│ │ Docker Registry (localhost:5000) │ │ +│ │ - littleshop:latest, littleshop: │ │ +│ │ - telebot:latest, telebot: │ │ +│ └────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ LittleShop │ │ TeleBot │ │ +│ │ Container │ │ Container │ │ +│ │ Port: 5100 │ │ Port: 5010 │ │ +│ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ +│ ┌──────┴────────────────┴────────┐ │ +│ │ Docker Networks: │ │ +│ │ - littleshop_littleshop- │ │ +│ │ network │ │ +│ │ - silverpay_silverpay- │ │ +│ │ network │ │ +│ └────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────┐ │ +│ │ Nginx Proxy Manager │ │ +│ │ https://admin.dark.side │ │ +│ └────────────────────────────────┘ │ +└─────────────────────────────────────────────┘ +``` + +## Testing the Migration + +### 1. Verify Gitea Actions Runner + +Ensure your Gitea instance has Actions enabled: + +```bash +# Check Gitea configuration +# In app.ini or via Gitea admin panel +[actions] +ENABLED = true +``` + +### 2. Test Build Workflow + +Push to a test branch to trigger workflow: + +```bash +git checkout -b test-gitea-actions +git add .gitea/ +git commit -m "feat: Migrate to Gitea Actions" +git push origin test-gitea-actions +``` + +Check Gitea UI: **Repository → Actions → Workflows** + +### 3. Monitor First Deployment + +Watch the deployment progress: +1. Navigate to Gitea Actions tab +2. Select the running workflow +3. Monitor each job's logs in real-time +4. Verify health checks pass + +## Rollback Plan + +If issues occur with Gitea Actions: + +### Option 1: Restore GitLab CI/CD (Emergency) + +```bash +# Restore .gitlab-ci.yml from Git history +git checkout HEAD~1 -- .gitlab-ci.yml TeleBot/.gitlab-ci.yml +git add .gitlab-ci.yml TeleBot/.gitlab-ci.yml +git commit -m "Rollback to GitLab CI/CD" +``` + +### Option 2: Manual Deployment + +```bash +# Connect to VPS +ssh -p 2255 sysadmin@srv1002428.hstgr.cloud + +# Manual deployment +cd /opt/littleshop +docker-compose down +docker-compose pull +docker-compose up -d +``` + +## Next Steps + +### 1. Configure Repository Secrets ⏳ +- [ ] Add VPS_HOST to Gitea repository secrets +- [ ] Add VPS_PORT to Gitea repository secrets +- [ ] Add VPS_USER to Gitea repository secrets +- [ ] Add VPS_SSH_KEY to Gitea repository secrets + +### 2. Configure Environments ⏳ +- [ ] Create `production` environment in Gitea +- [ ] Set production URL: `https://admin.dark.side` +- [ ] Create `development` environment (optional) + +### 3. Test Deployment ⏳ +- [ ] Push to `development` branch for test deployment +- [ ] Verify build jobs complete successfully +- [ ] Verify deployment completes with health checks +- [ ] Test rollback workflow manually + +### 4. Deploy to Production ⏳ +- [ ] Merge security fixes to `main` branch +- [ ] Monitor automated production deployment +- [ ] Verify application health after deployment + +## Troubleshooting + +### Issue: "Actions disabled for this repository" + +**Solution:** Enable Actions in Gitea repository settings or instance configuration. + +```bash +# In Gitea app.ini +[actions] +ENABLED = true +DEFAULT_ACTIONS_URL = https://github.com # For using GitHub marketplace actions +``` + +### Issue: "No runners available" + +**Solution:** Register a Gitea Actions runner. + +```bash +# Download act_runner +wget https://dl.gitea.com/act_runner/latest/act_runner-linux-amd64 +chmod +x act_runner-linux-amd64 + +# Register runner with Gitea +./act_runner-linux-amd64 register --instance https://git.silverlabs.uk --token + +# Run as service +./act_runner-linux-amd64 daemon +``` + +### Issue: "Secret not found" + +**Solution:** Verify secrets are set correctly in repository settings. + +Navigate to: **Repository → Settings → Secrets** and add missing secrets. + +## Documentation + +- **Workflow Documentation:** `.gitea/workflows/README.md` +- **Build Workflow:** `.gitea/workflows/build-and-deploy.yml` +- **Rollback Workflow:** `.gitea/workflows/rollback.yml` + +## References + +- [Gitea Actions Documentation](https://docs.gitea.io/en-us/actions/) +- [GitHub Actions Syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) +- [Docker Build Push Action](https://github.com/docker/build-push-action) + +--- + +**Migration completed successfully! 🎉** + +All GitLab CI/CD functionality has been replicated in Gitea Actions with improved workflow management and native Gitea integration. diff --git a/GITEA_SECRETS_SETUP_GUIDE.md b/GITEA_SECRETS_SETUP_GUIDE.md new file mode 100644 index 0000000..29fbd58 --- /dev/null +++ b/GITEA_SECRETS_SETUP_GUIDE.md @@ -0,0 +1,357 @@ +# Gitea Secrets Setup Guide for CT109 Deployment + +**Date:** November 14, 2025 + +## ⚠️ Prerequisites - CT109 SSH Access Setup Required + +### Issues Identified: + +1. **Port 21 Connection Refused** - Port 21 is FTP, not SSH +2. **SSH Key Not Authorized** - The `silverlabs` key is not authorized on CT109 + +### Before Adding Secrets, Fix SSH Access: + +#### Option A: Add SSH Key to CT109 + +```bash +# Copy the public key to CT109 +ssh-copy-id -i ~/.ssh/silverlabs.pub sysadmin@10.0.0.51 + +# Or manually add it: +cat ~/.ssh/silverlabs.pub | ssh sysadmin@10.0.0.51 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" +``` + +#### Option B: Generate New Deployment Key + +```bash +# Generate a new SSH key specifically for CI/CD +ssh-keygen -t ed25519 -C "gitea-actions-ct109" -f ~/.ssh/littleshop_ct109_key + +# Copy to CT109 +ssh-copy-id -i ~/.ssh/littleshop_ct109_key.pub sysadmin@10.0.0.51 + +# Test connection +ssh -i ~/.ssh/littleshop_ct109_key sysadmin@10.0.0.51 "echo 'Success!' && docker --version" +``` + +#### Verify Correct SSH Port + +```bash +# Test different ports +ssh -p 22 sysadmin@10.0.0.51 # Standard SSH port +ssh -p 2222 sysadmin@10.0.0.51 # Common alternative +ssh -p 22000 sysadmin@10.0.0.51 # Another common alternative + +# Or check from Proxmox: +pct enter 109 +ss -tlnp | grep ssh +# This will show the actual SSH port +``` + +--- + +## 📋 Gitea Secrets Configuration + +Once SSH access is working, add these secrets to Gitea. + +### Method 1: Via Gitea Web UI (Recommended) + +#### Step 1: Navigate to Repository Settings + +1. Go to: `https://git.silverlabs.uk/Jamie/littleshop` +2. Click **Settings** (gear icon) +3. Click **Secrets** in the left sidebar + +#### Step 2: Add Secrets + +Click **Add Secret** for each of the following: + +**Secret 1: CT109_HOST** +``` +Name: CT109_HOST +Value: 10.0.0.51 +``` + +**Secret 2: CT109_SSH_PORT** +``` +Name: CT109_SSH_PORT +Value: 22 +``` +*(Adjust this value based on the actual SSH port you verified above)* + +**Secret 3: CT109_USER** +``` +Name: CT109_USER +Value: sysadmin +``` + +**Secret 4: CT109_SSH_KEY** +``` +Name: CT109_SSH_KEY +Value: +``` + +To get the private key content: + +```bash +# If using existing silverlabs key: +cat ~/.ssh/silverlabs + +# If you generated a new key: +cat ~/.ssh/littleshop_ct109_key +``` + +Copy the entire output including: +- `-----BEGIN OPENSSH PRIVATE KEY-----` +- All the encoded content +- `-----END OPENSSH PRIVATE KEY-----` + +--- + +### Method 2: Via Gitea API (Advanced) + +```bash +# Set variables +GITEA_URL="https://git.silverlabs.uk" +GITEA_TOKEN="70ec152b27ee12d8a2cfb7241df5735351df72cd" +REPO_OWNER="Jamie" +REPO_NAME="littleshop" + +# Read SSH key into variable +SSH_KEY=$(cat ~/.ssh/silverlabs) + +# Add CT109_HOST +curl -X POST "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/actions/secrets/CT109_HOST" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"data": "10.0.0.51"}' + +# Add CT109_SSH_PORT +curl -X POST "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/actions/secrets/CT109_SSH_PORT" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"data": "22"}' + +# Add CT109_USER +curl -X POST "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/actions/secrets/CT109_USER" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"data": "root"}' + +# Add CT109_SSH_KEY +curl -X POST "$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/actions/secrets/CT109_SSH_KEY" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"data\": $(jq -Rs . <<< "$SSH_KEY")}" +``` + +--- + +## 🔧 CT109 Docker Container Setup + +Ensure CT109 has Docker installed and configured: + +```bash +# SSH into CT109 +ssh sysadmin@10.0.0.51 + +# Install Docker (if not already installed) +apt update +apt install -y docker.io docker-compose + +# Enable and start Docker +systemctl enable docker +systemctl start docker + +# Verify Docker is working +docker --version +docker ps + +# Create deployment directory +mkdir -p /opt/littleshop +cd /opt/littleshop + +# Test Docker can run +docker run --rm hello-world +``` + +### Enable Docker in Proxmox LXC Container + +If Docker isn't working in CT109, enable nesting on the Proxmox host: + +```bash +# On Proxmox host (not inside CT109) +pct set 109 -features nesting=1,keyctl=1 +pct stop 109 +pct start 109 +``` + +--- + +## ✅ Verification Steps + +### 1. Test SSH Connection from Gitea Actions + +Create a test workflow to verify secrets are working: + +```yaml +# .gitea/workflows/test-secrets.yml +name: Test CT109 Connection + +on: + workflow_dispatch: + +jobs: + test-connection: + runs-on: ubuntu-latest + steps: + - name: Test SSH Connection + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo "${{ secrets.CT109_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + + ssh -i ~/.ssh/deploy_key \ + -p ${{ secrets.CT109_SSH_PORT }} \ + -o StrictHostKeyChecking=no \ + ${{ secrets.CT109_USER }}@${{ secrets.CT109_HOST }} \ + "echo 'Connection successful!' && docker --version" + + rm ~/.ssh/deploy_key +``` + +Run this workflow manually to test the connection. + +### 2. Verify All Secrets Are Set + +In Gitea UI, navigate to: +`https://git.silverlabs.uk/Jamie/littleshop/settings/secrets` + +You should see all 4 secrets listed: +- ✅ CT109_HOST +- ✅ CT109_SSH_PORT +- ✅ CT109_USER +- ✅ CT109_SSH_KEY + +### 3. Test Full Deployment + +Once secrets are verified: + +```bash +# Push to development branch +git checkout development +git add . +git commit -m "test: Verify CT109 deployment" +git push origin development +``` + +Watch the deployment in Gitea Actions: +`https://git.silverlabs.uk/Jamie/littleshop/actions` + +--- + +## 🔍 Troubleshooting + +### Issue: "Permission denied (publickey)" + +**Solution:** SSH key not authorized on CT109 + +```bash +# Add your SSH public key to CT109 +ssh-copy-id -i ~/.ssh/silverlabs.pub sysadmin@10.0.0.51 + +# Or manually: +ssh sysadmin@10.0.0.51 +mkdir -p ~/.ssh +chmod 700 ~/.ssh +echo "YOUR_PUBLIC_KEY_HERE" >> ~/.ssh/authorized_keys +chmod 600 ~/.ssh/authorized_keys +``` + +### Issue: "Connection refused" on port 21 + +**Solution:** Port 21 is FTP, not SSH. Find the correct SSH port: + +```bash +# Check from Proxmox host +pct exec 109 -- ss -tlnp | grep ssh + +# Or try common SSH ports +ssh -p 22 sysadmin@10.0.0.51 # Standard +ssh -p 2222 sysadmin@10.0.0.51 # Alternative +ssh -p 22000 sysadmin@10.0.0.51 # Another common port +``` + +### Issue: "docker: command not found" in CT109 + +**Solution:** Install Docker in the container + +```bash +ssh sysadmin@10.0.0.51 +apt update +apt install -y docker.io +systemctl enable --now docker +``` + +### Issue: Docker not starting - "Cannot connect to daemon" + +**Solution:** Enable nesting in Proxmox + +```bash +# On Proxmox host +pct set 109 -features nesting=1,keyctl=1 +pct stop 109 +pct start 109 +``` + +### Issue: Secrets not visible in Gitea Actions + +**Solution:** Ensure repository exists and Actions are enabled + +```bash +# Create repository first (if needed) +# Via Gitea UI: New Repository → "littleshop" + +# Or push to create: +git push -u origin development +``` + +--- + +## 📝 Summary + +**Before secrets can be added:** +1. ✅ Fix SSH access to CT109 +2. ✅ Verify correct SSH port +3. ✅ Ensure Docker is installed in CT109 +4. ✅ Create littleshop repository in Gitea (if not exists) + +**Then add secrets via Gitea UI:** +- CT109_HOST: `10.0.0.51` +- CT109_SSH_PORT: `22` (or actual port) +- CT109_USER: `root` +- CT109_SSH_KEY: `` + +**Finally test deployment:** +```bash +git push origin development +``` + +--- + +## 🔐 Security Best Practices + +1. **Use dedicated deployment key** instead of your personal SSH key +2. **Restrict key permissions** on CT109: + ```bash + # In CT109's /root/.ssh/authorized_keys, prefix the key with: + command="docker ps",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... + ``` +3. **Rotate keys regularly** - regenerate deployment keys every 90 days +4. **Monitor deployment logs** in Gitea Actions for suspicious activity +5. **Use separate keys** for each environment (development, staging, production) + +--- + +**Next Steps:** Fix SSH access to CT109, then add secrets via Gitea UI! 🚀 diff --git a/TeleBot/.gitlab-ci.yml b/TeleBot/.gitlab-ci.yml deleted file mode 100644 index 36031d4..0000000 --- a/TeleBot/.gitlab-ci.yml +++ /dev/null @@ -1,61 +0,0 @@ -variables: - DOCKER_HOST: unix:///var/run/docker.sock - -stages: - - build - - deploy - -build: - stage: build - image: docker:24 - script: - - docker build -f TeleBot/Dockerfile -t localhost:5000/telebot:latest ../ - - docker tag localhost:5000/telebot:latest localhost:5000/telebot:$CI_COMMIT_SHORT_SHA - - docker push localhost:5000/telebot:latest - - docker push localhost:5000/telebot:$CI_COMMIT_SHORT_SHA - rules: - - if: '$CI_COMMIT_BRANCH == "main"' - - if: '$CI_COMMIT_TAG' - -deploy:vps: - stage: deploy - image: docker:24 - before_script: - - apk add --no-cache openssh-client bash curl - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo "$VPS_SSH_KEY_B64" | base64 -d > /tmp/deploy_key - - chmod 600 /tmp/deploy_key - - ssh-keyscan -p "$VPS_PORT" "$VPS_HOST" >> ~/.ssh/known_hosts 2>/dev/null - script: - - | - # Save and transfer Docker image - docker save localhost:5000/telebot:latest | ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" "docker load" - - # Deploy on VPS - ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" bash -s << 'EOF' - cd /opt/telebot - docker-compose down - docker-compose up -d - - # Health check - for i in 1 2 3 4 5 6; do - if pgrep -f "dotnet.*TeleBot" > /dev/null 2>&1; then - echo "✅ TeleBot deployment successful" - exit 0 - fi - echo "Waiting for TeleBot to start... ($i/6)" - sleep 10 - done - - echo "❌ TeleBot deployment failed - health check timeout" - docker-compose logs --tail=50 - exit 1 - EOF - rules: - - if: '$CI_COMMIT_BRANCH == "main"' - when: on_success - - if: '$CI_COMMIT_TAG' - when: manual - after_script: - - rm -f /tmp/deploy_key \ No newline at end of file