🏠 Home / Hub

🚀 Projects 05 — Deploy Pipeline

← Projects Menu

Goal: Vue frontend + Laravel API ကို production server မှာ deploy လုပ်မယ်။ GitHub Actions CI/CD, Nginx, SSL, PM2/Supervisor, database migration automation တွေပါမယ်။

1. Architecture Overview

[Developer Machine]
   │
   ▼  git push
[GitHub Repository]
   │
   ▼  GitHub Actions trigger
[CI/CD Pipeline]
   ├─ Run tests
   ├─ Build Vue frontend (npm run build)
   ├─ SSH to VPS
   └─ Deploy (git pull → migrate → optimize → reload)
         │
         ▼
[VPS / Cloud Server]
   ├─ Nginx (port 80/443, SSL, reverse proxy)
   ├─ PHP-FPM (Laravel API)
   ├─ Node.js/PM2 (optional for Node services)
   └─ PostgreSQL / MySQL database

2. Repository Structure Best Practices

repo/
├── .github/
│   └── workflows/
│       └── deploy.yml        ← GitHub Actions CI/CD
├── api/                      ← Laravel backend
│   ├── .env.example          ← env template (NO real secrets)
│   ├── .gitignore            ← exclude vendor/, .env, storage/
│   └── ...
├── frontend/                 ← Vue app
│   ├── .env.example
│   ├── .gitignore
│   └── ...
├── .gitignore                ← root gitignore
└── README.md

# .gitignore (critical — NEVER commit these)
.env
vendor/
node_modules/
storage/
*.log
.DS_Store
/public/hot

3. GitHub Actions CI/CD (.github/workflows/deploy.yml)

name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Build Vue frontend
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: cd frontend && npm ci && npm run build

      # Deploy via SSH
      - name: Deploy to VPS
        uses: appleboy/ssh-action@v1.0.0
        with:
          host:     ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key:      ${{ secrets.VPS_SSH_KEY }}
          script: |
            cd /var/www/myapp
            git pull origin main
            cd api
            composer install --no-dev --optimize-autoloader
            php artisan migrate --force
            php artisan config:cache
            php artisan route:cache
            php artisan view:cache
            sudo systemctl reload php8.2-fpm
            sudo supervisorctl restart laravel-queue
            # Copy built frontend
            cp -r /var/www/myapp/frontend/dist/* /var/www/myapp/public/
GitHub Secrets (Settings → Secrets): VPS_HOST, VPS_USER, VPS_SSH_KEY ထည့်ပါ

4. Nginx Configuration

# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$server_name$request_uri;  # Redirect HTTP → HTTPS
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    root /var/www/myapp/public;
    index index.php;

    # Vue SPA routing
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Laravel API
    location /api {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # PHP-FPM
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    add_header Referrer-Policy "strict-origin-when-cross-origin";

    gzip on;
    gzip_types text/css application/javascript image/svg+xml;

    client_max_body_size 10M;

    location ~ /\.ht { deny all; }
}

# Enable site & reload
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

5. SSL with Let's Encrypt (Free HTTPS)

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Auto-renew (already set up by certbot, but verify)
sudo systemctl status certbot.timer
sudo certbot renew --dry-run

6. Queue Worker (Supervisor)

# /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-queue]
command=php /var/www/myapp/api/artisan queue:work --sleep=3 --tries=3
directory=/var/www/myapp/api
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/myapp/api/storage/logs/queue.log

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-queue:*

7. Environment Variables (Production .env)

APP_NAME=MyApp
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=myapp_prod
DB_USERNAME=myapp_user
DB_PASSWORD=very_strong_password_here

CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=postmaster@mg.yourdomain.com
MAIL_PASSWORD=mailgun_api_key

# DO NOT commit this file!
# Use .env.example as template

8. Deployment Checklist

CategoryTaskDone?
CodeAll tests passing on CI
CodeNo TODO/debug code in production branch
ConfigAPP_DEBUG=false on production
ConfigALLOWED_HOSTS / CORS origins set correctly
Config.env not in git, .env.example committed
DatabaseMigrations ran successfully
DatabaseDB backups configured
Performanceconfig:cache, route:cache, view:cache run
SecurityHTTPS enabled, SSL cert valid
SecurityFirewall (ufw) allows only 80/443/22
MonitoringError logs configured and rotated

📌 Study Checklist