diff --git a/.env.example b/.env.example index 7e48dd4f..98561ec3 100644 --- a/.env.example +++ b/.env.example @@ -16,5 +16,17 @@ MINIO_ROOT_PASSWORD=yakpanel_minio_password MINIO_PORT=19000 MINIO_CONSOLE_PORT=19001 -# Host port for API (container still uses 8080). +# Host port for API scaffold (container still uses 8080). API_PORT=18080 + +# Web control panel — React UI + FastAPI (nginx proxies /api -> backend) +PANEL_UI_PORT=3080 +# Optional: comma-separated origins for direct browser access to API +PANEL_CORS_EXTRA_ORIGINS= + +# Observability stack +PROMETHEUS_PORT=19090 +GRAFANA_PORT=13000 +GRAFANA_ADMIN_USER=admin +GRAFANA_ADMIN_PASSWORD=yakpanel_grafana_admin +CADVISOR_PORT=18081 diff --git a/README.md b/README.md index 995ddfcd..1288a31b 100644 --- a/README.md +++ b/README.md @@ -121,3 +121,5 @@ make ps Reference: `docs/ubuntu-dev-install.md` +The **full web control panel** (sites, files, SSL, Docker, monitor, etc.) is the `YakPanel-server` stack: after `make up`, open `http://localhost:3080/` unless you changed `PANEL_UI_PORT` in `.env`. Default login: `admin` / `admin`. Observability is included: Prometheus (`PROMETHEUS_PORT`) and Grafana (`GRAFANA_PORT`). + diff --git a/YakPanel-server/frontend/nginx.conf b/YakPanel-server/frontend/nginx.conf index 538601a8..98678b8e 100644 --- a/YakPanel-server/frontend/nginx.conf +++ b/YakPanel-server/frontend/nginx.conf @@ -12,5 +12,8 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 86400; } } diff --git a/deploy/grafana/provisioning/datasources/prometheus.yml b/deploy/grafana/provisioning/datasources/prometheus.yml new file mode 100644 index 00000000..1a57b69c --- /dev/null +++ b/deploy/grafana/provisioning/datasources/prometheus.yml @@ -0,0 +1,9 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + editable: true diff --git a/deploy/prometheus/prometheus.yml b/deploy/prometheus/prometheus.yml new file mode 100644 index 00000000..cac3b666 --- /dev/null +++ b/deploy/prometheus/prometheus.yml @@ -0,0 +1,12 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: prometheus + static_configs: + - targets: ['prometheus:9090'] + + - job_name: cadvisor + static_configs: + - targets: ['cadvisor:8080'] diff --git a/docker-compose.yakpanel.yml b/docker-compose.yakpanel.yml index 8c6c636d..2d4e9f6a 100644 --- a/docker-compose.yakpanel.yml +++ b/docker-compose.yakpanel.yml @@ -55,6 +55,73 @@ services: volumes: - yakpanel_minio_data:/data + # Full web control panel: FastAPI (service hostname "backend" for nginx upstream) + backend: + build: ./YakPanel-server/backend + container_name: yakpanel-panel-api + restart: unless-stopped + command: + [ + "sh", + "-lc", + "python scripts/seed_admin.py && exec uvicorn app.main:app --host 0.0.0.0 --port 8888", + ] + volumes: + - ./YakPanel-server/backend:/app + - yakpanel_panel_data:/app/data + environment: + REDIS_URL: redis://redis:6379/0 + DATABASE_URL: sqlite+aiosqlite:///./data/default.db + CORS_EXTRA_ORIGINS: ${PANEL_CORS_EXTRA_ORIGINS:-} + depends_on: + redis: + condition: service_healthy + + panel-worker: + build: ./YakPanel-server/backend + container_name: yakpanel-panel-worker + restart: unless-stopped + command: ["celery", "-A", "app.tasks.celery_app", "worker", "-l", "info"] + volumes: + - ./YakPanel-server/backend:/app + - yakpanel_panel_data:/app/data + environment: + REDIS_URL: redis://redis:6379/0 + DATABASE_URL: sqlite+aiosqlite:///./data/default.db + depends_on: + redis: + condition: service_healthy + backend: + condition: service_started + + panel-scheduler: + build: ./YakPanel-server/backend + container_name: yakpanel-panel-scheduler + restart: unless-stopped + command: ["celery", "-A", "app.tasks.celery_app", "beat", "-l", "info"] + volumes: + - ./YakPanel-server/backend:/app + - yakpanel_panel_data:/app/data + environment: + REDIS_URL: redis://redis:6379/0 + DATABASE_URL: sqlite+aiosqlite:///./data/default.db + depends_on: + redis: + condition: service_healthy + backend: + condition: service_started + + panel-ui: + build: + context: ./YakPanel-server/frontend + dockerfile: Dockerfile + container_name: yakpanel-panel-frontend + restart: unless-stopped + ports: + - "${PANEL_UI_PORT}:80" + depends_on: + - backend + api: image: php:8.3-cli-alpine container_name: yakpanel-api @@ -85,6 +152,50 @@ services: redis: condition: service_healthy + prometheus: + image: prom/prometheus:latest + container_name: yakpanel-prometheus + restart: unless-stopped + command: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus + volumes: + - ./deploy/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - yakpanel_prometheus_data:/prometheus + ports: + - "${PROMETHEUS_PORT}:9090" + depends_on: + - cadvisor + + grafana: + image: grafana/grafana:latest + container_name: yakpanel-grafana + restart: unless-stopped + environment: + GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER} + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD} + GF_USERS_ALLOW_SIGN_UP: "false" + volumes: + - yakpanel_grafana_data:/var/lib/grafana + - ./deploy/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources:ro + ports: + - "${GRAFANA_PORT}:3000" + depends_on: + - prometheus + + cadvisor: + image: gcr.io/cadvisor/cadvisor:latest + container_name: yakpanel-cadvisor + restart: unless-stopped + privileged: true + ports: + - "${CADVISOR_PORT}:8080" + volumes: + - /:/rootfs:ro + - /var/run:/var/run:rw + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + db-migrate: image: postgres:16-alpine container_name: yakpanel-db-migrate @@ -108,3 +219,6 @@ volumes: yakpanel_postgres_data: yakpanel_redis_data: yakpanel_minio_data: + yakpanel_panel_data: + yakpanel_prometheus_data: + yakpanel_grafana_data: diff --git a/docs/ubuntu-dev-install.md b/docs/ubuntu-dev-install.md index 72fd47ad..a42386f0 100644 --- a/docs/ubuntu-dev-install.md +++ b/docs/ubuntu-dev-install.md @@ -1,6 +1,6 @@ # YakPanel Ubuntu Dev Install -This setup brings up the YakPanel 2026 scaffold stack on Ubuntu 22.04/24.04. +This setup brings up the YakPanel 2026 stack on Ubuntu 22.04/24.04. ## Clone the repository @@ -39,11 +39,16 @@ make down ## Services Host ports are defined in `.env` (see `.env.example`). Defaults avoid common conflicts: -- API health: `http://localhost:18080/health` (`API_PORT`) +- **Web control panel (full UI):** `http://localhost:3080/` (`PANEL_UI_PORT`) — default login `admin` / `admin` (change immediately). API is proxied at `/api`. +- Laravel scaffold API health: `http://localhost:18080/health` (`API_PORT`) - PostgreSQL: `localhost:15432` (`POSTGRES_PORT`) - Redis: `localhost:16379` (`REDIS_PORT`) - NATS monitor: `http://localhost:18222` (`NATS_MONITOR_PORT`) - MinIO console: `http://localhost:19001` (`MINIO_CONSOLE_PORT`) +- Prometheus: `http://localhost:19090` (`PROMETHEUS_PORT`) +- Grafana: `http://localhost:13000` (`GRAFANA_PORT`) + +First boot builds Docker images for `YakPanel-server` (backend + frontend); this can take several minutes. ## Troubleshooting @@ -76,7 +81,5 @@ bash scripts/docker-compose.sh up -d --build Or edit `.env` manually (raise `REDIS_PORT`, `POSTGRES_PORT`, etc.). ## Notes -- This is a development scaffold for the architecture implementation. -- `panel-api` currently serves a minimal runtime entrypoint for health and bootstrap validation. -- Full Laravel production bootstrap (artisan app, providers, migrations runtime wiring) is the next implementation step. +- This is a development-first integrated stack with a real control panel UI and supporting services. - Database schema is automatically applied by `db-migrate` during bootstrap and can be re-run with `make migrate`. diff --git a/one-click-installer.sh b/one-click-installer.sh index a4ea8675..26b57af8 100644 --- a/one-click-installer.sh +++ b/one-click-installer.sh @@ -37,9 +37,12 @@ main() { echo "YakPanel installation completed." dotenv_get() { grep -E "^${1}=" "${PROJECT_DIR}/.env" 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '\r'; } if [[ -f "${PROJECT_DIR}/.env" ]]; then - echo "API health: http://localhost:$(dotenv_get API_PORT)/health" + echo "Web control panel: http://localhost:$(dotenv_get PANEL_UI_PORT)/ (admin / admin)" + echo "API health (scaffold): http://localhost:$(dotenv_get API_PORT)/health" echo "MinIO console: http://localhost:$(dotenv_get MINIO_CONSOLE_PORT)" echo "NATS monitor: http://localhost:$(dotenv_get NATS_MONITOR_PORT)" + echo "Prometheus: http://localhost:$(dotenv_get PROMETHEUS_PORT)" + echo "Grafana: http://localhost:$(dotenv_get GRAFANA_PORT)" echo "(All host ports are in .env; defaults avoid PostgreSQL/Redis on 5432/6379.)" fi } diff --git a/scripts/ensure-env-ports.sh b/scripts/ensure-env-ports.sh index 8f60aa40..a7b6467b 100644 --- a/scripts/ensure-env-ports.sh +++ b/scripts/ensure-env-ports.sh @@ -7,10 +7,25 @@ ENV_FILE="${ROOT}/.env" [[ -f "$ENV_FILE" ]] || exit 0 -# Do not rewrite .env while the dev stack is already running: published ports would -# appear "in use" but belong to our own containers. +# Add new keys when .env was created before panel-ui/observability existed. +add_key_if_missing() { + local key="$1" value="$2" + if ! grep -qE "^${key}=" "$ENV_FILE"; then + echo "${key}=${value}" >> "$ENV_FILE" + fi +} + +add_key_if_missing PANEL_UI_PORT 3080 +add_key_if_missing PANEL_CORS_EXTRA_ORIGINS "" +add_key_if_missing PROMETHEUS_PORT 19090 +add_key_if_missing GRAFANA_PORT 13000 +add_key_if_missing GRAFANA_ADMIN_USER admin +add_key_if_missing GRAFANA_ADMIN_PASSWORD yakpanel_grafana_admin +add_key_if_missing CADVISOR_PORT 18081 + +# Do not rewrite .env while our stack is already running. if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then - if docker ps --format '{{.Names}}' 2>/dev/null | grep -qE '^yakpanel-(redis|postgres|api|nats|minio|agent-gateway)$'; then + if docker ps --format '{{.Names}}' 2>/dev/null | grep -qE '^yakpanel-(redis|postgres|api|nats|minio|agent-gateway|panel-api|panel-worker|panel-scheduler|panel-frontend|prometheus|grafana|cadvisor)$'; then exit 0 fi fi @@ -76,3 +91,7 @@ remap_key NATS_PORT 14222 remap_key NATS_MONITOR_PORT 18222 remap_key MINIO_PORT 19000 remap_key MINIO_CONSOLE_PORT 19001 +remap_key PANEL_UI_PORT 13080 +remap_key PROMETHEUS_PORT 19090 +remap_key GRAFANA_PORT 13000 +remap_key CADVISOR_PORT 18081 diff --git a/scripts/install-ubuntu.sh b/scripts/install-ubuntu.sh index 135cca2f..a8b712ca 100644 --- a/scripts/install-ubuntu.sh +++ b/scripts/install-ubuntu.sh @@ -48,11 +48,19 @@ _PG="$(dotenv_get POSTGRES_PORT)" _RD="$(dotenv_get REDIS_PORT)" _NATS_MON="$(dotenv_get NATS_MONITOR_PORT)" _MINIO_C="$(dotenv_get MINIO_CONSOLE_PORT)" -echo "API: http://localhost:${_API}/health" +_PANEL="$(dotenv_get PANEL_UI_PORT)" +_PROM="$(dotenv_get PROMETHEUS_PORT)" +_GRAF="$(dotenv_get GRAFANA_PORT)" + +echo "Web control panel: http://localhost:${_PANEL}/ (login: admin / admin — change after first sign-in)" +echo "API (scaffold): http://localhost:${_API}/health" +echo "Panel API (proxied): http://localhost:${_PANEL}/api/health" echo "PostgreSQL: localhost:${_PG}" echo "Redis: localhost:${_RD}" echo "NATS monitor: http://localhost:${_NATS_MON}" echo "MinIO console: http://localhost:${_MINIO_C}" +echo "Prometheus: http://localhost:${_PROM}" +echo "Grafana: http://localhost:${_GRAF} (admin user from .env)" echo "(Ports come from .env; defaults avoid system PostgreSQL/Redis on 5432/6379.)" echo echo "Docker group is configured; if a future terminal still cannot run docker, log out and back in once."