From b5443ddceeb54d9282ddc07bb4e950a8d0c36783 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 12 Dec 2025 01:06:06 +0800 Subject: [PATCH 01/33] add Docker configuration files and deployment guide --- .dockerignore | 18 +++++ .env.docker | 13 ++++ Dockerfile | 61 +++++++++++++++++ README-DOCKER.md | 165 +++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 24 +++++++ 5 files changed, 281 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.docker create mode 100644 Dockerfile create mode 100644 README-DOCKER.md create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..434a391 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +.git +.gitignore +.env +vendor +node_modules +storage/logs/* +storage/framework/cache/* +storage/framework/sessions/* +storage/framework/views/* +bootstrap/cache/* +tests +.editorconfig +.phpunit.result.cache +phpunit.xml +readme.md +docker-compose.yml +Dockerfile +.dockerignore diff --git a/.env.docker b/.env.docker new file mode 100644 index 0000000..e56d3f7 --- /dev/null +++ b/.env.docker @@ -0,0 +1,13 @@ +# Docker Environment Variables +# Copy this file and configure for your external MySQL database + +# Database Configuration - Update these to connect to your external MySQL +DB_HOST=your-mysql-host +DB_PORT=3306 +DB_DATABASE=merchbay_admin +DB_USERNAME=your-mysql-user +DB_PASSWORD=your-mysql-password + +# Application Configuration +APP_ENV=production +APP_DEBUG=false diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2414610 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,61 @@ +# Use PHP 7.4 with Apache (compatible with Laravel 5.2 and ARM64) +FROM php:7.4-apache + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + git \ + curl \ + libpng-dev \ + libonig-dev \ + libxml2-dev \ + libzip-dev \ + zip \ + unzip \ + libfreetype6-dev \ + libjpeg62-turbo-dev \ + openssh-client \ + && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install -j$(nproc) gd + +# Install PHP extensions +RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath zip + +# Enable Apache mod_rewrite +RUN a2enmod rewrite + +# Install Composer +COPY --from=composer:1.10 /usr/bin/composer /usr/bin/composer + +# Set working directory +WORKDIR /var/www/html + +# Copy existing application directory contents +COPY . /var/www/html + +# Copy existing application directory permissions +RUN chown -R www-data:www-data /var/www/html \ + && chmod -R 755 /var/www/html/storage \ + && chmod -R 755 /var/www/html/bootstrap/cache + +# Create .env file if it doesn't exist +RUN if [ ! -f .env ]; then cp .env.example .env; fi + +# Install PHP dependencies without running post-install scripts +RUN composer install --no-dev --no-scripts --no-interaction + +# Generate application key +RUN php artisan key:generate + +# Optimize autoloader +RUN composer dump-autoload --optimize --no-dev + +# Configure Apache DocumentRoot to point to Laravel's public directory +ENV APACHE_DOCUMENT_ROOT=/var/www/html/public +RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf +RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf + +# Expose port 80 +EXPOSE 80 + +# Start Apache +CMD ["apache2-foreground"] diff --git a/README-DOCKER.md b/README-DOCKER.md new file mode 100644 index 0000000..7aeba46 --- /dev/null +++ b/README-DOCKER.md @@ -0,0 +1,165 @@ +# Docker Deployment Guide for MerchBay Admin + +## Prerequisites + +- Docker installed on your system +- Docker Compose installed on your system + +## Quick Start + +### 1. Build and Start Containers + +```bash +docker-compose up -d --build +``` + +This will: +- Build the application container +- Start MySQL database +- Start PHPMyAdmin +- Set up networking between containers + +### 2. Access the Application + +- **Application**: http://localhost:8080 +- **PHPMyAdmin**: http://localhost:8081 + +### 3. Run Database Migrations + +```bash +docker-compose exec app php artisan migrate +``` + +### 4. Seed Database (if needed) + +```bash +docker-compose exec app php artisan db:seed +``` + +## Useful Commands + +### View Container Logs + +```bash +docker-compose logs -f app +``` + +### Access Container Shell + +```bash +docker-compose exec app bash +``` + +### Stop Containers + +```bash +docker-compose down +``` + +### Stop and Remove Volumes (Clean Slate) + +```bash +docker-compose down -v +``` + +### Rebuild Containers + +```bash +docker-compose up -d --build --force-recreate +``` + +### Run Artisan Commands + +```bash +docker-compose exec app php artisan [command] +``` + +### Clear Laravel Cache + +```bash +docker-compose exec app php artisan cache:clear +docker-compose exec app php artisan config:clear +docker-compose exec app php artisan route:clear +docker-compose exec app php artisan view:clear +``` + +### Install/Update Composer Dependencies + +```bash +docker-compose exec app composer install +# or +docker-compose exec app composer update +``` + +## Environment Configuration + +Edit the `docker-compose.yml` file to customize: +- Database credentials +- Port mappings +- Environment variables + +For production deployment, update the `APP_ENV` and `APP_DEBUG` values: + +```yaml +environment: + - APP_ENV=production + - APP_DEBUG=false +``` + +## Database Connection + +The application connects to the MySQL container using these credentials (defined in docker-compose.yml): + +- **Host**: db +- **Database**: merchbay_admin +- **Username**: merchbay_user +- **Password**: merchbay_password + +## Troubleshooting + +### Permission Issues + +If you encounter permission errors: + +```bash +docker-compose exec app chown -R www-data:www-data /var/www/html/storage +docker-compose exec app chmod -R 755 /var/www/html/storage +``` + +### Database Connection Issues + +Ensure the database container is fully started: + +```bash +docker-compose logs db +``` + +Wait a few seconds after starting containers for MySQL to initialize. + +### Port Already in Use + +If ports 8080 or 3306 are already in use, modify the ports in `docker-compose.yml`: + +```yaml +ports: + - "8090:80" # Change 8080 to 8090 or any available port +``` + +## Production Deployment + +For production environments: + +1. Update `.env` file with production settings +2. Set `APP_DEBUG=false` in docker-compose.yml +3. Use a secure database password +4. Consider using a reverse proxy (Nginx/Traefik) with SSL +5. Set up proper backup strategies for database volumes +6. Configure log rotation + +## Volumes + +- `db_data`: Persistent MySQL data +- `./storage`: Laravel storage (logs, cache, sessions) +- `./public/uploads`: User uploaded files + +These volumes ensure data persists across container restarts. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..83c916a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3.8' + +services: + app: + build: + context: . + dockerfile: Dockerfile + container_name: merchbay_admin_app + restart: unless-stopped + ports: + - "8080:80" + environment: + - APP_ENV=production + - APP_DEBUG=false + - DB_CONNECTION=mysql + - DB_HOST=${DB_HOST:-localhost} + - DB_PORT=${DB_PORT:-3306} + - DB_DATABASE=${DB_DATABASE:-merchbay_admin} + - DB_USERNAME=${DB_USERNAME:-root} + - DB_PASSWORD=${DB_PASSWORD:-} + volumes: + - ./storage:/var/www/html/storage + - ./public/uploads:/var/www/html/public/uploads + network_mode: bridge -- 2.49.1 From 0cedc90031832db3a93b44f905cc6b3b0e03aad8 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 12 Dec 2025 01:24:50 +0800 Subject: [PATCH 02/33] Add CI/CD workflows for development and production deployments - Created `deploy-dev.yml` for automated deployment to the development server on push to the `dev` branch. - Created `deploy.yml` for automated deployment to the production server on push to the `main` or `master` branches. - Added deployment instructions in `DEPLOYMENT-PORTAINER.md` for using Portainer and Traefik. - Documented Gitea Actions deployment process in `DEPLOYMENT.md`. - Configured Traefik SSL settings in `TRAEFIK-SSL-CONFIG.md` for both development and production environments. - Implemented a deployment script `deploy.sh` for manual deployments. - Added Docker Compose configurations for development (`docker-compose.portainer.dev.yml`) and production (`docker-compose.portainer.yml`) environments. - Updated main `docker-compose.yml` to support Traefik integration and environment variable configurations. --- .env.example | 26 +- .gitea/workflows/build-push.yml | 46 ++++ .gitea/workflows/deploy-dev.yml | 111 +++++++++ .gitea/workflows/deploy.yml | 122 ++++++++++ DEPLOYMENT-PORTAINER.md | 405 +++++++++++++++++++++++++++++++ DEPLOYMENT.md | 264 ++++++++++++++++++++ TRAEFIK-SSL-CONFIG.md | 316 ++++++++++++++++++++++++ deploy.sh | 105 ++++++++ docker-compose.portainer.dev.yml | 48 ++++ docker-compose.portainer.yml | 51 ++++ docker-compose.yml | 29 ++- 11 files changed, 1509 insertions(+), 14 deletions(-) create mode 100644 .gitea/workflows/build-push.yml create mode 100644 .gitea/workflows/deploy-dev.yml create mode 100644 .gitea/workflows/deploy.yml create mode 100644 DEPLOYMENT-PORTAINER.md create mode 100644 DEPLOYMENT.md create mode 100644 TRAEFIK-SSL-CONFIG.md create mode 100755 deploy.sh create mode 100644 docker-compose.portainer.dev.yml create mode 100644 docker-compose.portainer.yml diff --git a/.env.example b/.env.example index 9a9d0dc..7a837d6 100644 --- a/.env.example +++ b/.env.example @@ -1,25 +1,33 @@ -APP_ENV=local -APP_DEBUG=true -APP_KEY=SomeRandomString -APP_URL=http://localhost +# Application Configuration +APP_ENV=production +APP_DEBUG=false +APP_KEY=base64:YOUR_APP_KEY_HERE +APP_URL=https://merchbay-admin.yourdomain.com +# Database Configuration - External MySQL DB_CONNECTION=mysql -DB_HOST=127.0.0.1 +DB_HOST=your-mysql-host DB_PORT=3306 -DB_DATABASE=homestead -DB_USERNAME=homestead -DB_PASSWORD=secret +DB_DATABASE=merchbay_admin +DB_USERNAME=your-mysql-user +DB_PASSWORD=your-mysql-password +# Traefik Domain Configuration +DOMAIN=merchbay-admin.yourdomain.com + +# Cache & Session CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_DRIVER=sync +# Redis (Optional) REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 +# Mail Configuration MAIL_DRIVER=smtp -MAIL_HOST=mailtrap.io +MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null diff --git a/.gitea/workflows/build-push.yml b/.gitea/workflows/build-push.yml new file mode 100644 index 0000000..a80c2dc --- /dev/null +++ b/.gitea/workflows/build-push.yml @@ -0,0 +1,46 @@ +name: Build and Push Docker Image + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Registry + uses: docker/login-action@v2 + with: + registry: ${{ secrets.DOCKER_REGISTRY_URL }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ secrets.DOCKER_REGISTRY_URL }}/merchbay_admin + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ secrets.DOCKER_REGISTRY_URL }}/merchbay_admin:buildcache + cache-to: type=registry,ref=${{ secrets.DOCKER_REGISTRY_URL }}/merchbay_admin:buildcache,mode=max diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml new file mode 100644 index 0000000..a21948d --- /dev/null +++ b/.gitea/workflows/deploy-dev.yml @@ -0,0 +1,111 @@ +name: Deploy Development + +on: + push: + branches: + - dev + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build Docker Image + run: | + docker build -t merchbay_admin:dev . + + - name: Save Docker Image + run: | + docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz + + - name: Deploy to Development Server via SSH + uses: appleboy/scp-action@master + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: ${{ secrets.DEPLOY_PORT || 22 }} + source: "merchbay_admin_dev.tar.gz,docker-compose.yml" + target: "/tmp/merchbay_admin_dev_deploy" + + - name: Execute Development Deployment Script + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: ${{ secrets.DEPLOY_PORT || 22 }} + script: | + # Set deployment directory for dev + DEPLOY_DIR="/var/www/merchbay_admin_dev" + + # Create deployment directory if it doesn't exist + mkdir -p $DEPLOY_DIR + + # Load the Docker image + cd /tmp/merchbay_admin_dev_deploy + docker load < merchbay_admin_dev.tar.gz + + # Copy docker-compose.yml to deployment directory + cp docker-compose.yml $DEPLOY_DIR/ + + # Navigate to deployment directory + cd $DEPLOY_DIR + + # Update environment file for dev + cat > .env << EOF + APP_ENV=staging + APP_DEBUG=false + APP_URL=https://dev.merchbay.app + DB_HOST=${{ secrets.DEV_DB_HOST }} + DB_PORT=${{ secrets.DEV_DB_PORT || 3306 }} + DB_DATABASE=${{ secrets.DEV_DB_DATABASE }} + DB_USERNAME=${{ secrets.DEV_DB_USERNAME }} + DB_PASSWORD=${{ secrets.DEV_DB_PASSWORD }} + DOMAIN=dev.merchbay.app + EOF + + # Stop existing container + docker compose down || true + + # Remove old image + docker image prune -f + + # Ensure Traefik network exists + docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public + + # Update docker-compose for dev + export DOMAIN=dev.merchbay.app + export APP_URL=https://dev.merchbay.app + + # Start the application + docker compose up -d + + # Wait for container to be ready + sleep 10 + + # Run migrations + docker compose exec -T app php artisan migrate --force + + # Clear and cache configuration + docker compose exec -T app php artisan config:cache + docker compose exec -T app php artisan route:cache + docker compose exec -T app php artisan view:cache + + # Cleanup + rm -rf /tmp/merchbay_admin_dev_deploy + + echo "Development deployment completed successfully!" + echo "Application available at: https://dev.merchbay.app" + + - name: Health Check + run: | + sleep 10 + curl -f https://dev.merchbay.app || exit 1 diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..fdba7b5 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,122 @@ +name: Deploy Production + +on: + push: + branches: + - main + - master + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + # If using self-hosted runner, change to: + # runs-on: self-hosted + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Registry (Optional) + if: ${{ secrets.DOCKER_REGISTRY_URL != '' }} + uses: docker/login-action@v2 + with: + registry: ${{ secrets.DOCKER_REGISTRY_URL }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build Docker Image + run: | + docker build -t merchbay_admin:latest . + + - name: Save Docker Image + run: | + docker save merchbay_admin:latest | gzip > merchbay_admin.tar.gz + + - name: Deploy to Server via SSH + uses: appleboy/scp-action@master + with: + host: ${{ secrets.DEPLOY_HOST }} + username: ${{ secrets.DEPLOY_USER }} + key: ${{ secrets.DEPLOY_SSH_KEY }} + port: ${{ secrets.DEPLOY_PORT || 22 }} + source: "merchbay_admin.tar.gz,docker-compose.yml" + target: "/tmp/merchbay_admin_deploy" + + - name: Execute Production Deployment Script + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.PROD_DEPLOY_HOST }} + username: ${{ secrets.PROD_DEPLOY_USER }} + key: ${{ secrets.PROD_DEPLOY_SSH_KEY }} + port: ${{ secrets.PROD_DEPLOY_PORT || 22 }} + script: | + # Set deployment directory for production + DEPLOY_DIR="/var/www/merchbay_admin" + + # Create deployment directory if it doesn't exist + mkdir -p $DEPLOY_DIR + + # Load the Docker image + cd /tmp/merchbay_admin_deploy + docker load < merchbay_admin.tar.gz + + # Copy docker-compose.yml to deployment directory + cp docker-compose.yml $DEPLOY_DIR/ + + # Navigate to deployment directory + cd $DEPLOY_DIR + + # Update environment file for production + cat > .env << EOF + APP_ENV=production + APP_DEBUG=false + APP_URL=https://merchbay.app + DB_HOST=${{ secrets.PROD_DB_HOST }} + DB_PORT=${{ secrets.PROD_DB_PORT || 3306 }} + DB_DATABASE=${{ secrets.PROD_DB_DATABASE }} + DB_USERNAME=${{ secrets.PROD_DB_USERNAME }} + DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }} + DOMAIN=merchbay.app + EOF + + # Stop existing container (disconnect from Traefik network gracefully) + docker compose down || true + + # Remove old image (optional, keeps only latest) + docker image prune -f + + # Ensure Traefik network exists + docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public + + # Update docker-compose for production + export DOMAIN=merchbay.app + export APP_URL=https://merchbay.app + + # Start the application (will auto-connect to Traefik with paid SSL) + docker compose up -d + + # Wait for container to be ready + sleep 10 + + # Run migrations + docker compose exec -T app php artisan migrate --force + + # Clear and cache configuration + docker compose exec -T app php artisan config:cache + docker compose exec -T app php artisan route:cache + docker compose exec -T app php artisan view:cache + + # Cleanup + rm -rf /tmp/merchbay_admin_deploy + + echo "Production deployment completed successfully!" + echo "Application available at: https://merchbay.app" + + - name: Health Check + run: | + sleep 10 + curl -f https://merchbay.app || exit 1 diff --git a/DEPLOYMENT-PORTAINER.md b/DEPLOYMENT-PORTAINER.md new file mode 100644 index 0000000..81493df --- /dev/null +++ b/DEPLOYMENT-PORTAINER.md @@ -0,0 +1,405 @@ +# Deployment with Portainer and Traefik + +This guide covers deploying MerchBay Admin using your existing Portainer and Traefik setup. + +## Prerequisites + +- ✅ Gitea self-hosted with Gitea runners configured +- ✅ Portainer installed and accessible +- ✅ Traefik reverse proxy running with: + - `web` entrypoint (port 80) + - `websecure` entrypoint (port 443) + - Let's Encrypt certificate resolver named `letsencrypt` + - External network named `traefik` + +## Deployment Methods + +### Method 1: Portainer Stack Deployment (Recommended) + +#### Step 1: Prepare the Image + +Build the Docker image via Gitea Actions or manually: + +```bash +# Using Gitea Actions (will build automatically on push) +git push origin main + +# OR build manually +docker build -t merchbay_admin:latest . +``` + +#### Step 2: Deploy in Portainer + +1. **Access Portainer** → `Stacks` → `Add stack` + +2. **Stack Configuration:** + - Name: `merchbay-admin` + - Build method: `Web editor` + +3. **Paste the content from `docker-compose.portainer.yml`** and update: + - `APP_URL`: Your domain (e.g., `https://merchbay-admin.yourdomain.com`) + - `DB_HOST`: Your MySQL host + - `DB_DATABASE`: Database name + - `DB_USERNAME`: Database username + - `DB_PASSWORD`: Database password + - Traefik Host rule: Replace `merchbay-admin.yourdomain.com` with your actual domain + +4. **Deploy the stack** + +5. **Run Initial Setup:** + - Go to `Containers` → Find `merchbay_admin_app` + - Click `Console` → Connect with `/bin/bash` + - Run: + ```bash + php artisan migrate --force + php artisan config:cache + php artisan route:cache + ``` + +### Method 2: Gitea Actions CI/CD (Automated) + +#### Step 1: Configure Gitea Secrets + +In your Gitea repository → `Settings` → `Secrets` → `Actions`, add: + +| Secret Name | Value | Description | +|------------|-------|-------------| +| `DEPLOY_HOST` | `192.168.1.100` | Your server IP/hostname | +| `DEPLOY_USER` | `deploy` | SSH username | +| `DEPLOY_SSH_KEY` | `-----BEGIN RSA...` | Private SSH key | +| `DEPLOY_PORT` | `22` | SSH port (optional) | +| `DEPLOY_DIR` | `/var/www/merchbay_admin` | Deployment directory | +| `DOMAIN` | `merchbay-admin.yourdomain.com` | Your domain for Traefik | + +#### Step 2: Prepare Deployment Server + +```bash +# SSH into your server +ssh deploy@your-server + +# Create deployment directory +sudo mkdir -p /var/www/merchbay_admin +sudo chown $USER:$USER /var/www/merchbay_admin +cd /var/www/merchbay_admin + +# Create .env file +nano .env +``` + +Add to `.env`: +```env +APP_ENV=production +APP_DEBUG=false +APP_URL=https://merchbay-admin.yourdomain.com +DB_HOST=your-mysql-host +DB_PORT=3306 +DB_DATABASE=merchbay_admin +DB_USERNAME=your-mysql-user +DB_PASSWORD=your-mysql-password +DOMAIN=merchbay-admin.yourdomain.com +``` + +#### Step 3: Ensure Traefik Network Exists + +```bash +docker network inspect traefik >/dev/null 2>&1 || docker network create traefik +``` + +#### Step 4: Deploy + +Simply push to your main branch: + +```bash +git add . +git commit -m "Deploy application" +git push origin main +``` + +Gitea Actions will automatically: +1. Build the Docker image +2. Transfer to your server +3. Deploy with docker-compose +4. Connect to Traefik network +5. Run migrations +6. Cache configurations + +### Method 3: Manual Deployment with Script + +```bash +# On your server +cd /var/www/merchbay_admin + +# Pull latest code +git pull origin main + +# Run deployment script +./deploy.sh +``` + +## Traefik Configuration + +### Verify Traefik Setup + +Ensure your Traefik configuration includes: + +```yaml +# traefik.yml or docker-compose.yml +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + +certificatesResolvers: + letsencrypt: + acme: + email: your-email@example.com + storage: /letsencrypt/acme.json + httpChallenge: + entryPoint: web +``` + +### External Network + +Ensure Traefik network exists and is external: + +```bash +# Create network if it doesn't exist +docker network create traefik + +# Verify +docker network inspect traefik +``` + +## DNS Configuration + +Point your domain to your server: + +``` +Type: A Record +Name: merchbay-admin (or @ for root domain) +Value: YOUR_SERVER_IP +TTL: 3600 +``` + +## Verification + +### 1. Check Container Status + +**Via Portainer:** +- Navigate to `Containers` +- Verify `merchbay_admin_app` is running + +**Via CLI:** +```bash +docker ps | grep merchbay_admin +``` + +### 2. Check Traefik Dashboard + +If you have Traefik dashboard enabled: +- Look for `merchbay-admin@docker` router +- Verify it's connected to the correct service + +### 3. Test Application + +```bash +# Test HTTPS +curl -I https://merchbay-admin.yourdomain.com + +# Should return: HTTP/2 200 +``` + +### 4. Check Logs + +**Via Portainer:** +- `Containers` → `merchbay_admin_app` → `Logs` + +**Via CLI:** +```bash +docker logs merchbay_admin_app -f +``` + +## Troubleshooting + +### Issue: Container not accessible via domain + +**Check Traefik labels:** +```bash +docker inspect merchbay_admin_app | grep -A 20 Labels +``` + +**Verify network connection:** +```bash +docker network inspect traefik | grep merchbay_admin +``` + +**Solution:** +```bash +# Reconnect to Traefik network +docker network connect traefik merchbay_admin_app +``` + +### Issue: SSL certificate not generating + +**Check Traefik logs:** +```bash +docker logs traefik | grep letsencrypt +``` + +**Common fixes:** +1. Ensure port 80 is accessible (Let's Encrypt HTTP challenge) +2. Verify DNS is pointing to your server +3. Check email in Traefik's ACME configuration +4. Ensure `acme.json` has correct permissions (600) + +### Issue: Database connection failed + +**Check environment variables:** +```bash +docker exec merchbay_admin_app env | grep DB_ +``` + +**Test connection:** +```bash +docker exec merchbay_admin_app php artisan tinker +>>> DB::connection()->getPdo(); +``` + +### Issue: 502 Bad Gateway + +**Possible causes:** +1. Application not fully started +2. Wrong port in Traefik label (should be 80) +3. Application crashed + +**Check:** +```bash +# Container status +docker ps -a | grep merchbay_admin + +# Application logs +docker logs merchbay_admin_app --tail 100 + +# Restart container +docker restart merchbay_admin_app +``` + +## Updating the Application + +### Via Gitea Actions (Automatic) + +```bash +git add . +git commit -m "Update application" +git push origin main +``` + +### Via Portainer + +1. Go to `Stacks` → `merchbay-admin` +2. Click `Editor` +3. Update image or configuration +4. Click `Update the stack` +5. Enable "Re-pull image and redeploy" + +### Manual Update + +```bash +ssh deploy@your-server +cd /var/www/merchbay_admin +./deploy.sh +``` + +## Rollback + +### Via Portainer + +1. Go to `Stacks` → `merchbay-admin` +2. Click on the stack +3. Find previous version in `Stack History` (if available) +4. Revert to previous version + +### Manual Rollback + +```bash +# List available backups +ls -lh /var/www/merchbay_admin/backups/ + +# Restore from backup +cd /var/www/merchbay_admin +tar -xzf backups/backup_YYYYMMDD_HHMMSS.tar.gz + +# Restart +docker compose restart +``` + +## Security Best Practices + +1. **Use Strong Database Passwords**: Generate with `openssl rand -base64 32` +2. **Restrict SSH Access**: Use key-based authentication only +3. **Firewall Rules**: Only allow necessary ports (80, 443, 22) +4. **Regular Backups**: Automated backups of database and storage +5. **Keep Docker Updated**: Regularly update Docker and images +6. **Monitor Logs**: Set up log monitoring/alerting +7. **Use Secrets**: Never commit sensitive data to repository +8. **HTTPS Only**: Ensure HTTP redirects to HTTPS + +## Performance Optimization + +### PHP-FPM Configuration + +Consider switching to PHP-FPM for better performance: + +```dockerfile +FROM php:7.4-fpm-alpine +# ... additional configuration +``` + +### Use Redis for Cache/Sessions + +```env +CACHE_DRIVER=redis +SESSION_DRIVER=redis +REDIS_HOST=redis +``` + +Add Redis service to docker-compose: +```yaml +services: + redis: + image: redis:alpine + networks: + - default +``` + +### Enable OPcache + +Already included in Dockerfile, verify: +```bash +docker exec merchbay_admin_app php -i | grep opcache +``` + +## Monitoring + +### View Real-time Logs in Portainer + +1. Navigate to `Containers` +2. Click on `merchbay_admin_app` +3. Select `Logs` tab +4. Enable `Auto-refresh` + +### Set Up Alerts + +Configure Portainer notifications: +1. `Settings` → `Notifications` +2. Add webhook or email notification +3. Set up container health checks + +## Support + +For issues: +1. Check application logs in Portainer +2. Verify Traefik configuration +3. Test database connectivity +4. Review Gitea Actions logs if using CI/CD diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..54b6635 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,264 @@ +# Gitea Actions Deployment Guide + +This repository uses Gitea Actions for automated deployment to your server. + +## Workflows + +### 1. Deploy Workflow (`.gitea/workflows/deploy.yml`) +Automatically deploys the application when code is pushed to `main` or `master` branch. + +**Steps:** +1. Builds Docker image +2. Transfers image to deployment server +3. Stops existing container +4. Starts new container +5. Runs database migrations +6. Clears and caches Laravel configuration + +### 2. Build and Push Workflow (`.gitea/workflows/build-push.yml`) +Builds and pushes Docker images to a registry when a version tag is created. + +## Required Secrets + +Configure these secrets in your Gitea repository settings: +`Settings` → `Secrets` → `Actions` + +### Deployment Secrets + +| Secret Name | Description | Example | +|------------|-------------|---------| +| `DEPLOY_HOST` | Deployment server hostname or IP | `192.168.1.100` or `example.com` | +| `DEPLOY_USER` | SSH username for deployment | `deploy` or `ubuntu` | +| `DEPLOY_SSH_KEY` | Private SSH key for authentication | `-----BEGIN RSA PRIVATE KEY-----...` | +| `DEPLOY_PORT` | SSH port (optional, defaults to 22) | `22` | +| `DEPLOY_DIR` | Deployment directory (optional) | `/var/www/merchbay_admin` | + +### Docker Registry Secrets (Optional) + +Only required if using the build-push workflow or private registry: + +| Secret Name | Description | Example | +|------------|-------------|---------| +| `DOCKER_REGISTRY_URL` | Docker registry URL | `registry.example.com` or `docker.io` | +| `DOCKER_USERNAME` | Registry username | `myuser` | +| `DOCKER_PASSWORD` | Registry password or token | `mypassword` | + +### Database Configuration on Server + +Create a `.env` file in your deployment directory with database credentials: + +```bash +# On your deployment server +sudo mkdir -p /var/www/merchbay_admin +sudo nano /var/www/merchbay_admin/.env +``` + +Add your database configuration: + +```env +DB_HOST=your-mysql-host +DB_PORT=3306 +DB_DATABASE=merchbay_admin +DB_USERNAME=your-mysql-user +DB_PASSWORD=your-mysql-password +APP_ENV=production +APP_DEBUG=false +APP_KEY=base64:YOUR_APP_KEY_HERE +``` + +## Setup Instructions + +### 1. Generate SSH Key for Deployment + +On your local machine or CI server: + +```bash +# Generate a new SSH key pair +ssh-keygen -t rsa -b 4096 -f ~/.ssh/deploy_key -N "" + +# Copy the public key to your deployment server +ssh-copy-id -i ~/.ssh/deploy_key.pub user@your-server + +# Copy the private key content for Gitea secret +cat ~/.ssh/deploy_key +``` + +### 2. Configure Gitea Secrets + +1. Go to your Gitea repository +2. Navigate to `Settings` → `Secrets` → `Actions` +3. Add each required secret listed above +4. For `DEPLOY_SSH_KEY`, paste the entire private key content + +### 3. Prepare Deployment Server + +On your deployment server, install Docker and Docker Compose: + +```bash +# Install Docker +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh + +# Add your user to docker group +sudo usermod -aG docker $USER + +# Install Docker Compose +sudo apt-get update +sudo apt-get install docker-compose-plugin + +# Create deployment directory +sudo mkdir -p /var/www/merchbay_admin +sudo chown $USER:$USER /var/www/merchbay_admin + +# Create .env file with database credentials +nano /var/www/merchbay_admin/.env +``` + +### 4. Update docker-compose.yml for Production + +Ensure your `docker-compose.yml` references the `.env` file: + +```yaml +services: + app: + environment: + - DB_HOST=${DB_HOST} + - DB_PORT=${DB_PORT} + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} +``` + +## Triggering Deployment + +### Automatic Deployment + +Push to main/master branch: + +```bash +git add . +git commit -m "Deploy updates" +git push origin main +``` + +### Manual Deployment + +1. Go to your Gitea repository +2. Click on `Actions` +3. Select `Deploy MerchBay Admin` workflow +4. Click `Run workflow` + +## Monitoring Deployment + +### View Workflow Logs + +1. Go to `Actions` tab in your Gitea repository +2. Click on the running/completed workflow +3. View logs for each step + +### Check Application Logs + +On your deployment server: + +```bash +cd /var/www/merchbay_admin +docker compose logs -f app +``` + +### Verify Deployment + +```bash +# Check container status +docker compose ps + +# Test application +curl http://localhost:8080 + +# Access application shell +docker compose exec app bash +``` + +## Rollback Procedure + +If deployment fails, you can quickly rollback: + +```bash +# On deployment server +cd /var/www/merchbay_admin + +# Stop current container +docker compose down + +# Load previous image (if available) +docker images # Find previous image ID +docker tag merchbay_admin:latest + +# Start with previous version +docker compose up -d +``` + +## Troubleshooting + +### SSH Connection Issues + +```bash +# Test SSH connection from CI to server +ssh -i ~/.ssh/deploy_key user@your-server + +# Check SSH key permissions +chmod 600 ~/.ssh/deploy_key +``` + +### Docker Permission Issues + +```bash +# On deployment server, ensure user is in docker group +sudo usermod -aG docker $USER +newgrp docker +``` + +### Migration Failures + +```bash +# Manually run migrations +docker compose exec app php artisan migrate --force + +# Check database connection +docker compose exec app php artisan tinker +>>> DB::connection()->getPdo(); +``` + +## Security Best Practices + +1. **Use SSH keys, not passwords** for server authentication +2. **Restrict SSH key** to only deployment commands if possible +3. **Use secrets** for all sensitive data, never commit to repository +4. **Set proper file permissions** on deployment server (755 for directories, 644 for files) +5. **Enable firewall** on deployment server and restrict access +6. **Use HTTPS** with SSL certificates in production +7. **Regular backups** of database and uploaded files + +## Advanced Configuration + +### Using Docker Registry + +To use a private registry: + +1. Add registry secrets to Gitea +2. Update deployment script to pull from registry instead of transferring image +3. Use the build-push workflow to automate image publishing + +### Zero-Downtime Deployment + +For zero-downtime deployments, consider: + +1. Using a load balancer +2. Running multiple container instances +3. Implementing blue-green deployment strategy + +### Environment-Specific Deployments + +Create separate workflows for staging and production: + +- `.gitea/workflows/deploy-staging.yml` (triggered on `develop` branch) +- `.gitea/workflows/deploy-production.yml` (triggered on `main` branch) diff --git a/TRAEFIK-SSL-CONFIG.md b/TRAEFIK-SSL-CONFIG.md new file mode 100644 index 0000000..ba9117b --- /dev/null +++ b/TRAEFIK-SSL-CONFIG.md @@ -0,0 +1,316 @@ +# Traefik SSL Configuration for MerchBay Admin + +This document explains how to configure paid SSL certificates for production and automatic Let's Encrypt for development. + +## Network Configuration + +All deployments use the external network: `traefik-public` + +```bash +# Ensure the network exists +docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public +``` + +## Development (dev.merchbay.app) - Automatic SSL + +Development uses Let's Encrypt for automatic SSL certificate generation. + +### Traefik Configuration + +Ensure your Traefik has Let's Encrypt configured: + +```yaml +# traefik.yml or dynamic config +certificatesResolvers: + letsencrypt: + acme: + email: admin@merchbay.app + storage: /letsencrypt/acme.json + httpChallenge: + entryPoint: web +``` + +### Application Labels (Already configured in docker-compose) + +```yaml +labels: + - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" +``` + +## Production (merchbay.app) - Paid SSL Certificate + +Production uses a paid SSL certificate (e.g., from GoDaddy, Namecheap, Cloudflare). + +### Step 1: Prepare SSL Certificate Files + +You should have these files from your SSL provider: +- `merchbay.app.crt` - Certificate file +- `merchbay.app.key` - Private key file +- `ca-bundle.crt` - CA bundle (optional, for chain) + +Create a combined certificate file: + +```bash +# Create SSL directory in Traefik +mkdir -p /opt/traefik/certs + +# Copy your certificate and key +sudo cp merchbay.app.crt /opt/traefik/certs/ +sudo cp merchbay.app.key /opt/traefik/certs/ + +# If you have a CA bundle, create a full chain +cat merchbay.app.crt ca-bundle.crt > /opt/traefik/certs/merchbay.app-fullchain.crt + +# Set proper permissions +sudo chmod 600 /opt/traefik/certs/*.key +sudo chmod 644 /opt/traefik/certs/*.crt +``` + +### Step 2: Configure Traefik File Provider + +Create a dynamic configuration file for Traefik: + +```bash +sudo nano /opt/traefik/dynamic/certs.yml +``` + +Add: + +```yaml +# /opt/traefik/dynamic/certs.yml +tls: + certificates: + - certFile: /certs/merchbay.app-fullchain.crt + keyFile: /certs/merchbay.app.key + stores: + - default + stores: + default: + defaultCertificate: + certFile: /certs/merchbay.app-fullchain.crt + keyFile: /certs/merchbay.app.key +``` + +### Step 3: Update Traefik docker-compose.yml + +Ensure Traefik has file provider enabled and certificates mounted: + +```yaml +services: + traefik: + image: traefik:v2.10 + command: + - "--providers.docker=true" + - "--providers.docker.network=traefik-public" + - "--providers.file.directory=/etc/traefik/dynamic" + - "--providers.file.watch=true" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + # Let's Encrypt for dev + - "--certificatesresolvers.letsencrypt.acme.email=admin@merchbay.app" + - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" + - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - /opt/traefik/certs:/certs:ro + - /opt/traefik/dynamic:/etc/traefik/dynamic:ro + - traefik-letsencrypt:/letsencrypt + networks: + - traefik-public +``` + +### Step 4: Restart Traefik + +```bash +cd /path/to/traefik +docker compose restart traefik + +# Verify certificates are loaded +docker compose logs traefik | grep -i cert +``` + +## Application Configuration + +### Development Branch (dev) + +File: `docker-compose.portainer.dev.yml` + +- Domain: `dev.merchbay.app` +- SSL: Let's Encrypt (automatic) +- Certificate Resolver: `letsencrypt` + +```yaml +labels: + - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" +``` + +### Production Branch (main) + +File: `docker-compose.portainer.yml` + +- Domain: `merchbay.app` +- SSL: Paid certificate (via Traefik file provider) +- No certresolver label (uses default store) + +```yaml +labels: + - "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.app`)" + - "traefik.http.routers.merchbay-admin.tls=true" + # No certresolver - uses file provider certificate +``` + +## Gitea Secrets Configuration + +### Development Secrets + +``` +DEV_DB_HOST=dev-mysql-host +DEV_DB_PORT=3306 +DEV_DB_DATABASE=merchbay_admin_dev +DEV_DB_USERNAME=dev_user +DEV_DB_PASSWORD=dev_password +``` + +### Production Secrets + +``` +PROD_DEPLOY_HOST=prod-server-ip +PROD_DEPLOY_USER=deploy +PROD_DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----... +PROD_DEPLOY_PORT=22 +PROD_DB_HOST=prod-mysql-host +PROD_DB_PORT=3306 +PROD_DB_DATABASE=merchbay_admin +PROD_DB_USERNAME=prod_user +PROD_DB_PASSWORD=prod_password +``` + +### Shared Secrets (if using same server) + +``` +DEPLOY_HOST=your-server-ip +DEPLOY_USER=deploy +DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----... +DEPLOY_PORT=22 +``` + +## Verification + +### Check Development SSL + +```bash +# Check certificate issuer (should be Let's Encrypt) +echo | openssl s_client -servername dev.merchbay.app -connect dev.merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer +# Should show: issuer=C = US, O = Let's Encrypt, CN = R3 +``` + +### Check Production SSL + +```bash +# Check certificate issuer (should be your SSL provider) +echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer +# Should show your paid SSL provider + +# Check certificate validity +echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -dates +``` + +### Verify in Browser + +1. Visit https://dev.merchbay.app + - Certificate should be issued by "Let's Encrypt Authority X3" + +2. Visit https://merchbay.app + - Certificate should be issued by your paid SSL provider + +## Troubleshooting + +### Development SSL Not Working + +```bash +# Check Let's Encrypt logs +docker logs traefik | grep letsencrypt + +# Verify acme.json permissions +ls -l /path/to/letsencrypt/acme.json +# Should be: -rw------- (600) + +# Check DNS +dig dev.merchbay.app +short +# Should return your server IP +``` + +### Production SSL Not Working + +```bash +# Verify Traefik can read certificates +docker exec traefik ls -l /certs/ + +# Check dynamic configuration is loaded +docker exec traefik cat /etc/traefik/dynamic/certs.yml + +# Verify certificate format +openssl x509 -in /opt/traefik/certs/merchbay.app-fullchain.crt -text -noout + +# Check private key +openssl rsa -in /opt/traefik/certs/merchbay.app.key -check +``` + +### Certificate Mismatch + +```bash +# Verify certificate and key match +openssl x509 -noout -modulus -in /opt/traefik/certs/merchbay.app.crt | openssl md5 +openssl rsa -noout -modulus -in /opt/traefik/certs/merchbay.app.key | openssl md5 +# Both should output the same hash +``` + +## Renewing Certificates + +### Development (Let's Encrypt) + +Automatic renewal every 60 days. No action needed. + +### Production (Paid SSL) + +Before certificate expiration: + +1. Download new certificate from your SSL provider +2. Update files in `/opt/traefik/certs/` +3. Restart Traefik: `docker compose restart traefik` +4. Verify: `curl -vI https://merchbay.app` + +## DNS Configuration + +### Development + +``` +Type: A +Name: dev.merchbay.app +Value: YOUR_SERVER_IP +TTL: 3600 +``` + +### Production + +``` +Type: A +Name: merchbay.app (or @) +Value: YOUR_SERVER_IP +TTL: 3600 + +Type: A +Name: www.merchbay.app +Value: YOUR_SERVER_IP +TTL: 3600 +``` + +## Security Best Practices + +1. **Keep certificates private**: Never commit SSL keys to git +2. **Use strong permissions**: 600 for private keys, 644 for certificates +3. **Monitor expiration**: Set reminders 30 days before expiration +4. **Use HSTS**: Add header after SSL is working correctly +5. **Enable OCSP stapling**: Improves SSL performance +6. **Regular updates**: Keep Traefik updated for security patches diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..1e6468a --- /dev/null +++ b/deploy.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Deployment script for MerchBay Admin +# This can be used for manual deployments or called from CI/CD + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Configuration +DEPLOY_DIR="${DEPLOY_DIR:-/var/www/merchbay_admin}" +APP_NAME="merchbay_admin" +BACKUP_DIR="${DEPLOY_DIR}/backups" + +echo -e "${GREEN}Starting deployment of ${APP_NAME}...${NC}" + +# Create backup directory +mkdir -p "${BACKUP_DIR}" + +# Backup current state +if [ -d "${DEPLOY_DIR}/storage" ]; then + echo -e "${YELLOW}Creating backup...${NC}" + BACKUP_FILE="${BACKUP_DIR}/backup_$(date +%Y%m%d_%H%M%S).tar.gz" + tar -czf "${BACKUP_FILE}" -C "${DEPLOY_DIR}" storage .env 2>/dev/null || true + echo -e "${GREEN}Backup created: ${BACKUP_FILE}${NC}" +fi + +# Navigate to deployment directory +cd "${DEPLOY_DIR}" + +# Check if .env exists +if [ ! -f .env ]; then + echo -e "${RED}Error: .env file not found!${NC}" + echo "Please create .env file with database credentials" + exit 1 +fi + +# Pull latest code (if using git deployment) +if [ -d .git ]; then + echo -e "${YELLOW}Pulling latest code...${NC}" + git pull origin main || git pull origin master +fi + +# Stop existing containers +echo -e "${YELLOW}Stopping existing containers...${NC}" +docker compose down + +# Build new image +echo -e "${YELLOW}Building Docker image...${NC}" +docker compose build --no-cache + +# Start containers +echo -e "${YELLOW}Starting containers...${NC}" +docker compose up -d + +# Wait for container to be ready +echo -e "${YELLOW}Waiting for application to start...${NC}" +sleep 10 + +# Run migrations +echo -e "${YELLOW}Running database migrations...${NC}" +docker compose exec -T app php artisan migrate --force || { + echo -e "${RED}Migration failed! Rolling back...${NC}" + docker compose down + exit 1 +} + +# Clear and cache configuration +echo -e "${YELLOW}Optimizing application...${NC}" +docker compose exec -T app php artisan config:cache +docker compose exec -T app php artisan route:cache +docker compose exec -T app php artisan view:cache + +# Set proper permissions +echo -e "${YELLOW}Setting permissions...${NC}" +docker compose exec -T app chown -R www-data:www-data /var/www/html/storage +docker compose exec -T app chmod -R 755 /var/www/html/storage + +# Health check +echo -e "${YELLOW}Performing health check...${NC}" +sleep 5 +HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080) + +if [ "$HTTP_STATUS" -eq 200 ]; then + echo -e "${GREEN}✓ Deployment successful! Application is running.${NC}" + echo -e "${GREEN}✓ HTTP Status: ${HTTP_STATUS}${NC}" + + # Keep only last 5 backups + cd "${BACKUP_DIR}" + ls -t backup_*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm + + echo -e "${GREEN}Deployment completed successfully!${NC}" +else + echo -e "${RED}✗ Health check failed! HTTP Status: ${HTTP_STATUS}${NC}" + echo -e "${YELLOW}Check logs: docker compose logs app${NC}" + exit 1 +fi + +# Display container status +echo -e "${YELLOW}Container status:${NC}" +docker compose ps diff --git a/docker-compose.portainer.dev.yml b/docker-compose.portainer.dev.yml new file mode 100644 index 0000000..09d14d5 --- /dev/null +++ b/docker-compose.portainer.dev.yml @@ -0,0 +1,48 @@ +version: '3.8' + +# Development Stack - Portainer Configuration +# Deploy this through Portainer UI: Stacks -> Add Stack -> Web Editor +# Branch: dev + +services: + app: + image: merchbay_admin:dev + container_name: merchbay_admin_dev + restart: unless-stopped + environment: + - APP_ENV=staging + - APP_DEBUG=false + - APP_URL=https://dev.merchbay.app + - DB_CONNECTION=mysql + - DB_HOST=your-mysql-host + - DB_PORT=3306 + - DB_DATABASE=merchbay_admin_dev + - DB_USERNAME=your-mysql-user + - DB_PASSWORD=your-mysql-password + volumes: + - app_storage_dev:/var/www/html/storage + - app_uploads_dev:/var/www/html/public/uploads + labels: + - "traefik.enable=true" + - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev.entrypoints=websecure" + - "traefik.http.routers.merchbay-admin-dev.tls=true" + - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" + - "traefik.http.services.merchbay-admin-dev.loadbalancer.server.port=80" + # HTTP to HTTPS redirect + - "traefik.http.routers.merchbay-admin-dev-http.rule=Host(`dev.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev-http.entrypoints=web" + - "traefik.http.routers.merchbay-admin-dev-http.middlewares=https-redirect" + - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" + networks: + - traefik-public + +volumes: + app_storage_dev: + driver: local + app_uploads_dev: + driver: local + +networks: + traefik-public: + external: true diff --git a/docker-compose.portainer.yml b/docker-compose.portainer.yml new file mode 100644 index 0000000..ca562af --- /dev/null +++ b/docker-compose.portainer.yml @@ -0,0 +1,51 @@ +version: '3.8' + +# Production Stack - Portainer Configuration +# Deploy this through Portainer UI: Stacks -> Add Stack -> Web Editor +# Branch: main - Uses paid SSL certificate + +services: + app: + image: merchbay_admin:latest + container_name: merchbay_admin_prod + restart: unless-stopped + environment: + - APP_ENV=production + - APP_DEBUG=false + - APP_URL=https://merchbay.app + - DB_CONNECTION=mysql + - DB_HOST=your-mysql-host + - DB_PORT=3306 + - DB_DATABASE=merchbay_admin + - DB_USERNAME=your-mysql-user + - DB_PASSWORD=your-mysql-password + volumes: + - app_storage:/var/www/html/storage + - app_uploads:/var/www/html/public/uploads + # Mount paid SSL certificates + - /path/to/ssl/certs:/etc/ssl/certs:ro + labels: + - "traefik.enable=true" + - "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.app`)" + - "traefik.http.routers.merchbay-admin.entrypoints=websecure" + - "traefik.http.routers.merchbay-admin.tls=true" + # Use custom TLS configuration (file provider for paid cert) + # Ensure Traefik has file provider configured with your paid SSL cert + - "traefik.http.services.merchbay-admin.loadbalancer.server.port=80" + # HTTP to HTTPS redirect + - "traefik.http.routers.merchbay-admin-http.rule=Host(`merchbay.app`)" + - "traefik.http.routers.merchbay-admin-http.entrypoints=web" + - "traefik.http.routers.merchbay-admin-http.middlewares=https-redirect" + - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" + networks: + - traefik-public + +volumes: + app_storage: + driver: local + app_uploads: + driver: local + +networks: + traefik-public: + external: true diff --git a/docker-compose.yml b/docker-compose.yml index 83c916a..088f8de 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,11 +7,10 @@ services: dockerfile: Dockerfile container_name: merchbay_admin_app restart: unless-stopped - ports: - - "8080:80" environment: - - APP_ENV=production - - APP_DEBUG=false + - APP_ENV=${APP_ENV:-production} + - APP_DEBUG=${APP_DEBUG:-false} + - APP_URL=${APP_URL:-http://localhost} - DB_CONNECTION=mysql - DB_HOST=${DB_HOST:-localhost} - DB_PORT=${DB_PORT:-3306} @@ -21,4 +20,24 @@ services: volumes: - ./storage:/var/www/html/storage - ./public/uploads:/var/www/html/public/uploads - network_mode: bridge + labels: + - "traefik.enable=true" + - "traefik.http.routers.merchbay-admin.rule=Host(`${DOMAIN:-merchbay-admin.localhost}`)" + - "traefik.http.routers.merchbay-admin.entrypoints=websecure" + - "traefik.http.routers.merchbay-admin.tls=true" + - "traefik.http.routers.merchbay-admin.tls.certresolver=letsencrypt" + - "traefik.http.services.merchbay-admin.loadbalancer.server.port=80" + # HTTP to HTTPS redirect + - "traefik.http.routers.merchbay-admin-http.rule=Host(`${DOMAIN:-merchbay-admin.localhost}`)" + - "traefik.http.routers.merchbay-admin-http.entrypoints=web" + - "traefik.http.routers.merchbay-admin-http.middlewares=https-redirect" + - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" + networks: + - traefik-public + - default + +networks: + traefik-public: + external: true + default: + driver: bridge -- 2.49.1 From c72e03f28228961dac0147a077856a62f6d0a28d Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 12 Dec 2025 01:34:05 +0800 Subject: [PATCH 03/33] Update domain references from merchbay.app to merchbay.com in configuration files --- .env.example | 4 ++-- .gitea/workflows/deploy.yml | 12 +++++------ TRAEFIK-SSL-CONFIG.md | 42 +++++++++++++++++------------------- docker-compose.portainer.yml | 8 +++---- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/.env.example b/.env.example index 7a837d6..0b89503 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ APP_ENV=production APP_DEBUG=false APP_KEY=base64:YOUR_APP_KEY_HERE -APP_URL=https://merchbay-admin.yourdomain.com +APP_URL=https://merchbay.com # Database Configuration - External MySQL DB_CONNECTION=mysql @@ -13,7 +13,7 @@ DB_USERNAME=your-mysql-user DB_PASSWORD=your-mysql-password # Traefik Domain Configuration -DOMAIN=merchbay-admin.yourdomain.com +DOMAIN=merchbay.com # Cache & Session CACHE_DRIVER=file diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index fdba7b5..d5db9a1 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -74,13 +74,13 @@ jobs: cat > .env << EOF APP_ENV=production APP_DEBUG=false - APP_URL=https://merchbay.app + APP_URL=https://merchbay.com DB_HOST=${{ secrets.PROD_DB_HOST }} DB_PORT=${{ secrets.PROD_DB_PORT || 3306 }} DB_DATABASE=${{ secrets.PROD_DB_DATABASE }} DB_USERNAME=${{ secrets.PROD_DB_USERNAME }} DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }} - DOMAIN=merchbay.app + DOMAIN=merchbay.com EOF # Stop existing container (disconnect from Traefik network gracefully) @@ -93,8 +93,8 @@ jobs: docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public # Update docker-compose for production - export DOMAIN=merchbay.app - export APP_URL=https://merchbay.app + export DOMAIN=merchbay.com + export APP_URL=https://merchbay.com # Start the application (will auto-connect to Traefik with paid SSL) docker compose up -d @@ -114,9 +114,9 @@ jobs: rm -rf /tmp/merchbay_admin_deploy echo "Production deployment completed successfully!" - echo "Application available at: https://merchbay.app" + echo "Application available at: https://merchbay.com" - name: Health Check run: | sleep 10 - curl -f https://merchbay.app || exit 1 + curl -f https://merchbay.com || exit 1 diff --git a/TRAEFIK-SSL-CONFIG.md b/TRAEFIK-SSL-CONFIG.md index ba9117b..3459020 100644 --- a/TRAEFIK-SSL-CONFIG.md +++ b/TRAEFIK-SSL-CONFIG.md @@ -51,19 +51,17 @@ You should have these files from your SSL provider: Create a combined certificate file: ```bash -# Create SSL directory in Traefik -mkdir -p /opt/traefik/certs - -# Copy your certificate and key -sudo cp merchbay.app.crt /opt/traefik/certs/ -sudo cp merchbay.app.key /opt/traefik/certs/ +# Your SSL certificates are in /srv/certs +# Verify files exist +ls -la /srv/certs/ # If you have a CA bundle, create a full chain -cat merchbay.app.crt ca-bundle.crt > /opt/traefik/certs/merchbay.app-fullchain.crt +cd /srv/certs +cat merchbay.app.crt ca-bundle.crt > merchbay.app-fullchain.crt # Set proper permissions -sudo chmod 600 /opt/traefik/certs/*.key -sudo chmod 644 /opt/traefik/certs/*.crt +sudo chmod 600 /srv/certs/*.key +sudo chmod 644 /srv/certs/*.crt ``` ### Step 2: Configure Traefik File Provider @@ -77,18 +75,18 @@ sudo nano /opt/traefik/dynamic/certs.yml Add: ```yaml -# /opt/traefik/dynamic/certs.yml +# /opt/traefik/dynamic/certs.yml or your Traefik dynamic config location tls: certificates: - - certFile: /certs/merchbay.app-fullchain.crt - keyFile: /certs/merchbay.app.key + - certFile: /srv/certs/merchbay.app-fullchain.crt + keyFile: /srv/certs/merchbay.app.key stores: - default stores: default: defaultCertificate: - certFile: /certs/merchbay.app-fullchain.crt - keyFile: /certs/merchbay.app.key + certFile: /srv/certs/merchbay.app-fullchain.crt + keyFile: /srv/certs/merchbay.app.key ``` ### Step 3: Update Traefik docker-compose.yml @@ -112,7 +110,7 @@ services: - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - - /opt/traefik/certs:/certs:ro + - /srv/certs:/srv/certs:ro - /opt/traefik/dynamic:/etc/traefik/dynamic:ro - traefik-letsencrypt:/letsencrypt networks: @@ -221,7 +219,7 @@ echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/de 1. Visit https://dev.merchbay.app - Certificate should be issued by "Let's Encrypt Authority X3" -2. Visit https://merchbay.app +2. Visit https://merchbay.com - Certificate should be issued by your paid SSL provider ## Troubleshooting @@ -245,24 +243,24 @@ dig dev.merchbay.app +short ```bash # Verify Traefik can read certificates -docker exec traefik ls -l /certs/ +docker exec traefik ls -l /srv/certs/ # Check dynamic configuration is loaded docker exec traefik cat /etc/traefik/dynamic/certs.yml # Verify certificate format -openssl x509 -in /opt/traefik/certs/merchbay.app-fullchain.crt -text -noout +openssl x509 -in /srv/certs/merchbay.app-fullchain.crt -text -noout # Check private key -openssl rsa -in /opt/traefik/certs/merchbay.app.key -check +openssl rsa -in /srv/certs/merchbay.app.key -check ``` ### Certificate Mismatch ```bash # Verify certificate and key match -openssl x509 -noout -modulus -in /opt/traefik/certs/merchbay.app.crt | openssl md5 -openssl rsa -noout -modulus -in /opt/traefik/certs/merchbay.app.key | openssl md5 +openssl x509 -noout -modulus -in /srv/certs/merchbay.app.crt | openssl md5 +openssl rsa -noout -modulus -in /srv/certs/merchbay.app.key | openssl md5 # Both should output the same hash ``` @@ -277,7 +275,7 @@ Automatic renewal every 60 days. No action needed. Before certificate expiration: 1. Download new certificate from your SSL provider -2. Update files in `/opt/traefik/certs/` +2. Update files in `/srv/certs/` 3. Restart Traefik: `docker compose restart traefik` 4. Verify: `curl -vI https://merchbay.app` diff --git a/docker-compose.portainer.yml b/docker-compose.portainer.yml index ca562af..f515587 100644 --- a/docker-compose.portainer.yml +++ b/docker-compose.portainer.yml @@ -12,7 +12,7 @@ services: environment: - APP_ENV=production - APP_DEBUG=false - - APP_URL=https://merchbay.app + - APP_URL=https://merchbay.com - DB_CONNECTION=mysql - DB_HOST=your-mysql-host - DB_PORT=3306 @@ -22,18 +22,16 @@ services: volumes: - app_storage:/var/www/html/storage - app_uploads:/var/www/html/public/uploads - # Mount paid SSL certificates - - /path/to/ssl/certs:/etc/ssl/certs:ro labels: - "traefik.enable=true" - - "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.app`)" + - "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.com`)" - "traefik.http.routers.merchbay-admin.entrypoints=websecure" - "traefik.http.routers.merchbay-admin.tls=true" # Use custom TLS configuration (file provider for paid cert) # Ensure Traefik has file provider configured with your paid SSL cert - "traefik.http.services.merchbay-admin.loadbalancer.server.port=80" # HTTP to HTTPS redirect - - "traefik.http.routers.merchbay-admin-http.rule=Host(`merchbay.app`)" + - "traefik.http.routers.merchbay-admin-http.rule=Host(`merchbay.com`)" - "traefik.http.routers.merchbay-admin-http.entrypoints=web" - "traefik.http.routers.merchbay-admin-http.middlewares=https-redirect" - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" -- 2.49.1 From a12ee2e5aaefd113a3d4c41401ec1cf5ac8be3bd Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 12 Dec 2025 01:36:14 +0800 Subject: [PATCH 04/33] Refactor deployment workflows to streamline code checkout and file transfer processes --- .gitea/workflows/deploy-dev.yml | 47 +++++++++++---------------- .gitea/workflows/deploy.yml | 57 +++++++++++++-------------------- 2 files changed, 42 insertions(+), 62 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index a21948d..a593acb 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -12,37 +12,27 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build Docker Image run: | - docker build -t merchbay_admin:dev . + git clone ${{ gitea.repository_url }} /workspace/repo || true + cd /workspace/repo + git fetch origin ${{ gitea.ref_name }} + git checkout ${{ gitea.ref_name }} + git pull origin ${{ gitea.ref_name }} - - name: Save Docker Image + - name: Setup SSH Key run: | - docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz + mkdir -p ~/.ssh + echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key - - name: Deploy to Development Server via SSH - uses: appleboy/scp-action@master - with: - host: ${{ secrets.DEPLOY_HOST }} - username: ${{ secrets.DEPLOY_USER }} - key: ${{ secrets.DEPLOY_SSH_KEY }} - port: ${{ secrets.DEPLOY_PORT || 22 }} - source: "merchbay_admin_dev.tar.gz,docker-compose.yml" - target: "/tmp/merchbay_admin_dev_deploy" + - name: Transfer Files to Development Server + run: | + cd /workspace/repo + scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin_dev.tar.gz docker-compose.yml ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:/tmp/ - - name: Execute Development Deployment Script - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.DEPLOY_HOST }} - username: ${{ secrets.DEPLOY_USER }} - key: ${{ secrets.DEPLOY_SSH_KEY }} - port: ${{ secrets.DEPLOY_PORT || 22 }} - script: | + - name: Deploy to Development Server + run: | + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} << 'ENDSSH' # Set deployment directory for dev DEPLOY_DIR="/var/www/merchbay_admin_dev" @@ -50,7 +40,7 @@ jobs: mkdir -p $DEPLOY_DIR # Load the Docker image - cd /tmp/merchbay_admin_dev_deploy + cd /tmp docker load < merchbay_admin_dev.tar.gz # Copy docker-compose.yml to deployment directory @@ -100,10 +90,11 @@ jobs: docker compose exec -T app php artisan view:cache # Cleanup - rm -rf /tmp/merchbay_admin_dev_deploy + rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml echo "Development deployment completed successfully!" echo "Application available at: https://dev.merchbay.app" + ENDSSH - name: Health Check run: | diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index d5db9a1..99364f4 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -15,45 +15,33 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Login to Docker Registry (Optional) - if: ${{ secrets.DOCKER_REGISTRY_URL != '' }} - uses: docker/login-action@v2 - with: - registry: ${{ secrets.DOCKER_REGISTRY_URL }} - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + run: | + git clone ${{ gitea.repository_url }} /workspace/repo || true + cd /workspace/repo + git fetch origin ${{ gitea.ref_name }} + git checkout ${{ gitea.ref_name }} + git pull origin ${{ gitea.ref_name }} - name: Build Docker Image run: | + cd /workspace/repo docker build -t merchbay_admin:latest . - - - name: Save Docker Image - run: | docker save merchbay_admin:latest | gzip > merchbay_admin.tar.gz - - name: Deploy to Server via SSH - uses: appleboy/scp-action@master - with: - host: ${{ secrets.DEPLOY_HOST }} - username: ${{ secrets.DEPLOY_USER }} - key: ${{ secrets.DEPLOY_SSH_KEY }} - port: ${{ secrets.DEPLOY_PORT || 22 }} - source: "merchbay_admin.tar.gz,docker-compose.yml" - target: "/tmp/merchbay_admin_deploy" + - name: Setup SSH Key + run: | + mkdir -p ~/.ssh + echo "${{ secrets.PROD_DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key - - name: Execute Production Deployment Script - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.PROD_DEPLOY_HOST }} - username: ${{ secrets.PROD_DEPLOY_USER }} - key: ${{ secrets.PROD_DEPLOY_SSH_KEY }} - port: ${{ secrets.PROD_DEPLOY_PORT || 22 }} - script: | + - name: Transfer Files to Production Server + run: | + cd /workspace/repo + scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml ${{ secrets.PROD_DEPLOY_USER }}@${{ secrets.PROD_DEPLOY_HOST }}:/tmp/ + + - name: Deploy to Production Server + run: | + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key ${{ secrets.PROD_DEPLOY_USER }}@${{ secrets.PROD_DEPLOY_HOST }} << 'ENDSSH' # Set deployment directory for production DEPLOY_DIR="/var/www/merchbay_admin" @@ -61,7 +49,7 @@ jobs: mkdir -p $DEPLOY_DIR # Load the Docker image - cd /tmp/merchbay_admin_deploy + cd /tmp docker load < merchbay_admin.tar.gz # Copy docker-compose.yml to deployment directory @@ -111,10 +99,11 @@ jobs: docker compose exec -T app php artisan view:cache # Cleanup - rm -rf /tmp/merchbay_admin_deploy + rm -f /tmp/merchbay_admin.tar.gz /tmp/docker-compose.yml echo "Production deployment completed successfully!" echo "Application available at: https://merchbay.com" + ENDSSH - name: Health Check run: | -- 2.49.1 From 6f7b81f1da603241169fcc3acdb3388d89d60e15 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 12 Dec 2025 01:37:27 +0800 Subject: [PATCH 05/33] Refactor deployment scripts to use GitHub environment variables and improve SSH key handling --- .gitea/workflows/deploy-dev.yml | 33 +++++++++++++++++++++++++------- .gitea/workflows/deploy.yml | 34 ++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index a593acb..f00a420 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -13,26 +13,44 @@ jobs: steps: - name: Checkout code run: | - git clone ${{ gitea.repository_url }} /workspace/repo || true + #!/bin/sh + git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true cd /workspace/repo - git fetch origin ${{ gitea.ref_name }} - git checkout ${{ gitea.ref_name }} - git pull origin ${{ gitea.ref_name }} + git fetch origin $GITHUB_REF_NAME + git checkout $GITHUB_REF_NAME + git pull origin $GITHUB_REF_NAME - name: Setup SSH Key run: | + #!/bin/sh mkdir -p ~/.ssh - echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key + printf '%s' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - name: Transfer Files to Development Server run: | + #!/bin/sh cd /workspace/repo - scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin_dev.tar.gz docker-compose.yml ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:/tmp/ + scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin_dev.tar.gz docker-compose.yml "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" + env: + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - name: Deploy to Development Server run: | - ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} << 'ENDSSH' + #!/bin/sh + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" << 'ENDSSH' + #!/bin/sh + env: + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} + DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} + DEV_DB_DATABASE: ${{ secrets.DEV_DB_DATABASE }} + DEV_DB_USERNAME: ${{ secrets.DEV_DB_USERNAME }} + DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }} # Set deployment directory for dev DEPLOY_DIR="/var/www/merchbay_admin_dev" @@ -98,5 +116,6 @@ jobs: - name: Health Check run: | + #!/bin/sh sleep 10 curl -f https://dev.merchbay.app || exit 1 diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 99364f4..5aefa26 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -16,32 +16,51 @@ jobs: steps: - name: Checkout code run: | - git clone ${{ gitea.repository_url }} /workspace/repo || true + #!/bin/sh + git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true cd /workspace/repo - git fetch origin ${{ gitea.ref_name }} - git checkout ${{ gitea.ref_name }} - git pull origin ${{ gitea.ref_name }} + git fetch origin $GITHUB_REF_NAME + git checkout $GITHUB_REF_NAME + git pull origin $GITHUB_REF_NAME - name: Build Docker Image run: | + #!/bin/sh cd /workspace/repo docker build -t merchbay_admin:latest . docker save merchbay_admin:latest | gzip > merchbay_admin.tar.gz - name: Setup SSH Key run: | + #!/bin/sh mkdir -p ~/.ssh - echo "${{ secrets.PROD_DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key + printf '%s' "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key + env: + PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }} - name: Transfer Files to Production Server run: | + #!/bin/sh cd /workspace/repo - scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml ${{ secrets.PROD_DEPLOY_USER }}@${{ secrets.PROD_DEPLOY_HOST }}:/tmp/ + scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST:/tmp/" + env: + PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} + PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }} - name: Deploy to Production Server run: | - ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key ${{ secrets.PROD_DEPLOY_USER }}@${{ secrets.PROD_DEPLOY_HOST }} << 'ENDSSH' + #!/bin/sh + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST" << 'ENDSSH' + #!/bin/sh + env: + PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} + PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }} + PROD_DB_HOST: ${{ secrets.PROD_DB_HOST }} + PROD_DB_PORT: ${{ secrets.PROD_DB_PORT }} + PROD_DB_DATABASE: ${{ secrets.PROD_DB_DATABASE }} + PROD_DB_USERNAME: ${{ secrets.PROD_DB_USERNAME }} + PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} # Set deployment directory for production DEPLOY_DIR="/var/www/merchbay_admin" @@ -107,5 +126,6 @@ jobs: - name: Health Check run: | + #!/bin/sh sleep 10 curl -f https://merchbay.com || exit 1 -- 2.49.1 From fa59a081d84e9b855f7790d593c6bfbaa189fbb5 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Fri, 12 Dec 2025 01:39:37 +0800 Subject: [PATCH 06/33] Refactor deployment workflows to enhance SSH handling and streamline Docker image deployment --- .gitea/workflows/deploy-dev.yml | 126 ++++++++++++-------------------- .gitea/workflows/deploy.yml | 123 ++++++++++--------------------- 2 files changed, 84 insertions(+), 165 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index f00a420..3179e91 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -13,37 +13,64 @@ jobs: steps: - name: Checkout code run: | - #!/bin/sh git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true cd /workspace/repo git fetch origin $GITHUB_REF_NAME git checkout $GITHUB_REF_NAME git pull origin $GITHUB_REF_NAME - - name: Setup SSH Key + - name: Build Docker Image + run: | + cd /workspace/repo + docker build -t merchbay_admin:dev . + docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz + + - name: Setup SSH and Deploy run: | - #!/bin/sh mkdir -p ~/.ssh printf '%s' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key - env: - DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - - - name: Transfer Files to Development Server - run: | - #!/bin/sh + cd /workspace/repo scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin_dev.tar.gz docker-compose.yml "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" + + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" " + DEPLOY_DIR='/var/www/merchbay_admin_dev' + mkdir -p \$DEPLOY_DIR + cd /tmp + docker load < merchbay_admin_dev.tar.gz + cp docker-compose.yml \$DEPLOY_DIR/ + cd \$DEPLOY_DIR + + cat > .env <<'ENVEOF' + APP_ENV=staging + APP_DEBUG=false + APP_URL=https://dev.merchbay.app + DB_HOST=$DEV_DB_HOST + DB_PORT=${DEV_DB_PORT:-3306} + DB_DATABASE=$DEV_DB_DATABASE + DB_USERNAME=$DEV_DB_USERNAME + DB_PASSWORD=$DEV_DB_PASSWORD + DOMAIN=dev.merchbay.app + ENVEOF + + docker compose down || true + docker image prune -f + docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public + export DOMAIN=dev.merchbay.app + export APP_URL=https://dev.merchbay.app + docker compose up -d + sleep 10 + docker compose exec -T app php artisan migrate --force + docker compose exec -T app php artisan config:cache + docker compose exec -T app php artisan route:cache + docker compose exec -T app php artisan view:cache + rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml + echo 'Development deployment completed successfully!' + echo 'Application available at: https://dev.merchbay.app' + " env: - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - - - name: Deploy to Development Server - run: | - #!/bin/sh - ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" << 'ENDSSH' - #!/bin/sh - env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} @@ -51,71 +78,8 @@ jobs: DEV_DB_DATABASE: ${{ secrets.DEV_DB_DATABASE }} DEV_DB_USERNAME: ${{ secrets.DEV_DB_USERNAME }} DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }} - # Set deployment directory for dev - DEPLOY_DIR="/var/www/merchbay_admin_dev" - - # Create deployment directory if it doesn't exist - mkdir -p $DEPLOY_DIR - - # Load the Docker image - cd /tmp - docker load < merchbay_admin_dev.tar.gz - - # Copy docker-compose.yml to deployment directory - cp docker-compose.yml $DEPLOY_DIR/ - - # Navigate to deployment directory - cd $DEPLOY_DIR - - # Update environment file for dev - cat > .env << EOF - APP_ENV=staging - APP_DEBUG=false - APP_URL=https://dev.merchbay.app - DB_HOST=${{ secrets.DEV_DB_HOST }} - DB_PORT=${{ secrets.DEV_DB_PORT || 3306 }} - DB_DATABASE=${{ secrets.DEV_DB_DATABASE }} - DB_USERNAME=${{ secrets.DEV_DB_USERNAME }} - DB_PASSWORD=${{ secrets.DEV_DB_PASSWORD }} - DOMAIN=dev.merchbay.app - EOF - - # Stop existing container - docker compose down || true - - # Remove old image - docker image prune -f - - # Ensure Traefik network exists - docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public - - # Update docker-compose for dev - export DOMAIN=dev.merchbay.app - export APP_URL=https://dev.merchbay.app - - # Start the application - docker compose up -d - - # Wait for container to be ready - sleep 10 - - # Run migrations - docker compose exec -T app php artisan migrate --force - - # Clear and cache configuration - docker compose exec -T app php artisan config:cache - docker compose exec -T app php artisan route:cache - docker compose exec -T app php artisan view:cache - - # Cleanup - rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml - - echo "Development deployment completed successfully!" - echo "Application available at: https://dev.merchbay.app" - ENDSSH - name: Health Check run: | - #!/bin/sh sleep 10 curl -f https://dev.merchbay.app || exit 1 diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 5aefa26..cabbcb5 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -10,13 +10,10 @@ on: jobs: deploy: runs-on: ubuntu-latest - # If using self-hosted runner, change to: - # runs-on: self-hosted steps: - name: Checkout code run: | - #!/bin/sh git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true cd /workspace/repo git fetch origin $GITHUB_REF_NAME @@ -25,35 +22,56 @@ jobs: - name: Build Docker Image run: | - #!/bin/sh cd /workspace/repo docker build -t merchbay_admin:latest . docker save merchbay_admin:latest | gzip > merchbay_admin.tar.gz - - name: Setup SSH Key + - name: Setup SSH and Deploy run: | - #!/bin/sh mkdir -p ~/.ssh printf '%s' "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key - env: - PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }} - - - name: Transfer Files to Production Server - run: | - #!/bin/sh + cd /workspace/repo scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST:/tmp/" + + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST" " + DEPLOY_DIR='/var/www/merchbay_admin' + mkdir -p \$DEPLOY_DIR + cd /tmp + docker load < merchbay_admin.tar.gz + cp docker-compose.yml \$DEPLOY_DIR/ + cd \$DEPLOY_DIR + + cat > .env <<'ENVEOF' + APP_ENV=production + APP_DEBUG=false + APP_URL=https://merchbay.com + DB_HOST=$PROD_DB_HOST + DB_PORT=${PROD_DB_PORT:-3306} + DB_DATABASE=$PROD_DB_DATABASE + DB_USERNAME=$PROD_DB_USERNAME + DB_PASSWORD=$PROD_DB_PASSWORD + DOMAIN=merchbay.com + ENVEOF + + docker compose down || true + docker image prune -f + docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public + export DOMAIN=merchbay.com + export APP_URL=https://merchbay.com + docker compose up -d + sleep 10 + docker compose exec -T app php artisan migrate --force + docker compose exec -T app php artisan config:cache + docker compose exec -T app php artisan route:cache + docker compose exec -T app php artisan view:cache + rm -f /tmp/merchbay_admin.tar.gz /tmp/docker-compose.yml + echo 'Production deployment completed successfully!' + echo 'Application available at: https://merchbay.com' + " env: - PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} - PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }} - - - name: Deploy to Production Server - run: | - #!/bin/sh - ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST" << 'ENDSSH' - #!/bin/sh - env: + PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }} PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }} PROD_DB_HOST: ${{ secrets.PROD_DB_HOST }} @@ -61,71 +79,8 @@ jobs: PROD_DB_DATABASE: ${{ secrets.PROD_DB_DATABASE }} PROD_DB_USERNAME: ${{ secrets.PROD_DB_USERNAME }} PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} - # Set deployment directory for production - DEPLOY_DIR="/var/www/merchbay_admin" - - # Create deployment directory if it doesn't exist - mkdir -p $DEPLOY_DIR - - # Load the Docker image - cd /tmp - docker load < merchbay_admin.tar.gz - - # Copy docker-compose.yml to deployment directory - cp docker-compose.yml $DEPLOY_DIR/ - - # Navigate to deployment directory - cd $DEPLOY_DIR - - # Update environment file for production - cat > .env << EOF - APP_ENV=production - APP_DEBUG=false - APP_URL=https://merchbay.com - DB_HOST=${{ secrets.PROD_DB_HOST }} - DB_PORT=${{ secrets.PROD_DB_PORT || 3306 }} - DB_DATABASE=${{ secrets.PROD_DB_DATABASE }} - DB_USERNAME=${{ secrets.PROD_DB_USERNAME }} - DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }} - DOMAIN=merchbay.com - EOF - - # Stop existing container (disconnect from Traefik network gracefully) - docker compose down || true - - # Remove old image (optional, keeps only latest) - docker image prune -f - - # Ensure Traefik network exists - docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public - - # Update docker-compose for production - export DOMAIN=merchbay.com - export APP_URL=https://merchbay.com - - # Start the application (will auto-connect to Traefik with paid SSL) - docker compose up -d - - # Wait for container to be ready - sleep 10 - - # Run migrations - docker compose exec -T app php artisan migrate --force - - # Clear and cache configuration - docker compose exec -T app php artisan config:cache - docker compose exec -T app php artisan route:cache - docker compose exec -T app php artisan view:cache - - # Cleanup - rm -f /tmp/merchbay_admin.tar.gz /tmp/docker-compose.yml - - echo "Production deployment completed successfully!" - echo "Application available at: https://merchbay.com" - ENDSSH - name: Health Check run: | - #!/bin/sh sleep 10 curl -f https://merchbay.com || exit 1 -- 2.49.1 From af0d8cd9ac04409548b065db535aca3ac36f20f3 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Sat, 13 Dec 2025 02:58:29 +0800 Subject: [PATCH 07/33] Add container specification and shell definitions to deployment workflows --- .gitea/workflows/build-push.yml | 2 ++ .gitea/workflows/deploy-dev.yml | 6 ++++++ .gitea/workflows/deploy.yml | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/.gitea/workflows/build-push.yml b/.gitea/workflows/build-push.yml index a80c2dc..06f3dab 100644 --- a/.gitea/workflows/build-push.yml +++ b/.gitea/workflows/build-push.yml @@ -9,6 +9,8 @@ on: jobs: build-and-push: runs-on: ubuntu-latest + container: + image: catthehacker/ubuntu:act-latest steps: - name: Checkout code diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 3179e91..f376506 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -9,9 +9,12 @@ on: jobs: deploy: runs-on: ubuntu-latest + container: + image: catthehacker/ubuntu:act-latest steps: - name: Checkout code + shell: sh run: | git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true cd /workspace/repo @@ -20,12 +23,14 @@ jobs: git pull origin $GITHUB_REF_NAME - name: Build Docker Image + shell: sh run: | cd /workspace/repo docker build -t merchbay_admin:dev . docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz - name: Setup SSH and Deploy + shell: sh run: | mkdir -p ~/.ssh printf '%s' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key @@ -80,6 +85,7 @@ jobs: DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }} - name: Health Check + shell: sh run: | sleep 10 curl -f https://dev.merchbay.app || exit 1 diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index cabbcb5..5d7e58a 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -10,9 +10,12 @@ on: jobs: deploy: runs-on: ubuntu-latest + container: + image: catthehacker/ubuntu:act-latest steps: - name: Checkout code + shell: sh run: | git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true cd /workspace/repo @@ -21,12 +24,14 @@ jobs: git pull origin $GITHUB_REF_NAME - name: Build Docker Image + shell: sh run: | cd /workspace/repo docker build -t merchbay_admin:latest . docker save merchbay_admin:latest | gzip > merchbay_admin.tar.gz - name: Setup SSH and Deploy + shell: sh run: | mkdir -p ~/.ssh printf '%s' "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key @@ -81,6 +86,7 @@ jobs: PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} - name: Health Check + shell: sh run: | sleep 10 curl -f https://merchbay.com || exit 1 -- 2.49.1 From a4171330e54bc9aa5c984496e0fb107825eae324 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 13:18:29 +0800 Subject: [PATCH 08/33] Enhance deployment workflows with additional input parameters and setup scripts --- .gitea/workflows/build-push.yml | 9 ++ .gitea/workflows/deploy-dev.yml | 27 ++--- .gitea/workflows/deploy.yml | 18 +-- DEPLOYMENT-SETUP.md | 187 ++++++++++++++++++++++++++++++++ setup-server-env.sh | 153 ++++++++++++++++++++++++++ setup-ssh-keys.sh | 90 +++++++++++++++ 6 files changed, 452 insertions(+), 32 deletions(-) create mode 100644 DEPLOYMENT-SETUP.md create mode 100755 setup-server-env.sh create mode 100755 setup-ssh-keys.sh diff --git a/.gitea/workflows/build-push.yml b/.gitea/workflows/build-push.yml index 06f3dab..88b0bd8 100644 --- a/.gitea/workflows/build-push.yml +++ b/.gitea/workflows/build-push.yml @@ -5,6 +5,15 @@ on: tags: - 'v*' workflow_dispatch: + inputs: + tag: + description: 'Docker image tag (e.g., v1.0.0, latest)' + required: false + default: 'latest' + push_to_registry: + description: 'Push to registry?' + required: false + default: 'true' jobs: build-and-push: diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index f376506..5c6b3eb 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -5,6 +5,15 @@ on: branches: - dev workflow_dispatch: + inputs: + skip_health_check: + description: 'Skip health check?' + required: false + default: 'false' + run_migrations: + description: 'Run database migrations?' + required: false + default: 'true' jobs: deploy: @@ -47,17 +56,8 @@ jobs: cp docker-compose.yml \$DEPLOY_DIR/ cd \$DEPLOY_DIR - cat > .env <<'ENVEOF' - APP_ENV=staging - APP_DEBUG=false - APP_URL=https://dev.merchbay.app - DB_HOST=$DEV_DB_HOST - DB_PORT=${DEV_DB_PORT:-3306} - DB_DATABASE=$DEV_DB_DATABASE - DB_USERNAME=$DEV_DB_USERNAME - DB_PASSWORD=$DEV_DB_PASSWORD - DOMAIN=dev.merchbay.app - ENVEOF + # .env file should already exist on server with all secrets + # If it doesn't exist, deployment will fail (this is intentional for security) docker compose down || true docker image prune -f @@ -78,11 +78,6 @@ jobs: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - DEV_DB_HOST: ${{ secrets.DEV_DB_HOST }} - DEV_DB_PORT: ${{ secrets.DEV_DB_PORT }} - DEV_DB_DATABASE: ${{ secrets.DEV_DB_DATABASE }} - DEV_DB_USERNAME: ${{ secrets.DEV_DB_USERNAME }} - DEV_DB_PASSWORD: ${{ secrets.DEV_DB_PASSWORD }} - name: Health Check shell: sh diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 5d7e58a..dc49d0c 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -48,17 +48,8 @@ jobs: cp docker-compose.yml \$DEPLOY_DIR/ cd \$DEPLOY_DIR - cat > .env <<'ENVEOF' - APP_ENV=production - APP_DEBUG=false - APP_URL=https://merchbay.com - DB_HOST=$PROD_DB_HOST - DB_PORT=${PROD_DB_PORT:-3306} - DB_DATABASE=$PROD_DB_DATABASE - DB_USERNAME=$PROD_DB_USERNAME - DB_PASSWORD=$PROD_DB_PASSWORD - DOMAIN=merchbay.com - ENVEOF + # .env file should already exist on server with all secrets + # If it doesn't exist, deployment will fail (this is intentional for security) docker compose down || true docker image prune -f @@ -79,11 +70,6 @@ jobs: PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }} PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }} - PROD_DB_HOST: ${{ secrets.PROD_DB_HOST }} - PROD_DB_PORT: ${{ secrets.PROD_DB_PORT }} - PROD_DB_DATABASE: ${{ secrets.PROD_DB_DATABASE }} - PROD_DB_USERNAME: ${{ secrets.PROD_DB_USERNAME }} - PROD_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }} - name: Health Check shell: sh diff --git a/DEPLOYMENT-SETUP.md b/DEPLOYMENT-SETUP.md new file mode 100644 index 0000000..bdd52d7 --- /dev/null +++ b/DEPLOYMENT-SETUP.md @@ -0,0 +1,187 @@ +# Deployment Setup Guide + +This guide will help you set up your deployment infrastructure for the MerchBay Admin application. + +## Quick Start + +We've created two helper scripts to simplify the setup process: + +### 1. Setup SSH Keys (`setup-ssh-keys.sh`) + +Generate and configure SSH keys for Gitea deployment. + +```bash +./setup-ssh-keys.sh +``` + +**What it does:** +- Generates an SSH key pair for deployment +- Shows you the private key to add to Gitea secrets +- Optionally deploys the public key to your server +- Tests the SSH connection + +### 2. Setup Server Environment (`setup-server-env.sh`) + +Configure `.env` files on your deployment servers. + +```bash +./setup-server-env.sh +``` + +**What it does:** +- Guides you through environment configuration +- Creates `.env` file on your server +- Shows you which Gitea secrets are needed +- Supports both production and development environments + +## Manual Setup (Alternative) + +If you prefer manual setup, follow these steps: + +### Step 1: Generate SSH Keys + +```bash +# Generate SSH key +ssh-keygen -t ed25519 -C "gitea-deploy-key" -f ~/.ssh/gitea_deploy_key -N "" + +# View private key (for Gitea) +cat ~/.ssh/gitea_deploy_key + +# View public key (for server) +cat ~/.ssh/gitea_deploy_key.pub +``` + +### Step 2: Add Public Key to Server + +```bash +# SSH to your server +ssh user@your-server + +# Add public key +mkdir -p ~/.ssh +echo "your-public-key-here" >> ~/.ssh/authorized_keys +chmod 600 ~/.ssh/authorized_keys +``` + +### Step 3: Create .env Files on Server + +**Production Server:** +```bash +ssh user@prod-server + +mkdir -p /var/www/merchbay_admin +cat > /var/www/merchbay_admin/.env << 'EOF' +APP_ENV=production +APP_DEBUG=false +APP_URL=https://merchbay.com +DB_HOST=localhost +DB_PORT=3306 +DB_DATABASE=merchbay_prod +DB_USERNAME=merchbay_user +DB_PASSWORD=your_secure_password +DOMAIN=merchbay.com +EOF + +chmod 600 /var/www/merchbay_admin/.env +``` + +**Development Server:** +```bash +ssh user@dev-server + +mkdir -p /var/www/merchbay_admin_dev +cat > /var/www/merchbay_admin_dev/.env << 'EOF' +APP_ENV=staging +APP_DEBUG=false +APP_URL=https://dev.merchbay.app +DB_HOST=localhost +DB_PORT=3306 +DB_DATABASE=merchbay_dev +DB_USERNAME=merchbay_user +DB_PASSWORD=your_dev_password +DOMAIN=dev.merchbay.app +EOF + +chmod 600 /var/www/merchbay_admin_dev/.env +``` + +### Step 4: Add Secrets to Gitea + +Go to your Gitea repository → Settings → Secrets + +**For Production (deploy.yml):** +- `PROD_DEPLOY_SSH_KEY` - Your private SSH key content +- `PROD_DEPLOY_USER` - SSH username (e.g., `root`) +- `PROD_DEPLOY_HOST` - Server IP/hostname + +**For Development (deploy-dev.yml):** +- `DEPLOY_SSH_KEY` - Your private SSH key content +- `DEPLOY_USER` - SSH username (e.g., `root`) +- `DEPLOY_HOST` - Server IP/hostname + +**For Docker Registry (build-push.yml):** +- `DOCKER_REGISTRY_URL` - Your registry URL +- `DOCKER_USERNAME` - Registry username +- `DOCKER_PASSWORD` - Registry password + +## Benefits of This Approach + +✅ **Fewer Secrets** - Only 3 secrets per environment instead of 8+ +✅ **Centralized** - All database/app secrets stay on the server +✅ **Reusable** - Same SSH credentials work for all apps +✅ **Secure** - Secrets never appear in CI/CD logs +✅ **Easy Updates** - Edit `.env` files directly on server + +## Troubleshooting + +### SSH Connection Issues + +```bash +# Test SSH connection +ssh -i ~/.ssh/gitea_deploy_key user@server + +# Check SSH key permissions +chmod 600 ~/.ssh/gitea_deploy_key +chmod 644 ~/.ssh/gitea_deploy_key.pub +``` + +### Workflow Fails with "Could not resolve hostname" + +- Make sure all secrets are added to Gitea +- Verify `DEPLOY_HOST` / `PROD_DEPLOY_HOST` is correct +- Check `DEPLOY_USER` / `PROD_DEPLOY_USER` is set + +### .env File Not Found + +- Run `./setup-server-env.sh` to create it +- Or manually create `.env` file on server at: + - Production: `/var/www/merchbay_admin/.env` + - Development: `/var/www/merchbay_admin_dev/.env` + +## Multiple Applications + +To deploy multiple applications using the same setup: + +1. **Use the same SSH keys** - No need to generate new ones +2. **Create separate .env files** - One per app on the server +3. **Only 3 Gitea secrets total** - Reuse across all apps! + +Example for another app: +```bash +# Same SSH key works! +# Just create new .env file +ssh user@server +mkdir -p /var/www/another_app +cat > /var/www/another_app/.env << 'EOF' +# App-specific configuration +EOF +``` + +## Security Best Practices + +- ✅ Never commit `.env` files to git +- ✅ Keep private keys secure +- ✅ Use strong database passwords +- ✅ Restrict SSH key permissions (600) +- ✅ Use different passwords for prod/dev +- ✅ Regularly rotate credentials diff --git a/setup-server-env.sh b/setup-server-env.sh new file mode 100755 index 0000000..0196fca --- /dev/null +++ b/setup-server-env.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +# Server Environment Setup Script +# This script helps you set up .env files on your deployment servers + +set -e + +echo "================================================" +echo "Server Environment Setup for MerchBay Admin" +echo "================================================" +echo "" + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to prompt for input with default value +prompt_input() { + local prompt="$1" + local default="$2" + local value + + if [ -n "$default" ]; then + read -p "$prompt [$default]: " value + echo "${value:-$default}" + else + read -p "$prompt: " value + echo "$value" + fi +} + +# Function to prompt for password (hidden input) +prompt_password() { + local prompt="$1" + local value + + read -s -p "$prompt: " value + echo "" + echo "$value" +} + +# Choose environment +echo "Which environment are you setting up?" +echo "1) Production" +echo "2) Development" +read -p "Enter choice [1-2]: " env_choice + +case $env_choice in + 1) + ENV_TYPE="production" + DEPLOY_DIR="/var/www/merchbay_admin" + DEFAULT_DOMAIN="merchbay.com" + DEFAULT_APP_URL="https://merchbay.com" + DEFAULT_APP_ENV="production" + DEFAULT_DB_NAME="merchbay_prod" + ;; + 2) + ENV_TYPE="development" + DEPLOY_DIR="/var/www/merchbay_admin_dev" + DEFAULT_DOMAIN="dev.merchbay.app" + DEFAULT_APP_URL="https://dev.merchbay.app" + DEFAULT_APP_ENV="staging" + DEFAULT_DB_NAME="merchbay_dev" + ;; + *) + echo -e "${RED}Invalid choice${NC}" + exit 1 + ;; +esac + +echo -e "\n${GREEN}Setting up $ENV_TYPE environment${NC}\n" + +# Collect information +echo "=== Application Settings ===" +APP_ENV=$(prompt_input "APP_ENV" "$DEFAULT_APP_ENV") +APP_DEBUG=$(prompt_input "APP_DEBUG (true/false)" "false") +APP_URL=$(prompt_input "APP_URL" "$DEFAULT_APP_URL") +DOMAIN=$(prompt_input "DOMAIN" "$DEFAULT_DOMAIN") + +echo -e "\n=== Database Settings ===" +DB_HOST=$(prompt_input "DB_HOST" "localhost") +DB_PORT=$(prompt_input "DB_PORT" "3306") +DB_DATABASE=$(prompt_input "DB_DATABASE" "$DEFAULT_DB_NAME") +DB_USERNAME=$(prompt_input "DB_USERNAME" "merchbay_user") +DB_PASSWORD=$(prompt_password "DB_PASSWORD") + +echo -e "\n=== Server Connection ===" +SERVER_USER=$(prompt_input "SSH Username" "root") +SERVER_HOST=$(prompt_input "Server IP/Hostname" "") + +if [ -z "$SERVER_HOST" ]; then + echo -e "${RED}Error: Server hostname is required${NC}" + exit 1 +fi + +# Generate .env content +ENV_CONTENT="APP_ENV=$APP_ENV +APP_DEBUG=$APP_DEBUG +APP_URL=$APP_URL +DB_HOST=$DB_HOST +DB_PORT=$DB_PORT +DB_DATABASE=$DB_DATABASE +DB_USERNAME=$DB_USERNAME +DB_PASSWORD=$DB_PASSWORD +DOMAIN=$DOMAIN" + +# Show summary +echo -e "\n${YELLOW}=== Configuration Summary ===${NC}" +echo "Environment: $ENV_TYPE" +echo "Deploy Directory: $DEPLOY_DIR" +echo "Server: $SERVER_USER@$SERVER_HOST" +echo "Domain: $DOMAIN" +echo "Database: $DB_DATABASE" +echo "" + +# Ask for confirmation +read -p "Deploy this configuration to the server? (y/n): " confirm + +if [ "$confirm" != "y" ]; then + echo "Aborted." + exit 0 +fi + +# Deploy to server +echo -e "\n${GREEN}Deploying configuration to server...${NC}" + +# Create deployment directory and .env file +ssh "$SERVER_USER@$SERVER_HOST" "mkdir -p $DEPLOY_DIR" + +# Upload .env file +echo "$ENV_CONTENT" | ssh "$SERVER_USER@$SERVER_HOST" "cat > $DEPLOY_DIR/.env && chmod 600 $DEPLOY_DIR/.env" + +echo -e "\n${GREEN}✓ Configuration deployed successfully!${NC}" +echo -e "\nThe .env file has been created at: ${YELLOW}$DEPLOY_DIR/.env${NC}" +echo "" + +# Display Gitea secrets needed +echo -e "${YELLOW}=== Gitea Secrets Required ===${NC}" +if [ "$ENV_TYPE" = "production" ]; then + echo "Add these secrets to your Gitea repository:" + echo " • PROD_DEPLOY_SSH_KEY: Your SSH private key" + echo " • PROD_DEPLOY_USER: $SERVER_USER" + echo " • PROD_DEPLOY_HOST: $SERVER_HOST" +else + echo "Add these secrets to your Gitea repository:" + echo " • DEPLOY_SSH_KEY: Your SSH private key" + echo " • DEPLOY_USER: $SERVER_USER" + echo " • DEPLOY_HOST: $SERVER_HOST" +fi + +echo -e "\n${GREEN}Setup complete!${NC}" diff --git a/setup-ssh-keys.sh b/setup-ssh-keys.sh new file mode 100755 index 0000000..d1ccaa7 --- /dev/null +++ b/setup-ssh-keys.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# SSH Key Generation Script for Gitea Deployment +# This script generates SSH keys and helps you set them up + +set -e + +echo "================================================" +echo "SSH Key Setup for Gitea Deployment" +echo "================================================" +echo "" + +# Color codes +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +SSH_KEY_PATH="$HOME/.ssh/gitea_deploy_key" + +# Check if key already exists +if [ -f "$SSH_KEY_PATH" ]; then + echo -e "${YELLOW}Warning: SSH key already exists at $SSH_KEY_PATH${NC}" + read -p "Do you want to overwrite it? (y/n): " overwrite + if [ "$overwrite" != "y" ]; then + echo "Using existing key." + else + rm -f "$SSH_KEY_PATH" "$SSH_KEY_PATH.pub" + echo "Generating new SSH key..." + ssh-keygen -t ed25519 -C "gitea-deploy-key" -f "$SSH_KEY_PATH" -N "" + fi +else + echo "Generating new SSH key..." + ssh-keygen -t ed25519 -C "gitea-deploy-key" -f "$SSH_KEY_PATH" -N "" +fi + +echo -e "\n${GREEN}✓ SSH key generated successfully!${NC}\n" + +# Display private key for Gitea +echo -e "${YELLOW}=== PRIVATE KEY (for Gitea Secrets) ===${NC}" +echo -e "${BLUE}Copy this ENTIRE content for your Gitea secret:${NC}\n" +cat "$SSH_KEY_PATH" +echo "" + +# Display public key for server +echo -e "\n${YELLOW}=== PUBLIC KEY (for Server) ===${NC}" +echo -e "${BLUE}Copy this content to add to your server's ~/.ssh/authorized_keys:${NC}\n" +cat "$SSH_KEY_PATH.pub" +echo "" + +# Ask if user wants to deploy to server now +echo -e "\n${YELLOW}=== Deploy Public Key to Server ===${NC}" +read -p "Do you want to add the public key to a server now? (y/n): " deploy_now + +if [ "$deploy_now" = "y" ]; then + read -p "Enter SSH username: " ssh_user + read -p "Enter server IP/hostname: " ssh_host + + echo -e "\nAdding public key to $ssh_user@$ssh_host..." + + # Copy public key to server + ssh-copy-id -i "$SSH_KEY_PATH.pub" "$ssh_user@$ssh_host" 2>/dev/null || \ + ssh "$ssh_user@$ssh_host" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" < "$SSH_KEY_PATH.pub" + + echo -e "\n${GREEN}✓ Public key added to server!${NC}" + + # Test connection + echo -e "\nTesting SSH connection..." + if ssh -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no "$ssh_user@$ssh_host" "echo 'Connection successful!'" 2>/dev/null; then + echo -e "${GREEN}✓ SSH connection test successful!${NC}" + else + echo -e "${YELLOW}⚠ SSH connection test failed. Please check your server configuration.${NC}" + fi +fi + +# Summary +echo -e "\n${GREEN}=== Setup Complete! ===${NC}" +echo -e "\n${YELLOW}Next Steps:${NC}" +echo "1. Copy the PRIVATE KEY above and add it to Gitea Secrets as:" +echo " • DEPLOY_SSH_KEY (for dev)" +echo " • PROD_DEPLOY_SSH_KEY (for production)" +echo "" +echo "2. If you didn't deploy the public key yet, manually add it to your server:" +echo " ssh user@server" +echo " echo '$(cat "$SSH_KEY_PATH.pub")' >> ~/.ssh/authorized_keys" +echo "" +echo "3. The key files are saved at:" +echo " Private: $SSH_KEY_PATH" +echo " Public: $SSH_KEY_PATH.pub" +echo "" -- 2.49.1 From 632f143637ac96c46e13521340a608ee5bb2d301 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 13:22:35 +0800 Subject: [PATCH 09/33] Refactor SSH setup in deployment workflows to enhance security and error handling --- .gitea/workflows/deploy-dev.yml | 4 +++- .gitea/workflows/deploy.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 5c6b3eb..a383f74 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -42,8 +42,10 @@ jobs: shell: sh run: | mkdir -p ~/.ssh - printf '%s' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key + chmod 700 ~/.ssh + echo "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key + ssh-keygen -y -f ~/.ssh/deploy_key > /dev/null 2>&1 || { echo "Error: Invalid SSH key format"; exit 1; } cd /workspace/repo scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin_dev.tar.gz docker-compose.yml "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index dc49d0c..f379cc9 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -34,8 +34,10 @@ jobs: shell: sh run: | mkdir -p ~/.ssh - printf '%s' "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key + chmod 700 ~/.ssh + echo "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key + ssh-keygen -y -f ~/.ssh/deploy_key > /dev/null 2>&1 || { echo "Error: Invalid SSH key format"; exit 1; } cd /workspace/repo scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST:/tmp/" -- 2.49.1 From 63c5c505783c042ff1e9b9c9377c42f8fa252914 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 13:33:09 +0800 Subject: [PATCH 10/33] Update domain and application URL to dev-admin.merchbay.app across deployment configurations --- .gitea/workflows/deploy-dev.yml | 8 ++++---- DEPLOYMENT-SETUP.md | 4 ++-- TRAEFIK-SSL-CONFIG.md | 14 +++++++------- docker-compose.portainer.dev.yml | 6 +++--- setup-server-env.sh | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index a383f74..2c79bb0 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -64,8 +64,8 @@ jobs: docker compose down || true docker image prune -f docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public - export DOMAIN=dev.merchbay.app - export APP_URL=https://dev.merchbay.app + export DOMAIN=dev-admin.merchbay.app + export APP_URL=https://dev-admin.merchbay.app docker compose up -d sleep 10 docker compose exec -T app php artisan migrate --force @@ -74,7 +74,7 @@ jobs: docker compose exec -T app php artisan view:cache rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml echo 'Development deployment completed successfully!' - echo 'Application available at: https://dev.merchbay.app' + echo 'Application available at: https://dev-admin.merchbay.app' " env: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} @@ -85,4 +85,4 @@ jobs: shell: sh run: | sleep 10 - curl -f https://dev.merchbay.app || exit 1 + curl -f https://dev-admin.merchbay.app || exit 1 diff --git a/DEPLOYMENT-SETUP.md b/DEPLOYMENT-SETUP.md index bdd52d7..49bd057 100644 --- a/DEPLOYMENT-SETUP.md +++ b/DEPLOYMENT-SETUP.md @@ -93,13 +93,13 @@ mkdir -p /var/www/merchbay_admin_dev cat > /var/www/merchbay_admin_dev/.env << 'EOF' APP_ENV=staging APP_DEBUG=false -APP_URL=https://dev.merchbay.app +APP_URL=https://dev-admin.merchbay.app DB_HOST=localhost DB_PORT=3306 DB_DATABASE=merchbay_dev DB_USERNAME=merchbay_user DB_PASSWORD=your_dev_password -DOMAIN=dev.merchbay.app +DOMAIN=dev-admin.merchbay.app EOF chmod 600 /var/www/merchbay_admin_dev/.env diff --git a/TRAEFIK-SSL-CONFIG.md b/TRAEFIK-SSL-CONFIG.md index 3459020..cd51dc4 100644 --- a/TRAEFIK-SSL-CONFIG.md +++ b/TRAEFIK-SSL-CONFIG.md @@ -11,7 +11,7 @@ All deployments use the external network: `traefik-public` docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public ``` -## Development (dev.merchbay.app) - Automatic SSL +## Development (dev-admin.merchbay.app) - Automatic SSL Development uses Let's Encrypt for automatic SSL certificate generation. @@ -133,13 +133,13 @@ docker compose logs traefik | grep -i cert File: `docker-compose.portainer.dev.yml` -- Domain: `dev.merchbay.app` +- Domain: `dev-admin.merchbay.app` - SSL: Let's Encrypt (automatic) - Certificate Resolver: `letsencrypt` ```yaml labels: - - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)" - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" ``` @@ -199,7 +199,7 @@ DEPLOY_PORT=22 ```bash # Check certificate issuer (should be Let's Encrypt) -echo | openssl s_client -servername dev.merchbay.app -connect dev.merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer +echo | openssl s_client -servername dev-admin.merchbay.app -connect dev-admin.merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer # Should show: issuer=C = US, O = Let's Encrypt, CN = R3 ``` @@ -216,7 +216,7 @@ echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/de ### Verify in Browser -1. Visit https://dev.merchbay.app +1. Visit https://dev-admin.merchbay.app - Certificate should be issued by "Let's Encrypt Authority X3" 2. Visit https://merchbay.com @@ -235,7 +235,7 @@ ls -l /path/to/letsencrypt/acme.json # Should be: -rw------- (600) # Check DNS -dig dev.merchbay.app +short +dig dev-admin.merchbay.app +short # Should return your server IP ``` @@ -285,7 +285,7 @@ Before certificate expiration: ``` Type: A -Name: dev.merchbay.app +Name: dev-admin.merchbay.app Value: YOUR_SERVER_IP TTL: 3600 ``` diff --git a/docker-compose.portainer.dev.yml b/docker-compose.portainer.dev.yml index 09d14d5..1e9865a 100644 --- a/docker-compose.portainer.dev.yml +++ b/docker-compose.portainer.dev.yml @@ -12,7 +12,7 @@ services: environment: - APP_ENV=staging - APP_DEBUG=false - - APP_URL=https://dev.merchbay.app + - APP_URL=https://dev-admin.merchbay.app - DB_CONNECTION=mysql - DB_HOST=your-mysql-host - DB_PORT=3306 @@ -24,13 +24,13 @@ services: - app_uploads_dev:/var/www/html/public/uploads labels: - "traefik.enable=true" - - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)" - "traefik.http.routers.merchbay-admin-dev.entrypoints=websecure" - "traefik.http.routers.merchbay-admin-dev.tls=true" - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" - "traefik.http.services.merchbay-admin-dev.loadbalancer.server.port=80" # HTTP to HTTPS redirect - - "traefik.http.routers.merchbay-admin-dev-http.rule=Host(`dev.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev-http.rule=Host(`dev-admin.merchbay.app`)" - "traefik.http.routers.merchbay-admin-dev-http.entrypoints=web" - "traefik.http.routers.merchbay-admin-dev-http.middlewares=https-redirect" - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" diff --git a/setup-server-env.sh b/setup-server-env.sh index 0196fca..3ea7d17 100755 --- a/setup-server-env.sh +++ b/setup-server-env.sh @@ -59,8 +59,8 @@ case $env_choice in 2) ENV_TYPE="development" DEPLOY_DIR="/var/www/merchbay_admin_dev" - DEFAULT_DOMAIN="dev.merchbay.app" - DEFAULT_APP_URL="https://dev.merchbay.app" + DEFAULT_DOMAIN="dev-admin.merchbay.app" + DEFAULT_APP_URL="https://dev-admin.merchbay.app" DEFAULT_APP_ENV="staging" DEFAULT_DB_NAME="merchbay_dev" ;; -- 2.49.1 From 9d0bae2dea77495cbd1fa2474dd316bbf9c1e256 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 13:57:04 +0800 Subject: [PATCH 11/33] Refactor deployment workflow by removing unnecessary input parameters and enhancing SSH setup for improved security and reliability --- .gitea/workflows/deploy-dev.yml | 76 ++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 2c79bb0..5b0aa2d 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -5,29 +5,19 @@ on: branches: - dev workflow_dispatch: - inputs: - skip_health_check: - description: 'Skip health check?' - required: false - default: 'false' - run_migrations: - description: 'Run database migrations?' - required: false - default: 'true' jobs: deploy: runs-on: ubuntu-latest container: image: catthehacker/ubuntu:act-latest - + steps: - name: Checkout code shell: sh run: | - git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true + git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo cd /workspace/repo - git fetch origin $GITHUB_REF_NAME git checkout $GITHUB_REF_NAME git pull origin $GITHUB_REF_NAME @@ -38,46 +28,64 @@ jobs: docker build -t merchbay_admin:dev . docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz - - name: Setup SSH and Deploy + - name: Setup SSH shell: sh run: | mkdir -p ~/.ssh chmod 700 ~/.ssh - echo "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key - chmod 600 ~/.ssh/deploy_key - ssh-keygen -y -f ~/.ssh/deploy_key > /dev/null 2>&1 || { echo "Error: Invalid SSH key format"; exit 1; } - + + echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + + ssh-keyscan -H ${DEPLOY_HOST} >> ~/.ssh/known_hosts + env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + + - name: Deploy to Server + shell: sh + run: | cd /workspace/repo - scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin_dev.tar.gz docker-compose.yml "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" - - ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" " - DEPLOY_DIR='/var/www/merchbay_admin_dev' - mkdir -p \$DEPLOY_DIR + + scp -i ~/.ssh/id_ed25519 \ + merchbay_admin_dev.tar.gz docker-compose.yml \ + ${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/ + + ssh -i ~/.ssh/id_ed25519 ${DEPLOY_USER}@${DEPLOY_HOST} << 'EOF' + set -e + + DEPLOY_DIR="/var/www/merchbay_admin_dev" + + mkdir -p $DEPLOY_DIR cd /tmp + docker load < merchbay_admin_dev.tar.gz - cp docker-compose.yml \$DEPLOY_DIR/ - cd \$DEPLOY_DIR - - # .env file should already exist on server with all secrets - # If it doesn't exist, deployment will fail (this is intentional for security) - + cp docker-compose.yml $DEPLOY_DIR/ + + cd $DEPLOY_DIR + docker compose down || true docker image prune -f - docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public + + docker network inspect traefik-public >/dev/null 2>&1 || \ + docker network create traefik-public + export DOMAIN=dev-admin.merchbay.app export APP_URL=https://dev-admin.merchbay.app + docker compose up -d + sleep 10 docker compose exec -T app php artisan migrate --force docker compose exec -T app php artisan config:cache docker compose exec -T app php artisan route:cache docker compose exec -T app php artisan view:cache + rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml - echo 'Development deployment completed successfully!' - echo 'Application available at: https://dev-admin.merchbay.app' - " + + echo "✅ Development deployment completed" + EOF env: - DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} @@ -85,4 +93,4 @@ jobs: shell: sh run: | sleep 10 - curl -f https://dev-admin.merchbay.app || exit 1 + curl -f https://dev-admin.merchbay.app -- 2.49.1 From 74860f8a0d1eb4f5cfd344a564f8be239278010d Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 14:00:23 +0800 Subject: [PATCH 12/33] Fix SSH key variable in deployment workflow for consistency and security --- .gitea/workflows/deploy-dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 5b0aa2d..4c67f2a 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -34,12 +34,12 @@ jobs: mkdir -p ~/.ssh chmod 700 ~/.ssh - echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_ed25519 + echo "${DEPLOY_SSH_KEY}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H ${DEPLOY_HOST} >> ~/.ssh/known_hosts env: - SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - name: Deploy to Server -- 2.49.1 From aaa043f06e8d9a96ab5731d28ca69fb3c1adfc54 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 14:04:01 +0800 Subject: [PATCH 13/33] Enhance SSH setup in deployment workflow to include error handling for empty SSH key --- .gitea/workflows/deploy-dev.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 4c67f2a..a2ff2b9 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -31,6 +31,13 @@ jobs: - name: Setup SSH shell: sh run: | + set -e + + if [ -z "${DEPLOY_SSH_KEY}" ]; then + echo "❌ DEPLOY_SSH_KEY is EMPTY" + exit 1 + fi + mkdir -p ~/.ssh chmod 700 ~/.ssh -- 2.49.1 From 8e8bfd1897c3ac6dbf147b0ff39a4a259ea56f87 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 14:16:30 +0800 Subject: [PATCH 14/33] Refactor SSH setup in deployment workflow to enhance secrets presence checks and improve output clarity --- .gitea/workflows/deploy-dev.yml | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index a2ff2b9..b39517c 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -28,27 +28,39 @@ jobs: docker build -t merchbay_admin:dev . docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz - - name: Setup SSH + - name: Debug secrets (safe) shell: sh run: | - set -e + echo "== Secrets presence check ==" if [ -z "${DEPLOY_SSH_KEY}" ]; then - echo "❌ DEPLOY_SSH_KEY is EMPTY" - exit 1 + echo "❌ DEPLOY_SSH_KEY is EMPTY or NOT SET" + else + echo "✅ DEPLOY_SSH_KEY is SET" + echo "Length: ${#DEPLOY_SSH_KEY}" + echo "First line:" + echo "${DEPLOY_SSH_KEY}" | head -n 1 + echo "Last line:" + echo "${DEPLOY_SSH_KEY}" | tail -n 1 fi - mkdir -p ~/.ssh - chmod 700 ~/.ssh + if [ -z "${DEPLOY_USER}" ]; then + echo "❌ DEPLOY_USER is EMPTY" + else + echo "✅ DEPLOY_USER = ${DEPLOY_USER}" + fi - echo "${DEPLOY_SSH_KEY}" > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - - ssh-keyscan -H ${DEPLOY_HOST} >> ~/.ssh/known_hosts + if [ -z "${DEPLOY_HOST}" ]; then + echo "❌ DEPLOY_HOST is EMPTY" + else + echo "✅ DEPLOY_HOST = ${DEPLOY_HOST}" + fi env: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + - name: Deploy to Server shell: sh run: | -- 2.49.1 From 73b178fa2cef46fd44231eb406174b59f8683c47 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 14:24:11 +0800 Subject: [PATCH 15/33] Enhance deployment workflow by adding SSH setup and secret validation checks for improved security and reliability --- .gitea/workflows/deploy-dev.yml | 45 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index b39517c..5ea9f71 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -28,6 +28,7 @@ jobs: docker build -t merchbay_admin:dev . docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz + # 🔍 SAFE SECRET DEBUG (TEMPORARY – REMOVE LATER) - name: Debug secrets (safe) shell: sh run: | @@ -35,32 +36,52 @@ jobs: if [ -z "${DEPLOY_SSH_KEY}" ]; then echo "❌ DEPLOY_SSH_KEY is EMPTY or NOT SET" + exit 1 else echo "✅ DEPLOY_SSH_KEY is SET" echo "Length: ${#DEPLOY_SSH_KEY}" - echo "First line:" echo "${DEPLOY_SSH_KEY}" | head -n 1 - echo "Last line:" echo "${DEPLOY_SSH_KEY}" | tail -n 1 fi - if [ -z "${DEPLOY_USER}" ]; then - echo "❌ DEPLOY_USER is EMPTY" - else - echo "✅ DEPLOY_USER = ${DEPLOY_USER}" - fi + [ -z "${DEPLOY_USER}" ] && echo "❌ DEPLOY_USER EMPTY" && exit 1 + [ -z "${DEPLOY_HOST}" ] && echo "❌ DEPLOY_HOST EMPTY" && exit 1 - if [ -z "${DEPLOY_HOST}" ]; then - echo "❌ DEPLOY_HOST is EMPTY" - else - echo "✅ DEPLOY_HOST = ${DEPLOY_HOST}" - fi + echo "DEPLOY_USER=${DEPLOY_USER}" + echo "DEPLOY_HOST=${DEPLOY_HOST}" env: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + # 🔐 REQUIRED STEP (THIS WAS MISSING) + - name: Setup SSH + shell: sh + run: | + mkdir -p ~/.ssh + chmod 700 ~/.ssh + echo "${DEPLOY_SSH_KEY}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + + ssh-keyscan -H ${DEPLOY_HOST} >> ~/.ssh/known_hosts + + echo "SSH files:" + ls -l ~/.ssh + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + + # 🧪 OPTIONAL BUT HIGHLY RECOMMENDED (run once) + - name: SSH sanity check + shell: sh + run: | + ssh -i ~/.ssh/id_ed25519 ${DEPLOY_USER}@${DEPLOY_HOST} "whoami" + env: + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + + # 🚀 DEPLOY - name: Deploy to Server shell: sh run: | -- 2.49.1 From 676988fabbed89065690b3b2b8b99d9e746b52a7 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 14:58:43 +0800 Subject: [PATCH 16/33] Update deployment paths in workflow and remove versioning from docker-compose --- .gitea/workflows/deploy-dev.yml | 5 +---- docker-compose.yml | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 5ea9f71..af86e53 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -94,7 +94,7 @@ jobs: ssh -i ~/.ssh/id_ed25519 ${DEPLOY_USER}@${DEPLOY_HOST} << 'EOF' set -e - DEPLOY_DIR="/var/www/merchbay_admin_dev" + DEPLOY_DIR="/home/deploy/apps/merchbay_admin_dev" mkdir -p $DEPLOY_DIR cd /tmp @@ -125,9 +125,6 @@ jobs: echo "✅ Development deployment completed" EOF - env: - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - name: Health Check shell: sh diff --git a/docker-compose.yml b/docker-compose.yml index 088f8de..f99dbac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: app: build: -- 2.49.1 From 3ca2983c685cecfbe2a6c1ec5a45b7271770d2ac Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 15:14:48 +0800 Subject: [PATCH 17/33] Refactor secrets debug step in deployment workflow for clarity and efficiency --- .gitea/workflows/deploy-dev.yml | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index af86e53..1ddbf7c 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -28,33 +28,20 @@ jobs: docker build -t merchbay_admin:dev . docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz - # 🔍 SAFE SECRET DEBUG (TEMPORARY – REMOVE LATER) + # 🔍 TEMP DEBUG (remove after verification) - name: Debug secrets (safe) shell: sh run: | echo "== Secrets presence check ==" - - if [ -z "${DEPLOY_SSH_KEY}" ]; then - echo "❌ DEPLOY_SSH_KEY is EMPTY or NOT SET" - exit 1 - else - echo "✅ DEPLOY_SSH_KEY is SET" - echo "Length: ${#DEPLOY_SSH_KEY}" - echo "${DEPLOY_SSH_KEY}" | head -n 1 - echo "${DEPLOY_SSH_KEY}" | tail -n 1 - fi - + [ -z "${DEPLOY_SSH_KEY}" ] && echo "❌ DEPLOY_SSH_KEY EMPTY" && exit 1 [ -z "${DEPLOY_USER}" ] && echo "❌ DEPLOY_USER EMPTY" && exit 1 [ -z "${DEPLOY_HOST}" ] && echo "❌ DEPLOY_HOST EMPTY" && exit 1 - - echo "DEPLOY_USER=${DEPLOY_USER}" - echo "DEPLOY_HOST=${DEPLOY_HOST}" + echo "✅ Secrets OK" env: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - # 🔐 REQUIRED STEP (THIS WAS MISSING) - name: Setup SSH shell: sh run: | @@ -65,14 +52,10 @@ jobs: chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H ${DEPLOY_HOST} >> ~/.ssh/known_hosts - - echo "SSH files:" - ls -l ~/.ssh env: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - # 🧪 OPTIONAL BUT HIGHLY RECOMMENDED (run once) - name: SSH sanity check shell: sh run: | @@ -84,6 +67,9 @@ jobs: # 🚀 DEPLOY - name: Deploy to Server shell: sh + env: + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | cd /workspace/repo @@ -96,13 +82,13 @@ jobs: DEPLOY_DIR="/home/deploy/apps/merchbay_admin_dev" - mkdir -p $DEPLOY_DIR + mkdir -p "$DEPLOY_DIR" cd /tmp docker load < merchbay_admin_dev.tar.gz - cp docker-compose.yml $DEPLOY_DIR/ + cp docker-compose.yml "$DEPLOY_DIR/" - cd $DEPLOY_DIR + cd "$DEPLOY_DIR" docker compose down || true docker image prune -f -- 2.49.1 From e9620052f7677e32b48026ae20aefaa14e90c697 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 15:23:01 +0800 Subject: [PATCH 18/33] Update deployment directory path in workflow from /home/deploy/apps to /var/www/apps for consistency --- .gitea/workflows/deploy-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 1ddbf7c..f18e0ca 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -80,7 +80,7 @@ jobs: ssh -i ~/.ssh/id_ed25519 ${DEPLOY_USER}@${DEPLOY_HOST} << 'EOF' set -e - DEPLOY_DIR="/home/deploy/apps/merchbay_admin_dev" + DEPLOY_DIR="/var/www/apps/merchbay_admin_dev" mkdir -p "$DEPLOY_DIR" cd /tmp -- 2.49.1 From f2081217afad2b1f4395afb216fc25a56d7e6ff5 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 15:38:36 +0800 Subject: [PATCH 19/33] Refactor deployment workflow to streamline SSH setup and improve image building process --- .gitea/workflows/deploy-dev.yml | 103 +++++++++++++++----------------- docker-compose.yml | 4 +- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index f18e0ca..e9c50c2 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -13,107 +13,102 @@ jobs: image: catthehacker/ubuntu:act-latest steps: + # 1️⃣ Checkout code - name: Checkout code shell: sh run: | git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo cd /workspace/repo git checkout $GITHUB_REF_NAME - git pull origin $GITHUB_REF_NAME - - name: Build Docker Image + # 2️⃣ Build image + - name: Build Docker image shell: sh run: | cd /workspace/repo docker build -t merchbay_admin:dev . docker save merchbay_admin:dev | gzip > merchbay_admin_dev.tar.gz - # 🔍 TEMP DEBUG (remove after verification) - - name: Debug secrets (safe) - shell: sh - run: | - echo "== Secrets presence check ==" - [ -z "${DEPLOY_SSH_KEY}" ] && echo "❌ DEPLOY_SSH_KEY EMPTY" && exit 1 - [ -z "${DEPLOY_USER}" ] && echo "❌ DEPLOY_USER EMPTY" && exit 1 - [ -z "${DEPLOY_HOST}" ] && echo "❌ DEPLOY_HOST EMPTY" && exit 1 - echo "✅ Secrets OK" - env: - DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - + # 3️⃣ Setup SSH - name: Setup SSH shell: sh + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | mkdir -p ~/.ssh chmod 700 ~/.ssh - - echo "${DEPLOY_SSH_KEY}" > ~/.ssh/id_ed25519 + echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts - ssh-keyscan -H ${DEPLOY_HOST} >> ~/.ssh/known_hosts - env: - DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - - - name: SSH sanity check - shell: sh - run: | - ssh -i ~/.ssh/id_ed25519 ${DEPLOY_USER}@${DEPLOY_HOST} "whoami" - env: - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - - # 🚀 DEPLOY - - name: Deploy to Server + # 4️⃣ Upload artifacts + - name: Upload image and compose shell: sh env: DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | - cd /workspace/repo - scp -i ~/.ssh/id_ed25519 \ - merchbay_admin_dev.tar.gz docker-compose.yml \ - ${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/ + merchbay_admin_dev.tar.gz \ + docker-compose.yml \ + $DEPLOY_USER@$DEPLOY_HOST:/tmp/ - ssh -i ~/.ssh/id_ed25519 ${DEPLOY_USER}@${DEPLOY_HOST} << 'EOF' + # 5️⃣ Deploy on server + - name: Deploy on server + shell: sh + env: + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + run: | + ssh -i ~/.ssh/id_ed25519 $DEPLOY_USER@$DEPLOY_HOST << 'EOF' set -e DEPLOY_DIR="/var/www/apps/merchbay_admin_dev" - mkdir -p "$DEPLOY_DIR" - cd /tmp - docker load < merchbay_admin_dev.tar.gz - cp docker-compose.yml "$DEPLOY_DIR/" + echo "📦 Loading image" + docker load < /tmp/merchbay_admin_dev.tar.gz + + echo "📄 Updating compose file" + cp /tmp/docker-compose.yml "$DEPLOY_DIR/" cd "$DEPLOY_DIR" - docker compose down || true - docker image prune -f - + echo "🌐 Ensure Traefik network" docker network inspect traefik-public >/dev/null 2>&1 || \ docker network create traefik-public + echo "🚀 Starting containers" export DOMAIN=dev-admin.merchbay.app export APP_URL=https://dev-admin.merchbay.app - docker compose up -d - sleep 10 - docker compose exec -T app php artisan migrate --force - docker compose exec -T app php artisan config:cache - docker compose exec -T app php artisan route:cache - docker compose exec -T app php artisan view:cache + echo "⏳ Waiting for app container" + sleep 15 + if docker ps --format '{{.Names}}' | grep -q merchbay_admin_app; then + docker compose exec -T app php artisan migrate --force + docker compose exec -T app php artisan config:clear + docker compose exec -T app php artisan config:cache + docker compose exec -T app php artisan route:cache + docker compose exec -T app php artisan view:cache + else + echo "❌ App container not running" + docker compose logs + exit 1 + fi + + echo "🧹 Cleanup" rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml + docker image prune -f - echo "✅ Development deployment completed" + echo "✅ Deployment completed" EOF - - name: Health Check + # 6️⃣ Health check + - name: Health check shell: sh run: | sleep 10 - curl -f https://dev-admin.merchbay.app + curl -f https://dev-admin.merchbay.app \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f99dbac..c13fa0d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,6 @@ services: app: - build: - context: . - dockerfile: Dockerfile + image: merchbay_admin:dev container_name: merchbay_admin_app restart: unless-stopped environment: -- 2.49.1 From 183d19848b7e99836b69d6b539d70541ca84654d Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Tue, 16 Dec 2025 15:42:22 +0800 Subject: [PATCH 20/33] Update artifact upload paths in deployment workflow for accuracy --- .gitea/workflows/deploy-dev.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index e9c50c2..0bde65e 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -50,9 +50,9 @@ jobs: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | scp -i ~/.ssh/id_ed25519 \ - merchbay_admin_dev.tar.gz \ - docker-compose.yml \ - $DEPLOY_USER@$DEPLOY_HOST:/tmp/ + /workspace/repo/merchbay_admin_dev.tar.gz \ + /workspace/repo/docker-compose.yml \ + ${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/ # 5️⃣ Deploy on server - name: Deploy on server -- 2.49.1 From 7fb6a74a13c659fe745c3d54799a6a9c7f4c23c0 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 11:15:29 +0800 Subject: [PATCH 21/33] Add .env.example file and update docker-compose configurations for environment variables --- .env.server.example | 23 +++++++++++++++++++++++ .gitea/workflows/deploy-dev.yml | 17 +++++++++++++---- docker-compose.portainer.dev.yml | 10 +++++----- docker-compose.yml | 27 +++++++++++++++------------ 4 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 .env.server.example diff --git a/.env.server.example b/.env.server.example new file mode 100644 index 0000000..1ce82cd --- /dev/null +++ b/.env.server.example @@ -0,0 +1,23 @@ +# Server .env file for Development Environment +# +# Instructions: +# 1. SSH to your server: ssh webmaster@YOUR_SERVER_IP +# 2. Create directory: mkdir -p /var/www/merchbay_admin_dev +# 3. Create this file: nano /var/www/merchbay_admin_dev/.env +# 4. Copy the content below (fill in YOUR_DB_PASSWORD) +# 5. Save and secure: chmod 600 /var/www/merchbay_admin_dev/.env + +APP_ENV=development +APP_DEBUG=true +APP_URL=https://dev-admin.merchbay.app +DB_HOST=mysql +DB_PORT=3306 +DB_DATABASE=merchcbay_db +DB_USERNAME=crewapp +DB_PASSWORD=YOUR_DB_PASSWORD_HERE +DOMAIN=dev-admin.merchbay.app + +# Notes: +# - DB_HOST=mysql (your MySQL container name on crew-app-net network) +# - Replace YOUR_DB_PASSWORD_HERE with your actual MySQL password +# - This file should NEVER be committed to git diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 0bde65e..ce9c39f 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -60,6 +60,7 @@ jobs: env: DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + run: | ssh -i ~/.ssh/id_ed25519 $DEPLOY_USER@$DEPLOY_HOST << 'EOF' set -e @@ -75,13 +76,20 @@ jobs: cd "$DEPLOY_DIR" - echo "🌐 Ensure Traefik network" + echo "🔍 Checking .env file" + if [ ! -f .env ]; then + echo "❌ .env file not found at $DEPLOY_DIR/.env" + echo "Please create it first. See DEPLOYMENT-SETUP.md" + exit 1 + fi + + echo "🌐 Ensure networks" docker network inspect traefik-public >/dev/null 2>&1 || \ docker network create traefik-public + docker network inspect crew-app-net >/dev/null 2>&1 || \ + docker network create crew-app-net - echo "🚀 Starting containers" - export DOMAIN=dev-admin.merchbay.app - export APP_URL=https://dev-admin.merchbay.app + echo "🚀 Starting containers (env vars from .env file)" docker compose up -d echo "⏳ Waiting for app container" @@ -106,6 +114,7 @@ jobs: echo "✅ Deployment completed" EOF + # 6️⃣ Health check - name: Health check shell: sh diff --git a/docker-compose.portainer.dev.yml b/docker-compose.portainer.dev.yml index 1e9865a..eb741f0 100644 --- a/docker-compose.portainer.dev.yml +++ b/docker-compose.portainer.dev.yml @@ -14,11 +14,11 @@ services: - APP_DEBUG=false - APP_URL=https://dev-admin.merchbay.app - DB_CONNECTION=mysql - - DB_HOST=your-mysql-host - - DB_PORT=3306 - - DB_DATABASE=merchbay_admin_dev - - DB_USERNAME=your-mysql-user - - DB_PASSWORD=your-mysql-password + - DB_HOST=${DB_HOST} + - DB_PORT=${DB_PORT:-3306} + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} volumes: - app_storage_dev:/var/www/html/storage - app_uploads_dev:/var/www/html/public/uploads diff --git a/docker-compose.yml b/docker-compose.yml index c13fa0d..a45431c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,32 +8,35 @@ services: - APP_DEBUG=${APP_DEBUG:-false} - APP_URL=${APP_URL:-http://localhost} - DB_CONNECTION=mysql - - DB_HOST=${DB_HOST:-localhost} + - DB_HOST=${DB_HOST} - DB_PORT=${DB_PORT:-3306} - - DB_DATABASE=${DB_DATABASE:-merchbay_admin} - - DB_USERNAME=${DB_USERNAME:-root} - - DB_PASSWORD=${DB_PASSWORD:-} + - DB_DATABASE=${DB_DATABASE} + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} volumes: - ./storage:/var/www/html/storage - ./public/uploads:/var/www/html/public/uploads labels: - "traefik.enable=true" - - "traefik.http.routers.merchbay-admin.rule=Host(`${DOMAIN:-merchbay-admin.localhost}`)" - - "traefik.http.routers.merchbay-admin.entrypoints=websecure" - - "traefik.http.routers.merchbay-admin.tls=true" - - "traefik.http.routers.merchbay-admin.tls.certresolver=letsencrypt" - - "traefik.http.services.merchbay-admin.loadbalancer.server.port=80" + - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev.entrypoints=websecure" + - "traefik.http.routers.merchbay-admin-dev.tls=true" + - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" + - "traefik.http.services.merchbay-admin-dev.loadbalancer.server.port=80" # HTTP to HTTPS redirect - - "traefik.http.routers.merchbay-admin-http.rule=Host(`${DOMAIN:-merchbay-admin.localhost}`)" - - "traefik.http.routers.merchbay-admin-http.entrypoints=web" - - "traefik.http.routers.merchbay-admin-http.middlewares=https-redirect" + - "traefik.http.routers.merchbay-admin-dev-http.rule=Host(`dev-admin.merchbay.app`)" + - "traefik.http.routers.merchbay-admin-dev-http.entrypoints=web" + - "traefik.http.routers.merchbay-admin-dev-http.middlewares=https-redirect" - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" networks: - traefik-public + - crew-app-net - default networks: traefik-public: external: true + crew-app-net: + external: true default: driver: bridge -- 2.49.1 From 58e36c420c8722b41c52f29987dd0266d7ba84c6 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 11:19:14 +0800 Subject: [PATCH 22/33] Fix .env permissions to ensure proper access during deployment --- .gitea/workflows/deploy-dev.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index ce9c39f..306edf3 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -83,6 +83,10 @@ jobs: exit 1 fi + echo "🔧 Fixing .env permissions" + sudo chown $USER:$USER .env + sudo chmod 600 .env + echo "🌐 Ensure networks" docker network inspect traefik-public >/dev/null 2>&1 || \ docker network create traefik-public -- 2.49.1 From 946f968ca0d4fa44feacce74042715bd6159d918 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 11:26:29 +0800 Subject: [PATCH 23/33] Add cache clearing step during deployment to optimize application performance --- .gitea/workflows/deploy-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 306edf3..af11ff8 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -100,7 +100,7 @@ jobs: sleep 15 if docker ps --format '{{.Names}}' | grep -q merchbay_admin_app; then - docker compose exec -T app php artisan migrate --force + echo "🧹 Clearing caches" docker compose exec -T app php artisan config:clear docker compose exec -T app php artisan config:cache docker compose exec -T app php artisan route:cache -- 2.49.1 From 159dda3843c473e6090110ed655ba0558170dfa1 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 11:30:35 +0800 Subject: [PATCH 24/33] Enhance deployment script to clear and rebuild config cache for improved performance --- .gitea/workflows/deploy-dev.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index af11ff8..f34b41d 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -100,11 +100,9 @@ jobs: sleep 15 if docker ps --format '{{.Names}}' | grep -q merchbay_admin_app; then - echo "🧹 Clearing caches" + echo "🧹 Clearing and rebuilding config cache" docker compose exec -T app php artisan config:clear docker compose exec -T app php artisan config:cache - docker compose exec -T app php artisan route:cache - docker compose exec -T app php artisan view:cache else echo "❌ App container not running" docker compose logs -- 2.49.1 From 2550a945a3289270196199ec28f5be0d7cc4f793 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 11:44:41 +0800 Subject: [PATCH 25/33] Enhance health check in deployment workflow and suppress Apache ServerName warning in Dockerfile --- .gitea/workflows/deploy-dev.yml | 28 ++++++++++++++++++++++++++-- Dockerfile | 3 +++ docker-compose.yml | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index f34b41d..72346c0 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -121,5 +121,29 @@ jobs: - name: Health check shell: sh run: | - sleep 10 - curl -f https://dev-admin.merchbay.app \ No newline at end of file + echo "⏳ Waiting for app to be ready..." + sleep 20 + + echo "🔍 Testing health check (ignoring SSL cert for now)..." + HTTP_CODE=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 30 https://dev-admin.merchbay.app || echo "000") + + if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ] || [ "$HTTP_CODE" = "301" ]; then + echo "✅ Health check passed! (HTTP $HTTP_CODE)" + echo "⚠️ Note: Using -k to ignore SSL cert. Check Traefik logs if cert not ready." + else + echo "❌ Health check failed! (HTTP $HTTP_CODE)" + echo "" + echo "💡 Troubleshooting:" + echo " 1. Check if container is running:" + echo " docker ps | grep merchbay_admin_app" + echo "" + echo " 2. Check app logs:" + echo " docker logs merchbay_admin_app" + echo "" + echo " 3. Check Traefik logs:" + echo " docker logs traefik" + echo "" + echo " 4. Test manually:" + echo " curl -Ik https://dev-admin.merchbay.app" + exit 1 + fi \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2414610..418f250 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,9 @@ ENV APACHE_DOCUMENT_ROOT=/var/www/html/public RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf +# Suppress Apache ServerName warning +RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf + # Expose port 80 EXPOSE 80 diff --git a/docker-compose.yml b/docker-compose.yml index a45431c..c6cc4d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,7 +21,7 @@ services: - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)" - "traefik.http.routers.merchbay-admin-dev.entrypoints=websecure" - "traefik.http.routers.merchbay-admin-dev.tls=true" - - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" + - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=le" - "traefik.http.services.merchbay-admin-dev.loadbalancer.server.port=80" # HTTP to HTTPS redirect - "traefik.http.routers.merchbay-admin-dev-http.rule=Host(`dev-admin.merchbay.app`)" -- 2.49.1 From 110c0f7291432a560757891c9f81b348873a75f6 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 12:14:14 +0800 Subject: [PATCH 26/33] Fix: Create storage directories and set proper permissions --- Dockerfile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 418f250..fc01642 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,10 +32,17 @@ WORKDIR /var/www/html # Copy existing application directory contents COPY . /var/www/html -# Copy existing application directory permissions +# Create storage directories and set permissions +RUN mkdir -p storage/framework/views \ + storage/framework/cache \ + storage/framework/sessions \ + storage/logs \ + bootstrap/cache + +# Set proper ownership and permissions RUN chown -R www-data:www-data /var/www/html \ - && chmod -R 755 /var/www/html/storage \ - && chmod -R 755 /var/www/html/bootstrap/cache + && chmod -R 775 /var/www/html/storage \ + && chmod -R 775 /var/www/html/bootstrap/cache # Create .env file if it doesn't exist RUN if [ ! -f .env ]; then cp .env.example .env; fi -- 2.49.1 From 58e1bad1cf963650b6829da7ad9c4d8f89338899 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 12:24:02 +0800 Subject: [PATCH 27/33] Enhance AppServiceProvider to force HTTPS when behind a proxy --- app/Providers/AppServiceProvider.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 31d4448..3b5ed9a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -16,7 +16,10 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // + // Force HTTPS when behind a proxy (Traefik) + if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + \URL::forceScheme('https'); + } Storage::extend('sftp', function ($app, $config) { return new Filesystem(new SftpAdapter($config)); -- 2.49.1 From 075c6bfdf9e764b843e04368660272a7fbf533c0 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 12:31:11 +0800 Subject: [PATCH 28/33] Fix typo in AppServiceProvider to use forceSchema instead of forceScheme --- app/Providers/AppServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 3b5ed9a..37d859a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -18,7 +18,7 @@ class AppServiceProvider extends ServiceProvider { // Force HTTPS when behind a proxy (Traefik) if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { - \URL::forceScheme('https'); + \URL::forceSchema('https'); } Storage::extend('sftp', function ($app, $config) { -- 2.49.1 From 246f6b2c0f01c742825c3e6ba833e73e7072311c Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 12:58:56 +0800 Subject: [PATCH 29/33] Remove outdated deployment and configuration files; consolidate deployment instructions into README and update project structure. --- DEPLOYMENT-PORTAINER.md | 405 ------------------------------- DEPLOYMENT-SETUP.md | 187 -------------- DEPLOYMENT.md | 264 -------------------- README-DOCKER.md | 165 ------------- TRAEFIK-SSL-CONFIG.md | 314 ------------------------ deploy.sh | 105 -------- docker-compose.portainer.dev.yml | 48 ---- docker-compose.portainer.yml | 49 ---- readme.md | 181 ++++++++++++-- setup-server-env.sh | 153 ------------ setup-ssh-keys.sh | 90 ------- 11 files changed, 166 insertions(+), 1795 deletions(-) delete mode 100644 DEPLOYMENT-PORTAINER.md delete mode 100644 DEPLOYMENT-SETUP.md delete mode 100644 DEPLOYMENT.md delete mode 100644 README-DOCKER.md delete mode 100644 TRAEFIK-SSL-CONFIG.md delete mode 100755 deploy.sh delete mode 100644 docker-compose.portainer.dev.yml delete mode 100644 docker-compose.portainer.yml delete mode 100755 setup-server-env.sh delete mode 100755 setup-ssh-keys.sh diff --git a/DEPLOYMENT-PORTAINER.md b/DEPLOYMENT-PORTAINER.md deleted file mode 100644 index 81493df..0000000 --- a/DEPLOYMENT-PORTAINER.md +++ /dev/null @@ -1,405 +0,0 @@ -# Deployment with Portainer and Traefik - -This guide covers deploying MerchBay Admin using your existing Portainer and Traefik setup. - -## Prerequisites - -- ✅ Gitea self-hosted with Gitea runners configured -- ✅ Portainer installed and accessible -- ✅ Traefik reverse proxy running with: - - `web` entrypoint (port 80) - - `websecure` entrypoint (port 443) - - Let's Encrypt certificate resolver named `letsencrypt` - - External network named `traefik` - -## Deployment Methods - -### Method 1: Portainer Stack Deployment (Recommended) - -#### Step 1: Prepare the Image - -Build the Docker image via Gitea Actions or manually: - -```bash -# Using Gitea Actions (will build automatically on push) -git push origin main - -# OR build manually -docker build -t merchbay_admin:latest . -``` - -#### Step 2: Deploy in Portainer - -1. **Access Portainer** → `Stacks` → `Add stack` - -2. **Stack Configuration:** - - Name: `merchbay-admin` - - Build method: `Web editor` - -3. **Paste the content from `docker-compose.portainer.yml`** and update: - - `APP_URL`: Your domain (e.g., `https://merchbay-admin.yourdomain.com`) - - `DB_HOST`: Your MySQL host - - `DB_DATABASE`: Database name - - `DB_USERNAME`: Database username - - `DB_PASSWORD`: Database password - - Traefik Host rule: Replace `merchbay-admin.yourdomain.com` with your actual domain - -4. **Deploy the stack** - -5. **Run Initial Setup:** - - Go to `Containers` → Find `merchbay_admin_app` - - Click `Console` → Connect with `/bin/bash` - - Run: - ```bash - php artisan migrate --force - php artisan config:cache - php artisan route:cache - ``` - -### Method 2: Gitea Actions CI/CD (Automated) - -#### Step 1: Configure Gitea Secrets - -In your Gitea repository → `Settings` → `Secrets` → `Actions`, add: - -| Secret Name | Value | Description | -|------------|-------|-------------| -| `DEPLOY_HOST` | `192.168.1.100` | Your server IP/hostname | -| `DEPLOY_USER` | `deploy` | SSH username | -| `DEPLOY_SSH_KEY` | `-----BEGIN RSA...` | Private SSH key | -| `DEPLOY_PORT` | `22` | SSH port (optional) | -| `DEPLOY_DIR` | `/var/www/merchbay_admin` | Deployment directory | -| `DOMAIN` | `merchbay-admin.yourdomain.com` | Your domain for Traefik | - -#### Step 2: Prepare Deployment Server - -```bash -# SSH into your server -ssh deploy@your-server - -# Create deployment directory -sudo mkdir -p /var/www/merchbay_admin -sudo chown $USER:$USER /var/www/merchbay_admin -cd /var/www/merchbay_admin - -# Create .env file -nano .env -``` - -Add to `.env`: -```env -APP_ENV=production -APP_DEBUG=false -APP_URL=https://merchbay-admin.yourdomain.com -DB_HOST=your-mysql-host -DB_PORT=3306 -DB_DATABASE=merchbay_admin -DB_USERNAME=your-mysql-user -DB_PASSWORD=your-mysql-password -DOMAIN=merchbay-admin.yourdomain.com -``` - -#### Step 3: Ensure Traefik Network Exists - -```bash -docker network inspect traefik >/dev/null 2>&1 || docker network create traefik -``` - -#### Step 4: Deploy - -Simply push to your main branch: - -```bash -git add . -git commit -m "Deploy application" -git push origin main -``` - -Gitea Actions will automatically: -1. Build the Docker image -2. Transfer to your server -3. Deploy with docker-compose -4. Connect to Traefik network -5. Run migrations -6. Cache configurations - -### Method 3: Manual Deployment with Script - -```bash -# On your server -cd /var/www/merchbay_admin - -# Pull latest code -git pull origin main - -# Run deployment script -./deploy.sh -``` - -## Traefik Configuration - -### Verify Traefik Setup - -Ensure your Traefik configuration includes: - -```yaml -# traefik.yml or docker-compose.yml -entryPoints: - web: - address: ":80" - websecure: - address: ":443" - -certificatesResolvers: - letsencrypt: - acme: - email: your-email@example.com - storage: /letsencrypt/acme.json - httpChallenge: - entryPoint: web -``` - -### External Network - -Ensure Traefik network exists and is external: - -```bash -# Create network if it doesn't exist -docker network create traefik - -# Verify -docker network inspect traefik -``` - -## DNS Configuration - -Point your domain to your server: - -``` -Type: A Record -Name: merchbay-admin (or @ for root domain) -Value: YOUR_SERVER_IP -TTL: 3600 -``` - -## Verification - -### 1. Check Container Status - -**Via Portainer:** -- Navigate to `Containers` -- Verify `merchbay_admin_app` is running - -**Via CLI:** -```bash -docker ps | grep merchbay_admin -``` - -### 2. Check Traefik Dashboard - -If you have Traefik dashboard enabled: -- Look for `merchbay-admin@docker` router -- Verify it's connected to the correct service - -### 3. Test Application - -```bash -# Test HTTPS -curl -I https://merchbay-admin.yourdomain.com - -# Should return: HTTP/2 200 -``` - -### 4. Check Logs - -**Via Portainer:** -- `Containers` → `merchbay_admin_app` → `Logs` - -**Via CLI:** -```bash -docker logs merchbay_admin_app -f -``` - -## Troubleshooting - -### Issue: Container not accessible via domain - -**Check Traefik labels:** -```bash -docker inspect merchbay_admin_app | grep -A 20 Labels -``` - -**Verify network connection:** -```bash -docker network inspect traefik | grep merchbay_admin -``` - -**Solution:** -```bash -# Reconnect to Traefik network -docker network connect traefik merchbay_admin_app -``` - -### Issue: SSL certificate not generating - -**Check Traefik logs:** -```bash -docker logs traefik | grep letsencrypt -``` - -**Common fixes:** -1. Ensure port 80 is accessible (Let's Encrypt HTTP challenge) -2. Verify DNS is pointing to your server -3. Check email in Traefik's ACME configuration -4. Ensure `acme.json` has correct permissions (600) - -### Issue: Database connection failed - -**Check environment variables:** -```bash -docker exec merchbay_admin_app env | grep DB_ -``` - -**Test connection:** -```bash -docker exec merchbay_admin_app php artisan tinker ->>> DB::connection()->getPdo(); -``` - -### Issue: 502 Bad Gateway - -**Possible causes:** -1. Application not fully started -2. Wrong port in Traefik label (should be 80) -3. Application crashed - -**Check:** -```bash -# Container status -docker ps -a | grep merchbay_admin - -# Application logs -docker logs merchbay_admin_app --tail 100 - -# Restart container -docker restart merchbay_admin_app -``` - -## Updating the Application - -### Via Gitea Actions (Automatic) - -```bash -git add . -git commit -m "Update application" -git push origin main -``` - -### Via Portainer - -1. Go to `Stacks` → `merchbay-admin` -2. Click `Editor` -3. Update image or configuration -4. Click `Update the stack` -5. Enable "Re-pull image and redeploy" - -### Manual Update - -```bash -ssh deploy@your-server -cd /var/www/merchbay_admin -./deploy.sh -``` - -## Rollback - -### Via Portainer - -1. Go to `Stacks` → `merchbay-admin` -2. Click on the stack -3. Find previous version in `Stack History` (if available) -4. Revert to previous version - -### Manual Rollback - -```bash -# List available backups -ls -lh /var/www/merchbay_admin/backups/ - -# Restore from backup -cd /var/www/merchbay_admin -tar -xzf backups/backup_YYYYMMDD_HHMMSS.tar.gz - -# Restart -docker compose restart -``` - -## Security Best Practices - -1. **Use Strong Database Passwords**: Generate with `openssl rand -base64 32` -2. **Restrict SSH Access**: Use key-based authentication only -3. **Firewall Rules**: Only allow necessary ports (80, 443, 22) -4. **Regular Backups**: Automated backups of database and storage -5. **Keep Docker Updated**: Regularly update Docker and images -6. **Monitor Logs**: Set up log monitoring/alerting -7. **Use Secrets**: Never commit sensitive data to repository -8. **HTTPS Only**: Ensure HTTP redirects to HTTPS - -## Performance Optimization - -### PHP-FPM Configuration - -Consider switching to PHP-FPM for better performance: - -```dockerfile -FROM php:7.4-fpm-alpine -# ... additional configuration -``` - -### Use Redis for Cache/Sessions - -```env -CACHE_DRIVER=redis -SESSION_DRIVER=redis -REDIS_HOST=redis -``` - -Add Redis service to docker-compose: -```yaml -services: - redis: - image: redis:alpine - networks: - - default -``` - -### Enable OPcache - -Already included in Dockerfile, verify: -```bash -docker exec merchbay_admin_app php -i | grep opcache -``` - -## Monitoring - -### View Real-time Logs in Portainer - -1. Navigate to `Containers` -2. Click on `merchbay_admin_app` -3. Select `Logs` tab -4. Enable `Auto-refresh` - -### Set Up Alerts - -Configure Portainer notifications: -1. `Settings` → `Notifications` -2. Add webhook or email notification -3. Set up container health checks - -## Support - -For issues: -1. Check application logs in Portainer -2. Verify Traefik configuration -3. Test database connectivity -4. Review Gitea Actions logs if using CI/CD diff --git a/DEPLOYMENT-SETUP.md b/DEPLOYMENT-SETUP.md deleted file mode 100644 index 49bd057..0000000 --- a/DEPLOYMENT-SETUP.md +++ /dev/null @@ -1,187 +0,0 @@ -# Deployment Setup Guide - -This guide will help you set up your deployment infrastructure for the MerchBay Admin application. - -## Quick Start - -We've created two helper scripts to simplify the setup process: - -### 1. Setup SSH Keys (`setup-ssh-keys.sh`) - -Generate and configure SSH keys for Gitea deployment. - -```bash -./setup-ssh-keys.sh -``` - -**What it does:** -- Generates an SSH key pair for deployment -- Shows you the private key to add to Gitea secrets -- Optionally deploys the public key to your server -- Tests the SSH connection - -### 2. Setup Server Environment (`setup-server-env.sh`) - -Configure `.env` files on your deployment servers. - -```bash -./setup-server-env.sh -``` - -**What it does:** -- Guides you through environment configuration -- Creates `.env` file on your server -- Shows you which Gitea secrets are needed -- Supports both production and development environments - -## Manual Setup (Alternative) - -If you prefer manual setup, follow these steps: - -### Step 1: Generate SSH Keys - -```bash -# Generate SSH key -ssh-keygen -t ed25519 -C "gitea-deploy-key" -f ~/.ssh/gitea_deploy_key -N "" - -# View private key (for Gitea) -cat ~/.ssh/gitea_deploy_key - -# View public key (for server) -cat ~/.ssh/gitea_deploy_key.pub -``` - -### Step 2: Add Public Key to Server - -```bash -# SSH to your server -ssh user@your-server - -# Add public key -mkdir -p ~/.ssh -echo "your-public-key-here" >> ~/.ssh/authorized_keys -chmod 600 ~/.ssh/authorized_keys -``` - -### Step 3: Create .env Files on Server - -**Production Server:** -```bash -ssh user@prod-server - -mkdir -p /var/www/merchbay_admin -cat > /var/www/merchbay_admin/.env << 'EOF' -APP_ENV=production -APP_DEBUG=false -APP_URL=https://merchbay.com -DB_HOST=localhost -DB_PORT=3306 -DB_DATABASE=merchbay_prod -DB_USERNAME=merchbay_user -DB_PASSWORD=your_secure_password -DOMAIN=merchbay.com -EOF - -chmod 600 /var/www/merchbay_admin/.env -``` - -**Development Server:** -```bash -ssh user@dev-server - -mkdir -p /var/www/merchbay_admin_dev -cat > /var/www/merchbay_admin_dev/.env << 'EOF' -APP_ENV=staging -APP_DEBUG=false -APP_URL=https://dev-admin.merchbay.app -DB_HOST=localhost -DB_PORT=3306 -DB_DATABASE=merchbay_dev -DB_USERNAME=merchbay_user -DB_PASSWORD=your_dev_password -DOMAIN=dev-admin.merchbay.app -EOF - -chmod 600 /var/www/merchbay_admin_dev/.env -``` - -### Step 4: Add Secrets to Gitea - -Go to your Gitea repository → Settings → Secrets - -**For Production (deploy.yml):** -- `PROD_DEPLOY_SSH_KEY` - Your private SSH key content -- `PROD_DEPLOY_USER` - SSH username (e.g., `root`) -- `PROD_DEPLOY_HOST` - Server IP/hostname - -**For Development (deploy-dev.yml):** -- `DEPLOY_SSH_KEY` - Your private SSH key content -- `DEPLOY_USER` - SSH username (e.g., `root`) -- `DEPLOY_HOST` - Server IP/hostname - -**For Docker Registry (build-push.yml):** -- `DOCKER_REGISTRY_URL` - Your registry URL -- `DOCKER_USERNAME` - Registry username -- `DOCKER_PASSWORD` - Registry password - -## Benefits of This Approach - -✅ **Fewer Secrets** - Only 3 secrets per environment instead of 8+ -✅ **Centralized** - All database/app secrets stay on the server -✅ **Reusable** - Same SSH credentials work for all apps -✅ **Secure** - Secrets never appear in CI/CD logs -✅ **Easy Updates** - Edit `.env` files directly on server - -## Troubleshooting - -### SSH Connection Issues - -```bash -# Test SSH connection -ssh -i ~/.ssh/gitea_deploy_key user@server - -# Check SSH key permissions -chmod 600 ~/.ssh/gitea_deploy_key -chmod 644 ~/.ssh/gitea_deploy_key.pub -``` - -### Workflow Fails with "Could not resolve hostname" - -- Make sure all secrets are added to Gitea -- Verify `DEPLOY_HOST` / `PROD_DEPLOY_HOST` is correct -- Check `DEPLOY_USER` / `PROD_DEPLOY_USER` is set - -### .env File Not Found - -- Run `./setup-server-env.sh` to create it -- Or manually create `.env` file on server at: - - Production: `/var/www/merchbay_admin/.env` - - Development: `/var/www/merchbay_admin_dev/.env` - -## Multiple Applications - -To deploy multiple applications using the same setup: - -1. **Use the same SSH keys** - No need to generate new ones -2. **Create separate .env files** - One per app on the server -3. **Only 3 Gitea secrets total** - Reuse across all apps! - -Example for another app: -```bash -# Same SSH key works! -# Just create new .env file -ssh user@server -mkdir -p /var/www/another_app -cat > /var/www/another_app/.env << 'EOF' -# App-specific configuration -EOF -``` - -## Security Best Practices - -- ✅ Never commit `.env` files to git -- ✅ Keep private keys secure -- ✅ Use strong database passwords -- ✅ Restrict SSH key permissions (600) -- ✅ Use different passwords for prod/dev -- ✅ Regularly rotate credentials diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md deleted file mode 100644 index 54b6635..0000000 --- a/DEPLOYMENT.md +++ /dev/null @@ -1,264 +0,0 @@ -# Gitea Actions Deployment Guide - -This repository uses Gitea Actions for automated deployment to your server. - -## Workflows - -### 1. Deploy Workflow (`.gitea/workflows/deploy.yml`) -Automatically deploys the application when code is pushed to `main` or `master` branch. - -**Steps:** -1. Builds Docker image -2. Transfers image to deployment server -3. Stops existing container -4. Starts new container -5. Runs database migrations -6. Clears and caches Laravel configuration - -### 2. Build and Push Workflow (`.gitea/workflows/build-push.yml`) -Builds and pushes Docker images to a registry when a version tag is created. - -## Required Secrets - -Configure these secrets in your Gitea repository settings: -`Settings` → `Secrets` → `Actions` - -### Deployment Secrets - -| Secret Name | Description | Example | -|------------|-------------|---------| -| `DEPLOY_HOST` | Deployment server hostname or IP | `192.168.1.100` or `example.com` | -| `DEPLOY_USER` | SSH username for deployment | `deploy` or `ubuntu` | -| `DEPLOY_SSH_KEY` | Private SSH key for authentication | `-----BEGIN RSA PRIVATE KEY-----...` | -| `DEPLOY_PORT` | SSH port (optional, defaults to 22) | `22` | -| `DEPLOY_DIR` | Deployment directory (optional) | `/var/www/merchbay_admin` | - -### Docker Registry Secrets (Optional) - -Only required if using the build-push workflow or private registry: - -| Secret Name | Description | Example | -|------------|-------------|---------| -| `DOCKER_REGISTRY_URL` | Docker registry URL | `registry.example.com` or `docker.io` | -| `DOCKER_USERNAME` | Registry username | `myuser` | -| `DOCKER_PASSWORD` | Registry password or token | `mypassword` | - -### Database Configuration on Server - -Create a `.env` file in your deployment directory with database credentials: - -```bash -# On your deployment server -sudo mkdir -p /var/www/merchbay_admin -sudo nano /var/www/merchbay_admin/.env -``` - -Add your database configuration: - -```env -DB_HOST=your-mysql-host -DB_PORT=3306 -DB_DATABASE=merchbay_admin -DB_USERNAME=your-mysql-user -DB_PASSWORD=your-mysql-password -APP_ENV=production -APP_DEBUG=false -APP_KEY=base64:YOUR_APP_KEY_HERE -``` - -## Setup Instructions - -### 1. Generate SSH Key for Deployment - -On your local machine or CI server: - -```bash -# Generate a new SSH key pair -ssh-keygen -t rsa -b 4096 -f ~/.ssh/deploy_key -N "" - -# Copy the public key to your deployment server -ssh-copy-id -i ~/.ssh/deploy_key.pub user@your-server - -# Copy the private key content for Gitea secret -cat ~/.ssh/deploy_key -``` - -### 2. Configure Gitea Secrets - -1. Go to your Gitea repository -2. Navigate to `Settings` → `Secrets` → `Actions` -3. Add each required secret listed above -4. For `DEPLOY_SSH_KEY`, paste the entire private key content - -### 3. Prepare Deployment Server - -On your deployment server, install Docker and Docker Compose: - -```bash -# Install Docker -curl -fsSL https://get.docker.com -o get-docker.sh -sudo sh get-docker.sh - -# Add your user to docker group -sudo usermod -aG docker $USER - -# Install Docker Compose -sudo apt-get update -sudo apt-get install docker-compose-plugin - -# Create deployment directory -sudo mkdir -p /var/www/merchbay_admin -sudo chown $USER:$USER /var/www/merchbay_admin - -# Create .env file with database credentials -nano /var/www/merchbay_admin/.env -``` - -### 4. Update docker-compose.yml for Production - -Ensure your `docker-compose.yml` references the `.env` file: - -```yaml -services: - app: - environment: - - DB_HOST=${DB_HOST} - - DB_PORT=${DB_PORT} - - DB_DATABASE=${DB_DATABASE} - - DB_USERNAME=${DB_USERNAME} - - DB_PASSWORD=${DB_PASSWORD} -``` - -## Triggering Deployment - -### Automatic Deployment - -Push to main/master branch: - -```bash -git add . -git commit -m "Deploy updates" -git push origin main -``` - -### Manual Deployment - -1. Go to your Gitea repository -2. Click on `Actions` -3. Select `Deploy MerchBay Admin` workflow -4. Click `Run workflow` - -## Monitoring Deployment - -### View Workflow Logs - -1. Go to `Actions` tab in your Gitea repository -2. Click on the running/completed workflow -3. View logs for each step - -### Check Application Logs - -On your deployment server: - -```bash -cd /var/www/merchbay_admin -docker compose logs -f app -``` - -### Verify Deployment - -```bash -# Check container status -docker compose ps - -# Test application -curl http://localhost:8080 - -# Access application shell -docker compose exec app bash -``` - -## Rollback Procedure - -If deployment fails, you can quickly rollback: - -```bash -# On deployment server -cd /var/www/merchbay_admin - -# Stop current container -docker compose down - -# Load previous image (if available) -docker images # Find previous image ID -docker tag merchbay_admin:latest - -# Start with previous version -docker compose up -d -``` - -## Troubleshooting - -### SSH Connection Issues - -```bash -# Test SSH connection from CI to server -ssh -i ~/.ssh/deploy_key user@your-server - -# Check SSH key permissions -chmod 600 ~/.ssh/deploy_key -``` - -### Docker Permission Issues - -```bash -# On deployment server, ensure user is in docker group -sudo usermod -aG docker $USER -newgrp docker -``` - -### Migration Failures - -```bash -# Manually run migrations -docker compose exec app php artisan migrate --force - -# Check database connection -docker compose exec app php artisan tinker ->>> DB::connection()->getPdo(); -``` - -## Security Best Practices - -1. **Use SSH keys, not passwords** for server authentication -2. **Restrict SSH key** to only deployment commands if possible -3. **Use secrets** for all sensitive data, never commit to repository -4. **Set proper file permissions** on deployment server (755 for directories, 644 for files) -5. **Enable firewall** on deployment server and restrict access -6. **Use HTTPS** with SSL certificates in production -7. **Regular backups** of database and uploaded files - -## Advanced Configuration - -### Using Docker Registry - -To use a private registry: - -1. Add registry secrets to Gitea -2. Update deployment script to pull from registry instead of transferring image -3. Use the build-push workflow to automate image publishing - -### Zero-Downtime Deployment - -For zero-downtime deployments, consider: - -1. Using a load balancer -2. Running multiple container instances -3. Implementing blue-green deployment strategy - -### Environment-Specific Deployments - -Create separate workflows for staging and production: - -- `.gitea/workflows/deploy-staging.yml` (triggered on `develop` branch) -- `.gitea/workflows/deploy-production.yml` (triggered on `main` branch) diff --git a/README-DOCKER.md b/README-DOCKER.md deleted file mode 100644 index 7aeba46..0000000 --- a/README-DOCKER.md +++ /dev/null @@ -1,165 +0,0 @@ -# Docker Deployment Guide for MerchBay Admin - -## Prerequisites - -- Docker installed on your system -- Docker Compose installed on your system - -## Quick Start - -### 1. Build and Start Containers - -```bash -docker-compose up -d --build -``` - -This will: -- Build the application container -- Start MySQL database -- Start PHPMyAdmin -- Set up networking between containers - -### 2. Access the Application - -- **Application**: http://localhost:8080 -- **PHPMyAdmin**: http://localhost:8081 - -### 3. Run Database Migrations - -```bash -docker-compose exec app php artisan migrate -``` - -### 4. Seed Database (if needed) - -```bash -docker-compose exec app php artisan db:seed -``` - -## Useful Commands - -### View Container Logs - -```bash -docker-compose logs -f app -``` - -### Access Container Shell - -```bash -docker-compose exec app bash -``` - -### Stop Containers - -```bash -docker-compose down -``` - -### Stop and Remove Volumes (Clean Slate) - -```bash -docker-compose down -v -``` - -### Rebuild Containers - -```bash -docker-compose up -d --build --force-recreate -``` - -### Run Artisan Commands - -```bash -docker-compose exec app php artisan [command] -``` - -### Clear Laravel Cache - -```bash -docker-compose exec app php artisan cache:clear -docker-compose exec app php artisan config:clear -docker-compose exec app php artisan route:clear -docker-compose exec app php artisan view:clear -``` - -### Install/Update Composer Dependencies - -```bash -docker-compose exec app composer install -# or -docker-compose exec app composer update -``` - -## Environment Configuration - -Edit the `docker-compose.yml` file to customize: -- Database credentials -- Port mappings -- Environment variables - -For production deployment, update the `APP_ENV` and `APP_DEBUG` values: - -```yaml -environment: - - APP_ENV=production - - APP_DEBUG=false -``` - -## Database Connection - -The application connects to the MySQL container using these credentials (defined in docker-compose.yml): - -- **Host**: db -- **Database**: merchbay_admin -- **Username**: merchbay_user -- **Password**: merchbay_password - -## Troubleshooting - -### Permission Issues - -If you encounter permission errors: - -```bash -docker-compose exec app chown -R www-data:www-data /var/www/html/storage -docker-compose exec app chmod -R 755 /var/www/html/storage -``` - -### Database Connection Issues - -Ensure the database container is fully started: - -```bash -docker-compose logs db -``` - -Wait a few seconds after starting containers for MySQL to initialize. - -### Port Already in Use - -If ports 8080 or 3306 are already in use, modify the ports in `docker-compose.yml`: - -```yaml -ports: - - "8090:80" # Change 8080 to 8090 or any available port -``` - -## Production Deployment - -For production environments: - -1. Update `.env` file with production settings -2. Set `APP_DEBUG=false` in docker-compose.yml -3. Use a secure database password -4. Consider using a reverse proxy (Nginx/Traefik) with SSL -5. Set up proper backup strategies for database volumes -6. Configure log rotation - -## Volumes - -- `db_data`: Persistent MySQL data -- `./storage`: Laravel storage (logs, cache, sessions) -- `./public/uploads`: User uploaded files - -These volumes ensure data persists across container restarts. diff --git a/TRAEFIK-SSL-CONFIG.md b/TRAEFIK-SSL-CONFIG.md deleted file mode 100644 index cd51dc4..0000000 --- a/TRAEFIK-SSL-CONFIG.md +++ /dev/null @@ -1,314 +0,0 @@ -# Traefik SSL Configuration for MerchBay Admin - -This document explains how to configure paid SSL certificates for production and automatic Let's Encrypt for development. - -## Network Configuration - -All deployments use the external network: `traefik-public` - -```bash -# Ensure the network exists -docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public -``` - -## Development (dev-admin.merchbay.app) - Automatic SSL - -Development uses Let's Encrypt for automatic SSL certificate generation. - -### Traefik Configuration - -Ensure your Traefik has Let's Encrypt configured: - -```yaml -# traefik.yml or dynamic config -certificatesResolvers: - letsencrypt: - acme: - email: admin@merchbay.app - storage: /letsencrypt/acme.json - httpChallenge: - entryPoint: web -``` - -### Application Labels (Already configured in docker-compose) - -```yaml -labels: - - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" -``` - -## Production (merchbay.app) - Paid SSL Certificate - -Production uses a paid SSL certificate (e.g., from GoDaddy, Namecheap, Cloudflare). - -### Step 1: Prepare SSL Certificate Files - -You should have these files from your SSL provider: -- `merchbay.app.crt` - Certificate file -- `merchbay.app.key` - Private key file -- `ca-bundle.crt` - CA bundle (optional, for chain) - -Create a combined certificate file: - -```bash -# Your SSL certificates are in /srv/certs -# Verify files exist -ls -la /srv/certs/ - -# If you have a CA bundle, create a full chain -cd /srv/certs -cat merchbay.app.crt ca-bundle.crt > merchbay.app-fullchain.crt - -# Set proper permissions -sudo chmod 600 /srv/certs/*.key -sudo chmod 644 /srv/certs/*.crt -``` - -### Step 2: Configure Traefik File Provider - -Create a dynamic configuration file for Traefik: - -```bash -sudo nano /opt/traefik/dynamic/certs.yml -``` - -Add: - -```yaml -# /opt/traefik/dynamic/certs.yml or your Traefik dynamic config location -tls: - certificates: - - certFile: /srv/certs/merchbay.app-fullchain.crt - keyFile: /srv/certs/merchbay.app.key - stores: - - default - stores: - default: - defaultCertificate: - certFile: /srv/certs/merchbay.app-fullchain.crt - keyFile: /srv/certs/merchbay.app.key -``` - -### Step 3: Update Traefik docker-compose.yml - -Ensure Traefik has file provider enabled and certificates mounted: - -```yaml -services: - traefik: - image: traefik:v2.10 - command: - - "--providers.docker=true" - - "--providers.docker.network=traefik-public" - - "--providers.file.directory=/etc/traefik/dynamic" - - "--providers.file.watch=true" - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" - # Let's Encrypt for dev - - "--certificatesresolvers.letsencrypt.acme.email=admin@merchbay.app" - - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - /srv/certs:/srv/certs:ro - - /opt/traefik/dynamic:/etc/traefik/dynamic:ro - - traefik-letsencrypt:/letsencrypt - networks: - - traefik-public -``` - -### Step 4: Restart Traefik - -```bash -cd /path/to/traefik -docker compose restart traefik - -# Verify certificates are loaded -docker compose logs traefik | grep -i cert -``` - -## Application Configuration - -### Development Branch (dev) - -File: `docker-compose.portainer.dev.yml` - -- Domain: `dev-admin.merchbay.app` -- SSL: Let's Encrypt (automatic) -- Certificate Resolver: `letsencrypt` - -```yaml -labels: - - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)" - - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" -``` - -### Production Branch (main) - -File: `docker-compose.portainer.yml` - -- Domain: `merchbay.app` -- SSL: Paid certificate (via Traefik file provider) -- No certresolver label (uses default store) - -```yaml -labels: - - "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.app`)" - - "traefik.http.routers.merchbay-admin.tls=true" - # No certresolver - uses file provider certificate -``` - -## Gitea Secrets Configuration - -### Development Secrets - -``` -DEV_DB_HOST=dev-mysql-host -DEV_DB_PORT=3306 -DEV_DB_DATABASE=merchbay_admin_dev -DEV_DB_USERNAME=dev_user -DEV_DB_PASSWORD=dev_password -``` - -### Production Secrets - -``` -PROD_DEPLOY_HOST=prod-server-ip -PROD_DEPLOY_USER=deploy -PROD_DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----... -PROD_DEPLOY_PORT=22 -PROD_DB_HOST=prod-mysql-host -PROD_DB_PORT=3306 -PROD_DB_DATABASE=merchbay_admin -PROD_DB_USERNAME=prod_user -PROD_DB_PASSWORD=prod_password -``` - -### Shared Secrets (if using same server) - -``` -DEPLOY_HOST=your-server-ip -DEPLOY_USER=deploy -DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----... -DEPLOY_PORT=22 -``` - -## Verification - -### Check Development SSL - -```bash -# Check certificate issuer (should be Let's Encrypt) -echo | openssl s_client -servername dev-admin.merchbay.app -connect dev-admin.merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer -# Should show: issuer=C = US, O = Let's Encrypt, CN = R3 -``` - -### Check Production SSL - -```bash -# Check certificate issuer (should be your SSL provider) -echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer -# Should show your paid SSL provider - -# Check certificate validity -echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -dates -``` - -### Verify in Browser - -1. Visit https://dev-admin.merchbay.app - - Certificate should be issued by "Let's Encrypt Authority X3" - -2. Visit https://merchbay.com - - Certificate should be issued by your paid SSL provider - -## Troubleshooting - -### Development SSL Not Working - -```bash -# Check Let's Encrypt logs -docker logs traefik | grep letsencrypt - -# Verify acme.json permissions -ls -l /path/to/letsencrypt/acme.json -# Should be: -rw------- (600) - -# Check DNS -dig dev-admin.merchbay.app +short -# Should return your server IP -``` - -### Production SSL Not Working - -```bash -# Verify Traefik can read certificates -docker exec traefik ls -l /srv/certs/ - -# Check dynamic configuration is loaded -docker exec traefik cat /etc/traefik/dynamic/certs.yml - -# Verify certificate format -openssl x509 -in /srv/certs/merchbay.app-fullchain.crt -text -noout - -# Check private key -openssl rsa -in /srv/certs/merchbay.app.key -check -``` - -### Certificate Mismatch - -```bash -# Verify certificate and key match -openssl x509 -noout -modulus -in /srv/certs/merchbay.app.crt | openssl md5 -openssl rsa -noout -modulus -in /srv/certs/merchbay.app.key | openssl md5 -# Both should output the same hash -``` - -## Renewing Certificates - -### Development (Let's Encrypt) - -Automatic renewal every 60 days. No action needed. - -### Production (Paid SSL) - -Before certificate expiration: - -1. Download new certificate from your SSL provider -2. Update files in `/srv/certs/` -3. Restart Traefik: `docker compose restart traefik` -4. Verify: `curl -vI https://merchbay.app` - -## DNS Configuration - -### Development - -``` -Type: A -Name: dev-admin.merchbay.app -Value: YOUR_SERVER_IP -TTL: 3600 -``` - -### Production - -``` -Type: A -Name: merchbay.app (or @) -Value: YOUR_SERVER_IP -TTL: 3600 - -Type: A -Name: www.merchbay.app -Value: YOUR_SERVER_IP -TTL: 3600 -``` - -## Security Best Practices - -1. **Keep certificates private**: Never commit SSL keys to git -2. **Use strong permissions**: 600 for private keys, 644 for certificates -3. **Monitor expiration**: Set reminders 30 days before expiration -4. **Use HSTS**: Add header after SSL is working correctly -5. **Enable OCSP stapling**: Improves SSL performance -6. **Regular updates**: Keep Traefik updated for security patches diff --git a/deploy.sh b/deploy.sh deleted file mode 100755 index 1e6468a..0000000 --- a/deploy.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash - -# Deployment script for MerchBay Admin -# This can be used for manual deployments or called from CI/CD - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Configuration -DEPLOY_DIR="${DEPLOY_DIR:-/var/www/merchbay_admin}" -APP_NAME="merchbay_admin" -BACKUP_DIR="${DEPLOY_DIR}/backups" - -echo -e "${GREEN}Starting deployment of ${APP_NAME}...${NC}" - -# Create backup directory -mkdir -p "${BACKUP_DIR}" - -# Backup current state -if [ -d "${DEPLOY_DIR}/storage" ]; then - echo -e "${YELLOW}Creating backup...${NC}" - BACKUP_FILE="${BACKUP_DIR}/backup_$(date +%Y%m%d_%H%M%S).tar.gz" - tar -czf "${BACKUP_FILE}" -C "${DEPLOY_DIR}" storage .env 2>/dev/null || true - echo -e "${GREEN}Backup created: ${BACKUP_FILE}${NC}" -fi - -# Navigate to deployment directory -cd "${DEPLOY_DIR}" - -# Check if .env exists -if [ ! -f .env ]; then - echo -e "${RED}Error: .env file not found!${NC}" - echo "Please create .env file with database credentials" - exit 1 -fi - -# Pull latest code (if using git deployment) -if [ -d .git ]; then - echo -e "${YELLOW}Pulling latest code...${NC}" - git pull origin main || git pull origin master -fi - -# Stop existing containers -echo -e "${YELLOW}Stopping existing containers...${NC}" -docker compose down - -# Build new image -echo -e "${YELLOW}Building Docker image...${NC}" -docker compose build --no-cache - -# Start containers -echo -e "${YELLOW}Starting containers...${NC}" -docker compose up -d - -# Wait for container to be ready -echo -e "${YELLOW}Waiting for application to start...${NC}" -sleep 10 - -# Run migrations -echo -e "${YELLOW}Running database migrations...${NC}" -docker compose exec -T app php artisan migrate --force || { - echo -e "${RED}Migration failed! Rolling back...${NC}" - docker compose down - exit 1 -} - -# Clear and cache configuration -echo -e "${YELLOW}Optimizing application...${NC}" -docker compose exec -T app php artisan config:cache -docker compose exec -T app php artisan route:cache -docker compose exec -T app php artisan view:cache - -# Set proper permissions -echo -e "${YELLOW}Setting permissions...${NC}" -docker compose exec -T app chown -R www-data:www-data /var/www/html/storage -docker compose exec -T app chmod -R 755 /var/www/html/storage - -# Health check -echo -e "${YELLOW}Performing health check...${NC}" -sleep 5 -HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080) - -if [ "$HTTP_STATUS" -eq 200 ]; then - echo -e "${GREEN}✓ Deployment successful! Application is running.${NC}" - echo -e "${GREEN}✓ HTTP Status: ${HTTP_STATUS}${NC}" - - # Keep only last 5 backups - cd "${BACKUP_DIR}" - ls -t backup_*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm - - echo -e "${GREEN}Deployment completed successfully!${NC}" -else - echo -e "${RED}✗ Health check failed! HTTP Status: ${HTTP_STATUS}${NC}" - echo -e "${YELLOW}Check logs: docker compose logs app${NC}" - exit 1 -fi - -# Display container status -echo -e "${YELLOW}Container status:${NC}" -docker compose ps diff --git a/docker-compose.portainer.dev.yml b/docker-compose.portainer.dev.yml deleted file mode 100644 index eb741f0..0000000 --- a/docker-compose.portainer.dev.yml +++ /dev/null @@ -1,48 +0,0 @@ -version: '3.8' - -# Development Stack - Portainer Configuration -# Deploy this through Portainer UI: Stacks -> Add Stack -> Web Editor -# Branch: dev - -services: - app: - image: merchbay_admin:dev - container_name: merchbay_admin_dev - restart: unless-stopped - environment: - - APP_ENV=staging - - APP_DEBUG=false - - APP_URL=https://dev-admin.merchbay.app - - DB_CONNECTION=mysql - - DB_HOST=${DB_HOST} - - DB_PORT=${DB_PORT:-3306} - - DB_DATABASE=${DB_DATABASE} - - DB_USERNAME=${DB_USERNAME} - - DB_PASSWORD=${DB_PASSWORD} - volumes: - - app_storage_dev:/var/www/html/storage - - app_uploads_dev:/var/www/html/public/uploads - labels: - - "traefik.enable=true" - - "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev-admin.merchbay.app`)" - - "traefik.http.routers.merchbay-admin-dev.entrypoints=websecure" - - "traefik.http.routers.merchbay-admin-dev.tls=true" - - "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt" - - "traefik.http.services.merchbay-admin-dev.loadbalancer.server.port=80" - # HTTP to HTTPS redirect - - "traefik.http.routers.merchbay-admin-dev-http.rule=Host(`dev-admin.merchbay.app`)" - - "traefik.http.routers.merchbay-admin-dev-http.entrypoints=web" - - "traefik.http.routers.merchbay-admin-dev-http.middlewares=https-redirect" - - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" - networks: - - traefik-public - -volumes: - app_storage_dev: - driver: local - app_uploads_dev: - driver: local - -networks: - traefik-public: - external: true diff --git a/docker-compose.portainer.yml b/docker-compose.portainer.yml deleted file mode 100644 index f515587..0000000 --- a/docker-compose.portainer.yml +++ /dev/null @@ -1,49 +0,0 @@ -version: '3.8' - -# Production Stack - Portainer Configuration -# Deploy this through Portainer UI: Stacks -> Add Stack -> Web Editor -# Branch: main - Uses paid SSL certificate - -services: - app: - image: merchbay_admin:latest - container_name: merchbay_admin_prod - restart: unless-stopped - environment: - - APP_ENV=production - - APP_DEBUG=false - - APP_URL=https://merchbay.com - - DB_CONNECTION=mysql - - DB_HOST=your-mysql-host - - DB_PORT=3306 - - DB_DATABASE=merchbay_admin - - DB_USERNAME=your-mysql-user - - DB_PASSWORD=your-mysql-password - volumes: - - app_storage:/var/www/html/storage - - app_uploads:/var/www/html/public/uploads - labels: - - "traefik.enable=true" - - "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.com`)" - - "traefik.http.routers.merchbay-admin.entrypoints=websecure" - - "traefik.http.routers.merchbay-admin.tls=true" - # Use custom TLS configuration (file provider for paid cert) - # Ensure Traefik has file provider configured with your paid SSL cert - - "traefik.http.services.merchbay-admin.loadbalancer.server.port=80" - # HTTP to HTTPS redirect - - "traefik.http.routers.merchbay-admin-http.rule=Host(`merchbay.com`)" - - "traefik.http.routers.merchbay-admin-http.entrypoints=web" - - "traefik.http.routers.merchbay-admin-http.middlewares=https-redirect" - - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https" - networks: - - traefik-public - -volumes: - app_storage: - driver: local - app_uploads: - driver: local - -networks: - traefik-public: - external: true diff --git a/readme.md b/readme.md index 7f8816d..5f90076 100644 --- a/readme.md +++ b/readme.md @@ -1,27 +1,178 @@ -# Laravel PHP Framework +# MerchBay Admin Panel -[![Build Status](https://travis-ci.org/laravel/framework.svg)](https://travis-ci.org/laravel/framework) -[![Total Downloads](https://poser.pugx.org/laravel/framework/d/total.svg)](https://packagist.org/packages/laravel/framework) -[![Latest Stable Version](https://poser.pugx.org/laravel/framework/v/stable.svg)](https://packagist.org/packages/laravel/framework) -[![Latest Unstable Version](https://poser.pugx.org/laravel/framework/v/unstable.svg)](https://packagist.org/packages/laravel/framework) -[![License](https://poser.pugx.org/laravel/framework/license.svg)](https://packagist.org/packages/laravel/framework) +A comprehensive administration platform built with Laravel 5.2 for managing e-commerce operations, product catalogs, and customer relationships. -Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as authentication, routing, sessions, queueing, and caching. +## Overview -Laravel is accessible, yet powerful, providing tools needed for large, robust applications. A superb inversion of control container, expressive migration system, and tightly integrated unit testing support give you the tools you need to build any application with which you are tasked. +MerchBay Admin is a web-based administration interface designed to streamline business operations for custom merchandise and sportswear management. The platform provides robust tools for inventory control, order processing, and analytics. -## Official Documentation +## Technology Stack -Documentation for the framework can be found on the [Laravel website](http://laravel.com/docs). +- **Framework**: Laravel 5.2 +- **PHP Version**: 7.4 +- **Web Server**: Apache 2.4 +- **Database**: MySQL +- **Reverse Proxy**: Traefik with Let's Encrypt SSL +- **Containerization**: Docker & Docker Compose +- **CI/CD**: Gitea Actions -## Contributing +## Features -Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions). +- User authentication and role-based access control +- Product and inventory management +- Order processing and tracking +- Customer relationship management +- Analytics and reporting dashboard +- RESTful API endpoints +- Secure HTTPS communication -## Security Vulnerabilities +## Requirements -If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. +- Docker Engine 20.10+ +- Docker Compose 2.0+ +- PHP 7.4 (for local development) +- Composer 1.x +- MySQL 5.7+ or MariaDB 10.3+ + +## Quick Start + +### Using Docker (Recommended) + +```bash +# Clone the repository +git clone +cd merchbay_admin + +# Copy environment file +cp .env.example .env + +# Configure your environment variables +vim .env + +# Build and start containers +docker-compose up -d + +# Install dependencies +docker exec merchbay_admin_app composer install + +# Generate application key +docker exec merchbay_admin_app php artisan key:generate + +# Run migrations +docker exec merchbay_admin_app php artisan migrate +``` + +### Local Development + +```bash +# Install PHP dependencies +composer install + +# Copy environment file +cp .env.example .env + +# Generate application key +php artisan key:generate + +# Configure database in .env file +# Run migrations +php artisan migrate + +# Start development server +php artisan serve +``` + +## Configuration + +### Environment Variables + +Key environment variables to configure: + +- `APP_URL` - Application URL (e.g., https://admin.merchbay.app) +- `DB_HOST` - Database host +- `DB_DATABASE` - Database name +- `DB_USERNAME` - Database username +- `DB_PASSWORD` - Database password + +### SSL/HTTPS Configuration + +The application uses Traefik as a reverse proxy with automatic Let's Encrypt SSL certificates. Ensure your DNS is properly configured and the following Traefik labels are set in `docker-compose.yml`. + +## Deployment + +This project includes automated CI/CD pipelines via Gitea Actions: + +- **Development**: Auto-deploys on push to `dev` branch +- **Production**: Auto-deploys on push to `main`/`master` branch +- **Manual Builds**: Trigger builds with custom tags + +Refer to [DEPLOYMENT.md](DEPLOYMENT.md) and [DEPLOYMENT-PORTAINER.md](DEPLOYMENT-PORTAINER.md) for detailed deployment instructions. + +## Project Structure + +``` +merchbay_admin/ +├── app/ # Application core files +│ ├── Http/ # Controllers, middleware, routes +│ ├── Models/ # Eloquent models +│ └── Providers/ # Service providers +├── config/ # Configuration files +├── database/ # Migrations and seeds +├── public/ # Public assets +├── resources/ # Views, assets, lang files +├── storage/ # Application storage +├── .gitea/workflows/ # CI/CD pipelines +└── docker-compose.yml # Docker configuration +``` + +## Development + +### Running Tests + +```bash +# Run PHPUnit tests +docker exec merchbay_admin_app vendor/bin/phpunit + +# Or locally +./vendor/bin/phpunit +``` + +### Artisan Commands + +```bash +# List all available commands +docker exec merchbay_admin_app php artisan list + +# Clear application cache +docker exec merchbay_admin_app php artisan cache:clear + +# Run database migrations +docker exec merchbay_admin_app php artisan migrate +``` + +## Security + +- All HTTP traffic is automatically redirected to HTTPS +- Environment variables are managed securely via `.env` files +- SQL injection prevention via Eloquent ORM +- CSRF protection enabled on all forms +- XSS protection via Blade templating + +For security vulnerabilities, please contact the development team directly. + +## Documentation + +Additional documentation is available: + +- [Docker Setup Guide](README-DOCKER.md) +- [Deployment Guide](DEPLOYMENT.md) +- [Portainer Deployment](DEPLOYMENT-PORTAINER.md) +- [Traefik SSL Configuration](TRAEFIK-SSL-CONFIG.md) + +## Support + +For issues, questions, or contributions, please contact the development team or open an issue in the repository. ## License -The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). +This project is proprietary software. All rights reserved. diff --git a/setup-server-env.sh b/setup-server-env.sh deleted file mode 100755 index 3ea7d17..0000000 --- a/setup-server-env.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash - -# Server Environment Setup Script -# This script helps you set up .env files on your deployment servers - -set -e - -echo "================================================" -echo "Server Environment Setup for MerchBay Admin" -echo "================================================" -echo "" - -# Color codes for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Function to prompt for input with default value -prompt_input() { - local prompt="$1" - local default="$2" - local value - - if [ -n "$default" ]; then - read -p "$prompt [$default]: " value - echo "${value:-$default}" - else - read -p "$prompt: " value - echo "$value" - fi -} - -# Function to prompt for password (hidden input) -prompt_password() { - local prompt="$1" - local value - - read -s -p "$prompt: " value - echo "" - echo "$value" -} - -# Choose environment -echo "Which environment are you setting up?" -echo "1) Production" -echo "2) Development" -read -p "Enter choice [1-2]: " env_choice - -case $env_choice in - 1) - ENV_TYPE="production" - DEPLOY_DIR="/var/www/merchbay_admin" - DEFAULT_DOMAIN="merchbay.com" - DEFAULT_APP_URL="https://merchbay.com" - DEFAULT_APP_ENV="production" - DEFAULT_DB_NAME="merchbay_prod" - ;; - 2) - ENV_TYPE="development" - DEPLOY_DIR="/var/www/merchbay_admin_dev" - DEFAULT_DOMAIN="dev-admin.merchbay.app" - DEFAULT_APP_URL="https://dev-admin.merchbay.app" - DEFAULT_APP_ENV="staging" - DEFAULT_DB_NAME="merchbay_dev" - ;; - *) - echo -e "${RED}Invalid choice${NC}" - exit 1 - ;; -esac - -echo -e "\n${GREEN}Setting up $ENV_TYPE environment${NC}\n" - -# Collect information -echo "=== Application Settings ===" -APP_ENV=$(prompt_input "APP_ENV" "$DEFAULT_APP_ENV") -APP_DEBUG=$(prompt_input "APP_DEBUG (true/false)" "false") -APP_URL=$(prompt_input "APP_URL" "$DEFAULT_APP_URL") -DOMAIN=$(prompt_input "DOMAIN" "$DEFAULT_DOMAIN") - -echo -e "\n=== Database Settings ===" -DB_HOST=$(prompt_input "DB_HOST" "localhost") -DB_PORT=$(prompt_input "DB_PORT" "3306") -DB_DATABASE=$(prompt_input "DB_DATABASE" "$DEFAULT_DB_NAME") -DB_USERNAME=$(prompt_input "DB_USERNAME" "merchbay_user") -DB_PASSWORD=$(prompt_password "DB_PASSWORD") - -echo -e "\n=== Server Connection ===" -SERVER_USER=$(prompt_input "SSH Username" "root") -SERVER_HOST=$(prompt_input "Server IP/Hostname" "") - -if [ -z "$SERVER_HOST" ]; then - echo -e "${RED}Error: Server hostname is required${NC}" - exit 1 -fi - -# Generate .env content -ENV_CONTENT="APP_ENV=$APP_ENV -APP_DEBUG=$APP_DEBUG -APP_URL=$APP_URL -DB_HOST=$DB_HOST -DB_PORT=$DB_PORT -DB_DATABASE=$DB_DATABASE -DB_USERNAME=$DB_USERNAME -DB_PASSWORD=$DB_PASSWORD -DOMAIN=$DOMAIN" - -# Show summary -echo -e "\n${YELLOW}=== Configuration Summary ===${NC}" -echo "Environment: $ENV_TYPE" -echo "Deploy Directory: $DEPLOY_DIR" -echo "Server: $SERVER_USER@$SERVER_HOST" -echo "Domain: $DOMAIN" -echo "Database: $DB_DATABASE" -echo "" - -# Ask for confirmation -read -p "Deploy this configuration to the server? (y/n): " confirm - -if [ "$confirm" != "y" ]; then - echo "Aborted." - exit 0 -fi - -# Deploy to server -echo -e "\n${GREEN}Deploying configuration to server...${NC}" - -# Create deployment directory and .env file -ssh "$SERVER_USER@$SERVER_HOST" "mkdir -p $DEPLOY_DIR" - -# Upload .env file -echo "$ENV_CONTENT" | ssh "$SERVER_USER@$SERVER_HOST" "cat > $DEPLOY_DIR/.env && chmod 600 $DEPLOY_DIR/.env" - -echo -e "\n${GREEN}✓ Configuration deployed successfully!${NC}" -echo -e "\nThe .env file has been created at: ${YELLOW}$DEPLOY_DIR/.env${NC}" -echo "" - -# Display Gitea secrets needed -echo -e "${YELLOW}=== Gitea Secrets Required ===${NC}" -if [ "$ENV_TYPE" = "production" ]; then - echo "Add these secrets to your Gitea repository:" - echo " • PROD_DEPLOY_SSH_KEY: Your SSH private key" - echo " • PROD_DEPLOY_USER: $SERVER_USER" - echo " • PROD_DEPLOY_HOST: $SERVER_HOST" -else - echo "Add these secrets to your Gitea repository:" - echo " • DEPLOY_SSH_KEY: Your SSH private key" - echo " • DEPLOY_USER: $SERVER_USER" - echo " • DEPLOY_HOST: $SERVER_HOST" -fi - -echo -e "\n${GREEN}Setup complete!${NC}" diff --git a/setup-ssh-keys.sh b/setup-ssh-keys.sh deleted file mode 100755 index d1ccaa7..0000000 --- a/setup-ssh-keys.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash - -# SSH Key Generation Script for Gitea Deployment -# This script generates SSH keys and helps you set them up - -set -e - -echo "================================================" -echo "SSH Key Setup for Gitea Deployment" -echo "================================================" -echo "" - -# Color codes -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -SSH_KEY_PATH="$HOME/.ssh/gitea_deploy_key" - -# Check if key already exists -if [ -f "$SSH_KEY_PATH" ]; then - echo -e "${YELLOW}Warning: SSH key already exists at $SSH_KEY_PATH${NC}" - read -p "Do you want to overwrite it? (y/n): " overwrite - if [ "$overwrite" != "y" ]; then - echo "Using existing key." - else - rm -f "$SSH_KEY_PATH" "$SSH_KEY_PATH.pub" - echo "Generating new SSH key..." - ssh-keygen -t ed25519 -C "gitea-deploy-key" -f "$SSH_KEY_PATH" -N "" - fi -else - echo "Generating new SSH key..." - ssh-keygen -t ed25519 -C "gitea-deploy-key" -f "$SSH_KEY_PATH" -N "" -fi - -echo -e "\n${GREEN}✓ SSH key generated successfully!${NC}\n" - -# Display private key for Gitea -echo -e "${YELLOW}=== PRIVATE KEY (for Gitea Secrets) ===${NC}" -echo -e "${BLUE}Copy this ENTIRE content for your Gitea secret:${NC}\n" -cat "$SSH_KEY_PATH" -echo "" - -# Display public key for server -echo -e "\n${YELLOW}=== PUBLIC KEY (for Server) ===${NC}" -echo -e "${BLUE}Copy this content to add to your server's ~/.ssh/authorized_keys:${NC}\n" -cat "$SSH_KEY_PATH.pub" -echo "" - -# Ask if user wants to deploy to server now -echo -e "\n${YELLOW}=== Deploy Public Key to Server ===${NC}" -read -p "Do you want to add the public key to a server now? (y/n): " deploy_now - -if [ "$deploy_now" = "y" ]; then - read -p "Enter SSH username: " ssh_user - read -p "Enter server IP/hostname: " ssh_host - - echo -e "\nAdding public key to $ssh_user@$ssh_host..." - - # Copy public key to server - ssh-copy-id -i "$SSH_KEY_PATH.pub" "$ssh_user@$ssh_host" 2>/dev/null || \ - ssh "$ssh_user@$ssh_host" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" < "$SSH_KEY_PATH.pub" - - echo -e "\n${GREEN}✓ Public key added to server!${NC}" - - # Test connection - echo -e "\nTesting SSH connection..." - if ssh -i "$SSH_KEY_PATH" -o StrictHostKeyChecking=no "$ssh_user@$ssh_host" "echo 'Connection successful!'" 2>/dev/null; then - echo -e "${GREEN}✓ SSH connection test successful!${NC}" - else - echo -e "${YELLOW}⚠ SSH connection test failed. Please check your server configuration.${NC}" - fi -fi - -# Summary -echo -e "\n${GREEN}=== Setup Complete! ===${NC}" -echo -e "\n${YELLOW}Next Steps:${NC}" -echo "1. Copy the PRIVATE KEY above and add it to Gitea Secrets as:" -echo " • DEPLOY_SSH_KEY (for dev)" -echo " • PROD_DEPLOY_SSH_KEY (for production)" -echo "" -echo "2. If you didn't deploy the public key yet, manually add it to your server:" -echo " ssh user@server" -echo " echo '$(cat "$SSH_KEY_PATH.pub")' >> ~/.ssh/authorized_keys" -echo "" -echo "3. The key files are saved at:" -echo " Private: $SSH_KEY_PATH" -echo " Public: $SSH_KEY_PATH.pub" -echo "" -- 2.49.1 From e45cfb5ebd075f9d0bfdec3c09bedb2a9b3dc40f Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 13:13:24 +0800 Subject: [PATCH 30/33] Update deployment scripts to specify required environment variables in .env file and docker-compose --- .gitea/workflows/deploy-dev.yml | 3 ++- .gitea/workflows/deploy.yml | 3 ++- docker-compose.yml | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 72346c0..2d959f2 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -79,7 +79,8 @@ jobs: echo "🔍 Checking .env file" if [ ! -f .env ]; then echo "❌ .env file not found at $DEPLOY_DIR/.env" - echo "Please create it first. See DEPLOYMENT-SETUP.md" + echo "Please create it first with required variables:" + echo " - DB_*, IMAGES_DIRECTORY, PRODUCTION_PRIVATE_SERVER" exit 1 fi diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index f379cc9..aee6688 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -50,7 +50,8 @@ jobs: cp docker-compose.yml \$DEPLOY_DIR/ cd \$DEPLOY_DIR - # .env file should already exist on server with all secrets + # .env file should already exist on server with all required variables + # Required: DB_*, IMAGES_DIRECTORY, PRODUCTION_PRIVATE_SERVER # If it doesn't exist, deployment will fail (this is intentional for security) docker compose down || true diff --git a/docker-compose.yml b/docker-compose.yml index c6cc4d5..58298e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,8 @@ services: - DB_DATABASE=${DB_DATABASE} - DB_USERNAME=${DB_USERNAME} - DB_PASSWORD=${DB_PASSWORD} + - IMAGES_DIRECTORY=${IMAGES_DIRECTORY} + - PRODUCTION_PRIVATE_SERVER=${PRODUCTION_PRIVATE_SERVER} volumes: - ./storage:/var/www/html/storage - ./public/uploads:/var/www/html/public/uploads -- 2.49.1 From 39abf1b5fc363c57b79d7974f7c35fa19bb602a1 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 14:53:13 +0800 Subject: [PATCH 31/33] Enhance deployment workflows to remove old Docker images and prune unused resources --- .gitea/workflows/deploy-dev.yml | 9 ++++++++- .gitea/workflows/deploy.yml | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 2d959f2..08a91f8 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -71,6 +71,9 @@ jobs: echo "📦 Loading image" docker load < /tmp/merchbay_admin_dev.tar.gz + echo "🧹 Removing old merchbay_admin images" + docker images | grep merchbay_admin | grep -v "$(docker images merchbay_admin:dev -q)" | awk '{print $3}' | xargs -r docker rmi -f || true + echo "📄 Updating compose file" cp /tmp/docker-compose.yml "$DEPLOY_DIR/" @@ -112,7 +115,11 @@ jobs: echo "🧹 Cleanup" rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml - docker image prune -f + + echo "🧹 Pruning unused Docker resources" + docker image prune -af --filter "until=24h" || true + docker container prune -f || true + docker system df echo "✅ Deployment completed" EOF diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index aee6688..bcbe022 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -47,6 +47,10 @@ jobs: mkdir -p \$DEPLOY_DIR cd /tmp docker load < merchbay_admin.tar.gz + + echo 'Removing old merchbay_admin images' + docker images | grep merchbay_admin | grep -v "\$(docker images merchbay_admin:latest -q)" | awk '{print \$3}' | xargs -r docker rmi -f || true + cp docker-compose.yml \$DEPLOY_DIR/ cd \$DEPLOY_DIR @@ -66,6 +70,12 @@ jobs: docker compose exec -T app php artisan route:cache docker compose exec -T app php artisan view:cache rm -f /tmp/merchbay_admin.tar.gz /tmp/docker-compose.yml + + echo 'Pruning unused Docker resources' + docker image prune -af --filter "until=24h" || true + docker container prune -f || true + docker system df + echo 'Production deployment completed successfully!' echo 'Application available at: https://merchbay.com' " -- 2.49.1 From 7c4650f83b121f7691c207ee2f25349f654bd9d6 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Thu, 18 Dec 2025 15:03:33 +0800 Subject: [PATCH 32/33] Enhance Docker cleanup in deployment workflows to reclaim space and improve resource management --- .gitea/workflows/deploy-dev.yml | 5 ++++- .gitea/workflows/deploy.yml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yml b/.gitea/workflows/deploy-dev.yml index 08a91f8..681ec28 100644 --- a/.gitea/workflows/deploy-dev.yml +++ b/.gitea/workflows/deploy-dev.yml @@ -116,9 +116,12 @@ jobs: echo "🧹 Cleanup" rm -f /tmp/merchbay_admin_dev.tar.gz /tmp/docker-compose.yml - echo "🧹 Pruning unused Docker resources" + echo "🧹 Aggressive Docker cleanup to reclaim space" docker image prune -af --filter "until=24h" || true docker container prune -f || true + docker volume prune -f || true + docker builder prune -af --filter "until=48h" || true + echo "📊 Docker space usage:" docker system df echo "✅ Deployment completed" diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index bcbe022..4adaa6b 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -71,9 +71,12 @@ jobs: docker compose exec -T app php artisan view:cache rm -f /tmp/merchbay_admin.tar.gz /tmp/docker-compose.yml - echo 'Pruning unused Docker resources' + echo 'Aggressive Docker cleanup to reclaim space' docker image prune -af --filter "until=24h" || true docker container prune -f || true + docker volume prune -f || true + docker builder prune -af --filter "until=48h" || true + echo 'Docker space usage:' docker system df echo 'Production deployment completed successfully!' -- 2.49.1 From 1c29fbf95809551c39c4b77a9278d66af266fb38 Mon Sep 17 00:00:00 2001 From: Frank John Begornia Date: Sun, 21 Dec 2025 04:02:00 +0800 Subject: [PATCH 33/33] Update deployment workflow to use environment-specific variables and enhance application URL references --- .gitea/workflows/deploy.yml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 4adaa6b..3406a42 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,4 +1,4 @@ -name: Deploy Production +name: Deploy Production (admin.merchbay.app) on: push: @@ -35,14 +35,14 @@ jobs: run: | mkdir -p ~/.ssh chmod 700 ~/.ssh - echo "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key + echo "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh-keygen -y -f ~/.ssh/deploy_key > /dev/null 2>&1 || { echo "Error: Invalid SSH key format"; exit 1; } cd /workspace/repo - scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST:/tmp/" + scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay_admin.tar.gz docker-compose.yml "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" - ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST" " + ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$DEPLOY_USER@$DEPLOY_HOST" " DEPLOY_DIR='/var/www/merchbay_admin' mkdir -p \$DEPLOY_DIR cd /tmp @@ -61,14 +61,13 @@ jobs: docker compose down || true docker image prune -f docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public - export DOMAIN=merchbay.com - export APP_URL=https://merchbay.com + docker network inspect crew-app-net >/dev/null 2>&1 || docker network create crew-app-net + export DOMAIN=admin.merchbay.app + export APP_URL=https://admin.merchbay.app docker compose up -d sleep 10 - docker compose exec -T app php artisan migrate --force docker compose exec -T app php artisan config:cache docker compose exec -T app php artisan route:cache - docker compose exec -T app php artisan view:cache rm -f /tmp/merchbay_admin.tar.gz /tmp/docker-compose.yml echo 'Aggressive Docker cleanup to reclaim space' @@ -80,15 +79,15 @@ jobs: docker system df echo 'Production deployment completed successfully!' - echo 'Application available at: https://merchbay.com' + echo 'Application available at: https://admin.merchbay.app' " env: - PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }} - PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }} - PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }} + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - name: Health Check shell: sh run: | sleep 10 - curl -f https://merchbay.com || exit 1 + curl -f https://admin.merchbay.app || exit 1 -- 2.49.1