diff --git a/.github/workflows/publish_github_docker.yml b/.github/workflows/publish_github_docker.yml new file mode 100644 index 000000000..b971dfff1 --- /dev/null +++ b/.github/workflows/publish_github_docker.yml @@ -0,0 +1,136 @@ +name: Publish Chatwoot docker images to GitHub + +permissions: + contents: read + packages: write + +on: + push: + branches: + - fazer-ai/main + workflow_dispatch: + +env: + GITHUB_REPO: ghcr.io/${{ github.repository }} + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + runs-on: ${{ matrix.runner }} + env: + GIT_REF: ${{ github.head_ref || github.ref_name }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - name: Strip enterprise code + run: | + rm -rf enterprise + rm -rf spec/enterprise + + - name: Set Docker Tags + run: | + SANITIZED_REF=$(echo "$GIT_REF" | sed 's/\//-/g') + if [ "${{ github.ref_name }}" = "fazer-ai/main" ]; then + echo "GITHUB_TAG=${GITHUB_REPO}:latest" >> $GITHUB_ENV + else + echo "GITHUB_TAG=${GITHUB_REPO}:${SANITIZED_REF}" >> $GITHUB_ENV + fi + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push to GitHub Container Registry + id: build-ghcr + uses: docker/build-push-action@v6 + with: + context: . + file: docker/Dockerfile + platforms: ${{ matrix.platform }} + push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + outputs: type=image,name=${{ env.GITHUB_TAG }},name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build-ghcr.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Create manifest list and push + working-directory: ${{ runner.temp }}/digests + env: + GIT_REF: ${{ github.head_ref || github.ref_name }} + run: | + SANITIZED_REF=$(echo "$GIT_REF" | sed 's/\//-/g') + if [ "${{ github.ref_name }}" = "fazer-ai/main" ]; then + GITHUB_TAG="ghcr.io/${{ github.repository }}:latest" + else + GITHUB_TAG="ghcr.io/${{ github.repository }}:${SANITIZED_REF}" + fi + + docker buildx imagetools create -t $GITHUB_TAG \ + $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) + + - name: Inspect image + env: + GIT_REF: ${{ github.head_ref || github.ref_name }} + run: | + SANITIZED_REF=$(echo "$GIT_REF" | sed 's/\//-/g') + if [ "${{ github.ref_name }}" = "fazer-ai/main" ]; then + GITHUB_TAG="ghcr.io/${{ github.repository }}:latest" + else + GITHUB_TAG="ghcr.io/${{ github.repository }}:${SANITIZED_REF}" + fi + + docker buildx imagetools inspect $GITHUB_TAG diff --git a/docker-compose.coolify.yaml b/docker-compose.coolify.yaml new file mode 100644 index 000000000..d6024cde2 --- /dev/null +++ b/docker-compose.coolify.yaml @@ -0,0 +1,149 @@ +version: '3' + +services: + rails: + image: 'ghcr.io/fazer-ai/chatwoot:latest' + pull_policy: always + volumes: + - 'storage:/app/storage' + depends_on: + - postgres + - redis + environment: + - NODE_ENV=production + - RAILS_ENV=production + - INSTALLATION_ENV=docker + - FRONTEND_URL=http://rails:3000 + - REDIS_URL=redis://redis:6379 + - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/chatwoot_production + - SECRET_KEY_BASE=${SECRET_KEY_BASE} + - REDIS_PASSWORD=${REDIS_PASSWORD} + - BAILEYS_PROVIDER_DEFAULT_CLIENT_NAME=${BAILEYS_PROVIDER_DEFAULT_CLIENT_NAME} + - BAILEYS_PROVIDER_DEFAULT_URL=http://baileys-api:3025 + - BAILEYS_PROVIDER_DEFAULT_API_KEY=${BAILEYS_PROVIDER_DEFAULT_API_KEY} + entrypoint: docker/entrypoints/rails.sh + command: + - bundle + - exec + - rails + - s + - '-p' + - '3000' + - '-b' + - 0.0.0.0 + restart: always + post_start: + - command: + - bundle + - exec + - rails + - db:chatwoot_prepare + healthcheck: + test: + - CMD-SHELL + - 'wget -qO- http://127.0.0.1:3000/' + interval: 60s + timeout: 20s + retries: 10 + + sidekiq: + image: 'ghcr.io/fazer-ai/chatwoot:latest' + pull_policy: always + volumes: + - 'storage:/app/storage' + depends_on: + - postgres + - redis + environment: + - NODE_ENV=production + - RAILS_ENV=production + - INSTALLATION_ENV=docker + - REDIS_URL=redis://redis:6379 + - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/chatwoot_production + - SECRET_KEY_BASE=${SECRET_KEY_BASE} + - REDIS_PASSWORD=${REDIS_PASSWORD} + command: + - bundle + - exec + - sidekiq + - '-C' + - config/sidekiq.yml + restart: always + healthcheck: + test: + - CMD-SHELL + - 'ps aux | grep [s]idekiq' + interval: 20s + timeout: 20s + retries: 10 + + baileys-api: + image: 'ghcr.io/fazer-ai/baileys-api:latest' + pull_policy: always + volumes: + - 'storage:/app/storage' + depends_on: + - rails + - sidekiq + - redis + environment: + - NODE_ENV=production + - REDIS_URL=redis://redis:6379 + - REDIS_PASSWORD=${REDIS_PASSWORD} + - LOG_LEVEL=${LOG_LEVEL:-debug} + - BAILEYS_LOG_LEVEL=${BAILEYS_LOG_LEVEL:-error} + command: + - bun + - start + restart: always + post_start: + - command: + - bun + - manage-api-keys + - create + - user + - ${BAILEYS_PROVIDER_DEFAULT_API_KEY} + healthcheck: + test: + - CMD-SHELL + - "wget --header='x-api-key: ${BAILEYS_PROVIDER_DEFAULT_API_KEY}' -qO- http://localhost:3025/status" + interval: 20s + timeout: 20s + retries: 10 + + postgres: + image: 'pgvector/pgvector:pg16' + restart: always + volumes: + - 'postgres:/var/lib/postgresql/data' + environment: + - POSTGRES_DB=chatwoot_production + - POSTGRES_USERNAME=postgres + - POSTGRES_PASSWORD=postgres + healthcheck: + test: + - CMD-SHELL + - 'pg_isready -h localhost -p 5432 -U postgres' + interval: 20s + timeout: 20s + retries: 10 + + redis: + image: 'redis:alpine' + restart: always + command: + - sh + - '-c' + - 'redis-server --requirepass "$REDIS_PASSWORD"' + volumes: + - 'redis:/data' + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD} + healthcheck: + test: + - CMD-SHELL + - 'redis-cli -h localhost -p 6379 -a $REDIS_PASSWORD ping' + interval: 20s + timeout: 20s + retries: 10 +