diff --git a/.env.example b/.env.example index 802baf1..ca94060 100644 --- a/.env.example +++ b/.env.example @@ -58,7 +58,3 @@ INIT_ADMIN_PASSWORD=ChangeMe123! # ------------------------------ # Host port mapped to frontend container port 80. FRONTEND_PORT=5173 -# Base API URL used at frontend build time. -# For reverse proxy + SSL, keep this relative to avoid mixed-content issues. -# Example direct mode: VITE_API_URL=http://localhost:8000/api/v1 -VITE_API_URL=/api/v1 diff --git a/Makefile b/Makefile index 524bdc9..c2dc3a0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ .PHONY: up down logs migrate up: - docker compose up -d --build + docker compose pull + docker compose up -d down: docker compose down diff --git a/README.md b/README.md index 6670faf..6b2d6e5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ It combines FastAPI, React, and PostgreSQL in a Docker Compose stack with RBAC, ## Table of Contents -- [Quick Start](#quick-start) +- [Quick Deploy (Prebuilt Images)](#quick-deploy-prebuilt-images) - [Prerequisites](#prerequisites) - [Make Commands](#make-commands) - [Configuration Reference (`.env`)](#configuration-reference-env) @@ -93,27 +93,50 @@ Optional: - `psql` for manual DB checks -## Quick Start +## Quick Deploy (Prebuilt Images) -1. Copy environment template: +If you only want to run NexaPG from published Docker Hub images, use the bootstrap script: ```bash -cp .env.example .env +mkdir -p /opt/NexaPG +cd /opt/NexaPG +wget -O bootstrap-compose.sh https://git.nesterovic.cc/nessi/NexaPG/raw/branch/main/ops/scripts/bootstrap-compose.sh +chmod +x bootstrap-compose.sh +./bootstrap-compose.sh ``` -2. Generate a Fernet key and set `ENCRYPTION_KEY` in `.env`: +This downloads: + +- `docker-compose.yml` +- `.env.example` +- `Makefile` + +Then: ```bash +# generate JWT secret +python -c "import secrets; print(secrets.token_urlsafe(64))" +# generate Fernet encryption key python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" -``` - -3. Start the stack: - -```bash +# put both values into .env (JWT_SECRET_KEY / ENCRYPTION_KEY) +# note: .env is auto-created by bootstrap if it does not exist make up ``` -4. Open the application: +Manual download alternative: + +```bash +mkdir -p /opt/NexaPG +cd /opt/NexaPG +wget https://git.nesterovic.cc/nessi/NexaPG/raw/branch/main/docker-compose.yml +wget https://git.nesterovic.cc/nessi/NexaPG/raw/branch/main/.env.example +wget https://git.nesterovic.cc/nessi/NexaPG/raw/branch/main/Makefile +cp .env.example .env +``` + +`make up` pulls `nesterovicit/nexapg-backend:latest` and `nesterovicit/nexapg-frontend:latest`, then starts the stack. + +Open the application: - Frontend: `http://:` - API base: `http://:/api/v1` @@ -127,7 +150,7 @@ Initial admin bootstrap user (created from `.env` if missing): ## Make Commands ```bash -make up # build and start all services +make up # pull latest images and start all services make down # stop all services make logs # follow compose logs make migrate # optional/manual: run alembic upgrade head in backend container @@ -183,12 +206,6 @@ Note: Migrations run automatically when the backend container starts (`entrypoin | Variable | Description | |---|---| | `FRONTEND_PORT` | Host port mapped to frontend container port `80` | -| `VITE_API_URL` | Frontend API base URL (build-time) | - -Recommended values for `VITE_API_URL`: - -- Reverse proxy setup: `/api/v1` -- Direct backend access: `http://:/api/v1` ## Core Functional Areas @@ -318,7 +335,7 @@ For production, serve frontend and API under the same public origin via reverse - Frontend URL example: `https://monitor.example.com` - Proxy API path `/api/` to backend service -- Use `VITE_API_URL=/api/v1` +- Route `/api/v1` to the backend service This prevents mixed-content and CORS issues. @@ -351,8 +368,7 @@ docker compose logs --tail=200 db ### CORS or mixed-content issues behind SSL proxy -- Set `VITE_API_URL=/api/v1` -- Ensure proxy forwards `/api/` to backend +- Ensure proxy forwards `/api/` (or `/api/v1`) to backend - Set correct frontend origin(s) in `CORS_ORIGINS` ### `rejected SSL upgrade` for a target diff --git a/docker-compose.yml b/docker-compose.yml index 05bb7db..09a1079 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,8 +18,8 @@ services: retries: 10 backend: - build: - context: ./backend + image: nesterovicit/nexapg-backend:latest + pull_policy: always container_name: nexapg-backend restart: unless-stopped environment: @@ -47,10 +47,8 @@ services: - "${BACKEND_PORT}:8000" frontend: - build: - context: ./frontend - args: - VITE_API_URL: ${VITE_API_URL} + image: nesterovicit/nexapg-frontend:latest + pull_policy: always container_name: nexapg-frontend restart: unless-stopped depends_on: diff --git a/ops/scripts/bootstrap-compose.sh b/ops/scripts/bootstrap-compose.sh new file mode 100644 index 0000000..e7ac78e --- /dev/null +++ b/ops/scripts/bootstrap-compose.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: +# bash bootstrap-compose.sh +# BASE_URL="https://git.nesterovic.cc/nessi/NexaPG/raw/branch/main" bash bootstrap-compose.sh + +BASE_URL="${BASE_URL:-https://git.nesterovic.cc/nessi/NexaPG/raw/branch/main}" + +echo "[bootstrap] Using base URL: ${BASE_URL}" + +fetch_file() { + local path="$1" + local out="$2" + + if command -v wget >/dev/null 2>&1; then + wget -q -O "${out}" "${BASE_URL}/${path}" + elif command -v curl >/dev/null 2>&1; then + curl -fsSL "${BASE_URL}/${path}" -o "${out}" + else + echo "[bootstrap] ERROR: wget or curl is required" + exit 1 + fi +} + +fetch_file "docker-compose.yml" "docker-compose.yml" +fetch_file ".env.example" ".env.example" +fetch_file "Makefile" "Makefile" + +if [[ ! -f ".env" ]]; then + cp .env.example .env + echo "[bootstrap] Created .env from .env.example" +else + echo "[bootstrap] .env already exists, keeping it" +fi + +echo +echo "[bootstrap] Next steps:" +echo " 1) Edit .env (set JWT_SECRET_KEY and ENCRYPTION_KEY at minimum)" +echo " 2) Run: make up" +echo