diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 00000000..aa24ed09 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,79 @@ +name: Publish Docker Image + +on: + push: + branches: [main] + tags: ["v*"] + +permissions: + contents: read + packages: write + +concurrency: + group: docker-publish-${{ github.ref }} + cancel-in-progress: true + +jobs: + docker: + name: Build & Push Docker Image + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + # ── 1. Checkout (needed for path context so .dockerignore is respected) ── + - name: Checkout + uses: actions/checkout@v4 + + # ── 2. Multi-platform support ─────────────────────────────────────────── + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + # ── 3. Registry authentication ───────────────────────────────────────── + - name: Log in to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Docker Hub + if: vars.DOCKERHUB_USERNAME != '' + uses: docker/login-action@v4 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # ── 4. Tag & label generation ────────────────────────────────────────── + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: | + ghcr.io/${{ github.repository }} + name=reqcore/reqcore,enable=${{ vars.DOCKERHUB_USERNAME != '' }} + tags: | + type=edge,branch=main + type=raw,value=latest,enable={{is_default_branch}} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix=sha- + + # ── 5. Build & push ──────────────────────────────────────────────────── + - name: Build and push + uses: docker/build-push-action@v7 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + annotations: ${{ steps.meta.outputs.annotations }} + cache-from: type=gha + cache-to: type=gha,mode=max + provenance: mode=max + sbom: true + env: + DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index diff --git a/README.md b/README.md index 1400308d..12ccb548 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ [![E2E Tests](https://github.com/reqcore-inc/reqcore/actions/workflows/e2e-tests.yml/badge.svg)](https://github.com/reqcore-inc/reqcore/actions/workflows/e2e-tests.yml) [![PR Validation](https://github.com/reqcore-inc/reqcore/actions/workflows/pr-validation.yml/badge.svg)](https://github.com/reqcore-inc/reqcore/actions/workflows/pr-validation.yml) [![Docker Integration](https://github.com/reqcore-inc/reqcore/actions/workflows/docker-readme-validation.yml/badge.svg)](https://github.com/reqcore-inc/reqcore/actions/workflows/docker-readme-validation.yml) +[![Docker Image](https://ghcr-badge.egpl.dev/reqcore-inc/reqcore/latest_tag?trim=major&label=docker)](https://github.com/reqcore-inc/reqcore/pkgs/container/reqcore) [Live Demo](https://reqcore.com) · [Documentation](ARCHITECTURE.md) · [Roadmap](ROADMAP.md) · [Report Bug](https://github.com/reqcore-inc/reqcore/issues/new) @@ -62,6 +63,29 @@ Hiring software shouldn't be complicated or expensive. Most applicant tracking s --- +### Option A — Use the pre-built image (fastest) + +No cloning, no building. Pull the official image and run: + +```bash +mkdir reqcore && cd reqcore +curl -fsSLO https://raw.githubusercontent.com/reqcore-inc/reqcore/main/docker-compose.production.yml +curl -fsSLO https://raw.githubusercontent.com/reqcore-inc/reqcore/main/setup.sh +chmod +x setup.sh +./setup.sh +docker compose -f docker-compose.production.yml up -d +``` + +Open **[http://localhost:3000](http://localhost:3000)** and sign up. That's it. + +To update: `docker compose -f docker-compose.production.yml pull app && docker compose -f docker-compose.production.yml up -d` + +--- + +### Option B — Build from source + +--- + ### Step 1 — Install Docker Docker packages the app, database, and file storage into containers so you don't have to install anything else manually. @@ -153,6 +177,15 @@ Then sign in with: When a new version of Reqcore is released, follow these steps **in order** to update your instance. Your data is safe — updates never delete the database or your uploaded files. +#### Pre-built image users + +```bash +docker compose -f docker-compose.production.yml pull app +docker compose -f docker-compose.production.yml up -d +``` + +#### Build from source users + **Step 1 — Pull the latest code** ```bash diff --git a/SELF-HOSTING.md b/SELF-HOSTING.md index 1f0f8a96..50813f30 100644 --- a/SELF-HOSTING.md +++ b/SELF-HOSTING.md @@ -9,16 +9,17 @@ Everything you need to deploy, manage, and update your own Reqcore applicant tra 1. [What is Self-Hosting?](#what-is-self-hosting) 2. [Why Self-Host Reqcore?](#why-self-host-reqcore) 3. [Requirements](#requirements) -4. [Quick Start (5 Minutes)](#quick-start-5-minutes) -5. [Step-by-Step Installation](#step-by-step-installation) -6. [Updating Your Instance](#updating-your-instance) -7. [Backups & Data Safety](#backups--data-safety) -8. [Custom Domain & HTTPS](#custom-domain--https) -9. [Email Configuration](#email-configuration) -10. [Security Best Practices](#security-best-practices) -11. [Monitoring & Health Checks](#monitoring--health-checks) -12. [Troubleshooting](#troubleshooting) -13. [FAQ](#faq) +4. [Quick Start — Pre-built Image (Fastest)](#quick-start--pre-built-image-fastest) +5. [Quick Start — Build from Source (5 Minutes)](#quick-start--build-from-source-5-minutes) +6. [Step-by-Step Installation](#step-by-step-installation) +7. [Updating Your Instance](#updating-your-instance) +8. [Backups & Data Safety](#backups--data-safety) +9. [Custom Domain & HTTPS](#custom-domain--https) +10. [Email Configuration](#email-configuration) +11. [Security Best Practices](#security-best-practices) +12. [Monitoring & Health Checks](#monitoring--health-checks) +13. [Troubleshooting](#troubleshooting) +14. [FAQ](#faq) --- @@ -79,9 +80,41 @@ All of these providers offer one-click Docker installation when creating a serve --- -## Quick Start (5 Minutes) +## Quick Start — Pre-built Image (Fastest) -If you have Docker already installed and just want to get running: +Use the official pre-built Docker image from GitHub Container Registry. No cloning, no building — just pull and run: + +```bash +# 1. Download just the files you need +mkdir reqcore && cd reqcore +curl -fsSLO https://raw.githubusercontent.com/reqcore-inc/reqcore/main/docker-compose.production.yml +curl -fsSLO https://raw.githubusercontent.com/reqcore-inc/reqcore/main/setup.sh +chmod +x setup.sh + +# 2. Generate secure passwords (one-time) +./setup.sh + +# 3. Start everything +docker compose -f docker-compose.production.yml up -d + +# 4. Open your browser +# → http://localhost:3000 +``` + +That's it. Sign up, create your organization, and start hiring. + +**Want to pin a specific version?** Edit `docker-compose.production.yml` and replace `latest` with a version tag (e.g., `1.3.0`): + +```yaml +app: + image: ghcr.io/reqcore-inc/reqcore:1.3.0 +``` + +--- + +## Quick Start — Build from Source (5 Minutes) + +If you prefer to build from source (useful for development or customization): ```bash # 1. Download Reqcore @@ -98,7 +131,7 @@ docker compose up -d # → http://localhost:3000 ``` -That's it. Sign up, create your organization, and start hiring. +Sign up, create your organization, and start hiring. **Want demo data to explore first?** @@ -217,9 +250,31 @@ Reqcore includes a built-in update system accessible from the Settings panel. No The UI shows the progress of each update step and clearly indicates success or failure. Your data is always preserved — database migrations run automatically. -### Method 2: Update from the Command Line +### Method 2: Update from the Command Line (Pre-built Image) + +If you're using the pre-built image (`docker-compose.production.yml`): + +```bash +# Navigate to your Reqcore directory +cd /path/to/reqcore + +# Pull the latest image and restart +docker compose -f docker-compose.production.yml pull app +docker compose -f docker-compose.production.yml up -d +``` + +To update to a specific version, edit `docker-compose.production.yml` and change the image tag: + +```yaml +app: + image: ghcr.io/reqcore-inc/reqcore:1.4.0 +``` + +Then run `docker compose -f docker-compose.production.yml up -d`. + +### Method 3: Update from the Command Line (Build from Source) -If you prefer using the terminal, or the UI update isn't available: +If you cloned the repository and build locally: ```bash # Navigate to your Reqcore directory diff --git a/docker-compose.production.yml b/docker-compose.production.yml new file mode 100644 index 00000000..ef1c25a4 --- /dev/null +++ b/docker-compose.production.yml @@ -0,0 +1,84 @@ +# docker-compose.production.yml +# +# Use this file to run Reqcore with the official pre-built Docker image +# instead of building from source. No git clone or local build required. +# +# Quick start: +# 1. Download this file and setup.sh from the repository +# 2. Run: ./setup.sh +# 3. Run: docker compose -f docker-compose.production.yml up -d +# 4. Open: http://localhost:3000 + +services: + db: + image: postgres:16-alpine + container_name: reqcore_db + restart: unless-stopped + environment: + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: ${DB_NAME} + ports: + - "127.0.0.1:5432:5432" # Postgres — localhost only, never expose publicly + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"] + interval: 5s + timeout: 5s + retries: 10 + + minio: + image: minio/minio + container_name: reqcore_minio + restart: unless-stopped + ports: + - "127.0.0.1:9000:9000" # S3 API — localhost only, never expose publicly + - "127.0.0.1:9001:9001" # MinIO Console → http://localhost:9001 + environment: + MINIO_ROOT_USER: ${STORAGE_USER} + MINIO_ROOT_PASSWORD: ${STORAGE_PASSWORD} + command: server /data --console-address ":9001" + volumes: + - minio_data:/data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 5s + timeout: 5s + retries: 10 + + app: + image: ghcr.io/reqcore-inc/reqcore:latest + container_name: reqcore_app + restart: unless-stopped + env_file: .env + environment: + # Override localhost URLs with Docker-internal hostnames + DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME} + S3_ENDPOINT: http://minio:9000 + ports: + - "3000:3000" + depends_on: + db: + condition: service_healthy + minio: + condition: service_healthy + volumes: + - backups_data:/data/backups + + # Optional DB browser — run with: docker compose -f docker-compose.production.yml --profile tools up + adminer: + image: adminer + container_name: reqcore_adminer + restart: unless-stopped + profiles: [tools] + ports: + - "127.0.0.1:8080:8080" # Adminer → http://localhost:8080 + depends_on: + db: + condition: service_healthy + +volumes: + postgres_data: + minio_data: + backups_data: