From 791d18495449a67017777a60992808c8cd269ae5 Mon Sep 17 00:00:00 2001 From: Gabriel Menezes Date: Wed, 7 Oct 2026 14:56:34 -0400 Subject: [PATCH] chore: configure docker-compose for homelab with task2.beetech.dev domain - Replace archived MinIO images with community-maintained pgsty images - Change routing domain to task2.beetech.dev across frontend, backend, and minio - Avoid port collisions with existing homelab services (postgres port 5434) - Add .env and *.pem to .gitignore - Remove legacy deploy/ directory and deploy-main.yml workflow --- .github/workflows/deploy-main.yml | 158 ------------------ .gitignore | 3 + .../src/main/resources/application.properties | 2 +- deploy/.env.production.example | 20 --- deploy/docker-compose.prod.yml | 94 ----------- docker-compose.yml | 91 ++++++++-- frontend/.env.production | 2 +- 7 files changed, 86 insertions(+), 284 deletions(-) delete mode 100644 .github/workflows/deploy-main.yml delete mode 100644 deploy/.env.production.example delete mode 100644 deploy/docker-compose.prod.yml diff --git a/.github/workflows/deploy-main.yml b/.github/workflows/deploy-main.yml deleted file mode 100644 index c1cc08a..0000000 --- a/.github/workflows/deploy-main.yml +++ /dev/null @@ -1,158 +0,0 @@ -name: Deploy to Hostinger - -on: - push: - branches: - - main - workflow_dispatch: - -env: - REGISTRY: ghcr.io - FRONTEND_IMAGE_NAME: ${{ github.repository }}-frontend - BACKEND_IMAGE_NAME: ${{ github.repository }}-backend - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: "21" - cache: maven - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: "22" - cache: npm - cache-dependency-path: frontend/package-lock.json - - # - name: Run backend tests - # working-directory: backend - # run: ./mvnw -B test - - - name: Run frontend build - working-directory: frontend - run: | - npm ci - npm run build - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract Docker metadata for frontend - id: meta-frontend - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }} - tags: | - type=raw,value=latest - type=sha - - - name: Extract Docker metadata for backend - id: meta-backend - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }} - tags: | - type=raw,value=latest - type=sha - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and push frontend image - uses: docker/build-push-action@v6 - with: - context: ./frontend - file: ./frontend/Dockerfile - push: true - tags: ${{ steps.meta-frontend.outputs.tags }} - labels: ${{ steps.meta-frontend.outputs.labels }} - build-args: | - VITE_API_URL=${{ secrets.FRONTEND_VITE_API_URL }} - - - name: Build and push backend image - uses: docker/build-push-action@v6 - with: - context: ./backend - file: ./backend/Dockerfile - push: true - tags: ${{ steps.meta-backend.outputs.tags }} - labels: ${{ steps.meta-backend.outputs.labels }} - - - name: Copy deploy files to server - uses: appleboy/scp-action@v0.1.7 - with: - host: ${{ secrets.HOSTINGER_HOST }} - username: ${{ secrets.HOSTINGER_USER }} - key: ${{ secrets.HOSTINGER_SSH_KEY }} - port: ${{ secrets.HOSTINGER_PORT || 22 }} - source: "deploy/docker-compose.prod.yml" - target: "${{ secrets.HOSTINGER_APP_PATH }}" - strip_components: 1 - - - name: Deploy on Hostinger - uses: appleboy/ssh-action@v1.2.0 - env: - FRONTEND_IMAGE: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:latest - BACKEND_IMAGE: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:latest - POSTGRES_USER: ${{ secrets.POSTGRES_USER }} - POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} - DB_URL: ${{ secrets.DB_URL }} - MP_JWT_VERIFY_ISSUER: ${{ secrets.MP_JWT_VERIFY_ISSUER }} - SMALLRYE_JWT_SIGN_KEY: ${{ secrets.SMALLRYE_JWT_SIGN_KEY }} - MP_JWT_VERIFY_PUBLICKEY: ${{ secrets.MP_JWT_VERIFY_PUBLICKEY }} - GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }} - GHCR_TOKEN: ${{ secrets.GHCR_READ_TOKEN }} - MINIO_ROOT_USER: ${{ secrets.MINIO_ROOT_USER }} - MINIO_ROOT_PASSWORD: ${{ secrets.MINIO_ROOT_PASSWORD }} - MINIO_ENDPOINT: ${{ secrets.MINIO_ENDPOINT }} - MINIO_PUBLIC_URL: ${{ secrets.MINIO_PUBLIC_URL }} - MINIO_BUCKET: ${{ secrets.MINIO_BUCKET }} - with: - host: ${{ secrets.HOSTINGER_HOST }} - username: ${{ secrets.HOSTINGER_USER }} - key: ${{ secrets.HOSTINGER_SSH_KEY }} - port: ${{ secrets.HOSTINGER_PORT || 22 }} - envs: FRONTEND_IMAGE,BACKEND_IMAGE,POSTGRES_USER,POSTGRES_PASSWORD,DB_URL,MP_JWT_VERIFY_ISSUER,SMALLRYE_JWT_SIGN_KEY,MP_JWT_VERIFY_PUBLICKEY,GHCR_USERNAME,GHCR_TOKEN,MINIO_ROOT_USER,MINIO_ROOT_PASSWORD,MINIO_ENDPOINT,MINIO_PUBLIC_URL,MINIO_BUCKET - script: | - set -eu - APP_DIR="${{ secrets.HOSTINGER_APP_PATH }}" - mkdir -p "$APP_DIR" - cd "$APP_DIR" - - { - echo "POSTGRES_USER=${POSTGRES_USER}" - echo "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" - echo "DB_URL=${DB_URL}" - echo "FRONTEND_IMAGE=${FRONTEND_IMAGE}" - echo "BACKEND_IMAGE=${BACKEND_IMAGE}" - echo "MP_JWT_VERIFY_ISSUER=${MP_JWT_VERIFY_ISSUER}" - echo "MINIO_ROOT_USER=${MINIO_ROOT_USER}" - echo "MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}" - echo "MINIO_ENDPOINT=${MINIO_ENDPOINT}" - echo "MINIO_PUBLIC_URL=${MINIO_PUBLIC_URL}" - echo "MINIO_BUCKET=${MINIO_BUCKET}" - - printf 'SMALLRYE_JWT_SIGN_KEY="%s"\n' "$SMALLRYE_JWT_SIGN_KEY" - printf 'MP_JWT_VERIFY_PUBLICKEY="%s"\n' "$MP_JWT_VERIFY_PUBLICKEY" - } > .env.production - - echo "${GHCR_TOKEN}" | docker login ghcr.io -u "${GHCR_USERNAME}" --password-stdin - docker compose --env-file .env.production -f docker-compose.prod.yml pull - docker compose --env-file .env.production -f docker-compose.prod.yml up -d - docker image prune -f diff --git a/.gitignore b/.gitignore index 2ad4287..5efca23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .agents .DS_Store .vscode +.env +*.pem + diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index b4c52d0..290eab3 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -1,7 +1,7 @@ quarkus.http.port=8081 quarkus.http.cors.enabled=true -quarkus.http.cors.origins=https://task.beetech.dev +quarkus.http.cors.origins=https://task2.beetech.dev quarkus.http.cors.methods=GET,PUT,POST,DELETE,PATCH,OPTIONS quarkus.http.cors.exposed-headers=Content-Disposition quarkus.http.cors.access-control-max-age=24H diff --git a/deploy/.env.production.example b/deploy/.env.production.example deleted file mode 100644 index 60a0bc1..0000000 --- a/deploy/.env.production.example +++ /dev/null @@ -1,20 +0,0 @@ -POSTGRES_USER=beetask -POSTGRES_PASSWORD=change-me -DB_URL=jdbc:postgresql://203.0.113.10:5432/beetask - -BACKEND_IMAGE=ghcr.io/owner/repo-backend:latest -FRONTEND_IMAGE=ghcr.io/owner/repo-frontend:latest - -QUARKUS_HTTP_CORS_ORIGINS=https://app.example.com -MP_JWT_VERIFY_ISSUER=https://beetech.net -SMALLRYE_JWT_SIGN_KEY_LOCATION=privateKey.pem -MP_JWT_VERIFY_PUBLICKEY_LOCATION=publicKey.pem - -# MinIO (object storage for user avatars) -# MINIO_ROOT_USER and MINIO_ROOT_PASSWORD are used both by the MinIO service -# and by the backend as access/secret keys. -MINIO_ROOT_USER=change-me -MINIO_ROOT_PASSWORD=change-me -MINIO_ENDPOINT=http://minio:9000 -MINIO_PUBLIC_URL=https://minio.task.beetech.dev -MINIO_BUCKET=avatars diff --git a/deploy/docker-compose.prod.yml b/deploy/docker-compose.prod.yml deleted file mode 100644 index 632bd62..0000000 --- a/deploy/docker-compose.prod.yml +++ /dev/null @@ -1,94 +0,0 @@ -services: - postgres: - image: postgres:16 - container_name: bee-task-postgres - restart: unless-stopped - - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB:-beetask} - - volumes: - - postgres_data:/var/lib/postgresql/data - - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] - interval: 10s - timeout: 5s - retries: 5 - - backend: - image: ${BACKEND_IMAGE} - restart: unless-stopped - - environment: - DB_USER: ${POSTGRES_USER} - DB_PASSWORD: ${POSTGRES_PASSWORD} - DB_URL: ${DB_URL} - MP_JWT_VERIFY_ISSUER: ${MP_JWT_VERIFY_ISSUER} - SMALLRYE_JWT_SIGN_KEY: ${SMALLRYE_JWT_SIGN_KEY} - MP_JWT_VERIFY_PUBLICKEY: ${MP_JWT_VERIFY_PUBLICKEY} - MINIO_ENDPOINT: ${MINIO_ENDPOINT} - MINIO_ACCESS_KEY: ${MINIO_ROOT_USER} - MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD} - MINIO_BUCKET: ${MINIO_BUCKET} - MINIO_PUBLIC_URL: ${MINIO_PUBLIC_URL} - - depends_on: - postgres: - condition: service_healthy - - labels: - - "traefik.enable=true" - - "traefik.http.routers.backend.rule=Host(`api.task.beetech.dev`)" - - "traefik.http.routers.backend.entrypoints=websecure" - - "traefik.http.routers.backend.tls.certresolver=letsencrypt" - - "traefik.http.services.backend.loadbalancer.server.port=8081" - - frontend: - image: ${FRONTEND_IMAGE} - restart: unless-stopped - - labels: - - "traefik.enable=true" - - "traefik.http.routers.frontend.rule=Host(`task.beetech.dev`)" - - "traefik.http.routers.frontend.entrypoints=websecure" - - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" - - "traefik.http.services.frontend.loadbalancer.server.port=80" - - minio: - image: minio/minio:latest - restart: unless-stopped - command: server /data --console-address ":9001" - environment: - MINIO_ROOT_USER: ${MINIO_ROOT_USER} - MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} - volumes: - - minio_data:/data - labels: - - "traefik.enable=true" - - "traefik.http.routers.minio.rule=Host(`minio.task.beetech.dev`)" - - "traefik.http.routers.minio.entrypoints=websecure" - - "traefik.http.routers.minio.tls.certresolver=letsencrypt" - - "traefik.http.services.minio.loadbalancer.server.port=9000" - - minio-init: - image: minio/mc:latest - depends_on: - - minio - restart: on-failure - entrypoint: > - /bin/sh -c " - sleep 3 && - mc alias set local http://minio:9000 $$MINIO_ROOT_USER $$MINIO_ROOT_PASSWORD && - mc mb --ignore-existing local/avatars && - mc anonymous set download local/avatars - " - environment: - MINIO_ROOT_USER: ${MINIO_ROOT_USER} - MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} - -volumes: - postgres_data: - minio_data: diff --git a/docker-compose.yml b/docker-compose.yml index 52f6024..03e7cad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,42 +3,49 @@ services: image: postgres:16 container_name: bee-task-postgres restart: unless-stopped - environment: POSTGRES_USER: beetask POSTGRES_PASSWORD: beetask POSTGRES_DB: beetask - ports: - - "5432:5432" - + - "5434:5432" volumes: - postgres_data:/var/lib/postgresql/data - healthcheck: test: ["CMD-SHELL", "pg_isready -U beetask"] interval: 10s timeout: 5s retries: 5 + networks: + - internal minio: - image: minio/minio:latest + image: pgsty/minio:latest restart: unless-stopped command: server /data --console-address ":9001" - environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:-beetask123} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-beetaskpassword} - ports: - "9000:9000" - "9001:9001" - volumes: - minio_data:/data + networks: + - proxy + - internal + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.minio.rule=Host(`minio.task2.beetech.dev`)" + - "traefik.http.routers.minio.entrypoints=web" + - "traefik.http.services.minio.loadbalancer.server.port=9000" + - "traefik.http.routers.minio-console.rule=Host(`console.minio.task2.beetech.dev`)" + - "traefik.http.routers.minio-console.entrypoints=web" + - "traefik.http.services.minio-console.loadbalancer.server.port=9001" minio-init: - image: minio/mc:latest + image: pgsty/mc:latest depends_on: - minio restart: on-failure @@ -52,7 +59,71 @@ services: mc mb --ignore-existing local/avatars && mc anonymous set download local/avatars " + networks: + - internal + + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: bee-task-backend + restart: unless-stopped + expose: + - "8081" + environment: + DB_USER: beetask + DB_PASSWORD: beetask + DB_URL: jdbc:postgresql://postgres:5432/beetask + QUARKUS_HTTP_CORS_ORIGINS: https://task2.beetech.dev + MP_JWT_VERIFY_ISSUER: ${MP_JWT_VERIFY_ISSUER} + SMALLRYE_JWT_SIGN_KEY: ${SMALLRYE_JWT_SIGN_KEY} + MP_JWT_VERIFY_PUBLICKEY: ${MP_JWT_VERIFY_PUBLICKEY} + MINIO_ENDPOINT: http://minio:9000 + MINIO_ACCESS_KEY: ${MINIO_ROOT_USER:-beetask123} + MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-beetaskpassword} + MINIO_BUCKET: avatars + MINIO_PUBLIC_URL: http://localhost:9000 + depends_on: + postgres: + condition: service_healthy + networks: + - proxy + - internal + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.backend.rule=Host(`api.task2.beetech.dev`)" + - "traefik.http.routers.backend.entrypoints=web" + - "traefik.http.services.backend.loadbalancer.server.port=8081" + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + args: + VITE_API_URL: ${VITE_API_URL:-https://api.task2.beetech.dev} + container_name: bee-task-frontend + restart: unless-stopped + expose: + - "80" + depends_on: + - backend + networks: + - proxy + - internal + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.frontend.rule=Host(`task2.beetech.dev`)" + - "traefik.http.routers.frontend.entrypoints=web" + - "traefik.http.services.frontend.loadbalancer.server.port=80" volumes: postgres_data: minio_data: + +networks: + proxy: + external: true + internal: + driver: bridge diff --git a/frontend/.env.production b/frontend/.env.production index 28aacea..7224450 100644 --- a/frontend/.env.production +++ b/frontend/.env.production @@ -1 +1 @@ -VITE_API_URL=https://api.task.beetech.dev +VITE_API_URL=https://api.task2.beetech.dev