#}

Deploy API on VPS WITH Traefik and Let's Encrypt SSL

Deploy GEMVC API on VPS with Traefik and Let's Encrypt SSL

VPS Deployment with Traefik & Automatic SSL

Complete guide for deploying a Dockerized GEMVC application on a VPS with Traefik reverse proxy and automatic Let's Encrypt SSL.

Docker

OpenSwoole

Traefik

Let's Encrypt

Core Concepts

  • VPS: Your private server space on the internet
  • Docker: Package your app into portable containers
  • Traefik: Reverse proxy that auto-discovers containers
  • Let's Encrypt: Free automatic SSL certificates

Part 1: Initial Server Setup

Prerequisites

  • βœ… VPS running Ubuntu 24.04 (or similar)
  • βœ… Registered domain name
  • βœ… DNS A record pointing to your VPS IP

Step 1: Install Docker

Install Docker
# Update package lists
sudo apt-get update

# Install prerequisites
sudo apt-get install -y ca-certificates curl

# Add Docker's GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add Docker repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Part 2: Traefik Setup

Step 2: Create Directory Structure

Create Directories
# Create infrastructure directory
mkdir -p /root/stacks/infra
cd /root/stacks/infra

Step 3: Create Traefik Docker Compose

Create /root/stacks/infra/docker-compose.yml:

docker-compose.yml (Traefik)
version: '3.8'

services:
  traefik:
    image: "traefik:v3.0"
    container_name: "traefik"
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
      - "--certificatesresolvers.mytlschallenge.acme.email=your-email@example.com"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    networks:
      - shared-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.your-domain.com`)"
      - "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
      - "traefik.http.routers.traefik-dashboard.tls.certresolver=mytlschallenge"
      - "traefik.http.routers.traefik-dashboard.service=api@internal"

networks:
  shared-net:
    name: shared-net
Tip: Replace your-email@example.com and your-domain.com with your actual values!

Step 4: Start Traefik

Start Traefik
cd /root/stacks/infra
docker compose up -d

Part 3: Deploy Your Application

Step 5: Create App Directory

Create App Directory
mkdir -p /root/stacks/app/gemvc-api
cd /root/stacks/app/gemvc-api

Step 6: Application Docker Compose

docker-compose.yml (App)
version: '3.8'

services:
  gemvc-api:
    image: your-dockerhub-username/gemvc-api:latest
    container_name: gemvc-api
    restart: unless-stopped
    env_file:
      - .env
    networks:
      - shared-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gemvc-api.rule=Host(`api.your-domain.com`)"
      - "traefik.http.routers.gemvc-api.entrypoints=websecure"
      - "traefik.http.routers.gemvc-api.tls.certresolver=mytlschallenge"
      - "traefik.http.services.gemvc-api.loadbalancer.server.port=9501"

networks:
  shared-net:
    external: true

Step 7: Create Environment File

info: This step is mandatory! Your application will fail without a properly configured .env file.
.env (Production)
# /root/stacks/app/gemvc-api/.env
APP_ENV=production
SWOOLE_DISPLAY_ERRORS=0

DB_HOST=your-db-host
DB_NAME=gemvc_production
DB_USER=gemvc
DB_PASSWORD=your-strong-password

TOKEN_SECRET=your-very-long-random-secret-key-minimum-32-chars
TOKEN_ISSUER=YourCompany
Secure .env
# Set strict permissions
chmod 600 /root/stacks/app/gemvc-api/.env

Step 8: Start Application

Start Application
cd /root/stacks/app/gemvc-api
docker compose up -d

Part 4: CI/CD with GitHub Actions

Step 9: GitHub Actions Workflow

GitHub Actions Workflow
# .github/workflows/docker-publish.yml
name: CI - Build and Push Docker Image

on:
  release:
    types: [published]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - uses: docker/setup-buildx-action@v2
      
      - uses: docker/login-action@v2
        with:
          username: \${{ secrets.DOCKERHUB_USERNAME }}
          password: \${{ secrets.DOCKERHUB_TOKEN }}
      
      - uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            \${{ secrets.DOCKERHUB_USERNAME }}/gemvc-api:latest
            \${{ secrets.DOCKERHUB_USERNAME }}/gemvc-api:\${{ github.ref_name }}

Step 10: Update Script

Update Script
#!/bin/bash
# /root/scripts/restart_gemvc-api.sh
set -e

APP_DIR="/root/stacks/app/gemvc-api"

echo "--- Stopping stack... ---"
cd "$APP_DIR" && docker compose down

echo "--- Pulling latest image... ---"
cd "$APP_DIR" && docker compose pull

echo "--- Starting stack... ---"
cd "$APP_DIR" && docker compose up -d

echo "--- Done! ---"
docker ps --filter "name=gemvc-api"
Make Executable
chmod +x /root/scripts/restart_gemvc-api.sh

Deployment Checklist

  • DNS A record points to VPS IP
  • Docker and Docker Compose installed
  • Traefik running and SSL working
  • .env file created with production settings
  • Application container running

Next Steps