diff --git a/.env.example b/.env.example index 2f13b1b8..7e48dd4f 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,20 @@ POSTGRES_USER=yakpanel POSTGRES_PASSWORD=yakpanel_dev_password POSTGRES_DB=yakpanel -POSTGRES_PORT=5432 +# Host port (container still uses 5432). 15432 avoids clashes with local PostgreSQL. +POSTGRES_PORT=15432 -REDIS_PORT=6379 +# Host port (container still uses 6379). 16379 avoids clashes with local Redis. +REDIS_PORT=16379 -NATS_PORT=4222 -NATS_MONITOR_PORT=8222 +# Host ports for NATS (14222/18222 avoid common local installs). +NATS_PORT=14222 +NATS_MONITOR_PORT=18222 MINIO_ROOT_USER=yakpanel MINIO_ROOT_PASSWORD=yakpanel_minio_password -MINIO_PORT=9000 -MINIO_CONSOLE_PORT=9001 +MINIO_PORT=19000 +MINIO_CONSOLE_PORT=19001 -API_PORT=8080 +# Host port for API (container still uses 8080). +API_PORT=18080 diff --git a/Makefile b/Makefile index 390248ec..3aab1817 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ COMPOSE := bash scripts/docker-compose.sh init: cp -n .env.example .env || true + bash scripts/ensure-env-ports.sh @echo "Initialized .env (kept existing values if present)" up: diff --git a/docs/ubuntu-dev-install.md b/docs/ubuntu-dev-install.md index 334ba942..72fd47ad 100644 --- a/docs/ubuntu-dev-install.md +++ b/docs/ubuntu-dev-install.md @@ -37,11 +37,13 @@ make down ``` ## Services -- API health: `http://localhost:8080/health` -- PostgreSQL: `localhost:5432` -- Redis: `localhost:6379` -- NATS monitor: `http://localhost:8222` -- MinIO console: `http://localhost:9001` +Host ports are defined in `.env` (see `.env.example`). Defaults avoid common conflicts: + +- 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`) ## Troubleshooting @@ -61,6 +63,18 @@ or log out and SSH in again, then: bash scripts/docker-compose.sh up -d --build ``` +### `failed to bind host port ... address already in use` + +Another service on the host is using the same published port. Run: + +```bash +bash scripts/ensure-env-ports.sh +bash scripts/docker-compose.sh down +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. diff --git a/one-click-installer.sh b/one-click-installer.sh index 93cdb704..a4ea8675 100644 --- a/one-click-installer.sh +++ b/one-click-installer.sh @@ -20,6 +20,8 @@ ensure_executable_scripts() { chmod +x "${PROJECT_DIR}/scripts/install-ubuntu.sh" chmod +x "${PROJECT_DIR}/scripts/bootstrap-dev.sh" chmod +x "${PROJECT_DIR}/scripts/migrate-dev.sh" + chmod +x "${PROJECT_DIR}/scripts/ensure-env-ports.sh" + chmod +x "${PROJECT_DIR}/scripts/docker-compose.sh" } main() { @@ -33,9 +35,13 @@ main() { echo echo "YakPanel installation completed." - echo "API health: http://localhost:8080/health" - echo "MinIO console: http://localhost:9001" - echo "NATS monitor: http://localhost:8222" + 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 "MinIO console: http://localhost:$(dotenv_get MINIO_CONSOLE_PORT)" + echo "NATS monitor: http://localhost:$(dotenv_get NATS_MONITOR_PORT)" + echo "(All host ports are in .env; defaults avoid PostgreSQL/Redis on 5432/6379.)" + fi } main "$@" diff --git a/scripts/bootstrap-dev.sh b/scripts/bootstrap-dev.sh index f770bcfb..34be0545 100644 --- a/scripts/bootstrap-dev.sh +++ b/scripts/bootstrap-dev.sh @@ -4,6 +4,7 @@ set -euo pipefail cd "$(dirname "$0")/.." cp -n .env.example .env || true +bash "$(dirname "$0")/ensure-env-ports.sh" bash "$(dirname "$0")/docker-compose.sh" up -d --build bash "$(dirname "$0")/docker-compose.sh" run --rm db-migrate bash "$(dirname "$0")/docker-compose.sh" ps diff --git a/scripts/docker-compose.sh b/scripts/docker-compose.sh index 9a8f70f4..5e639cad 100644 --- a/scripts/docker-compose.sh +++ b/scripts/docker-compose.sh @@ -9,6 +9,9 @@ cd "$ROOT" || exit 1 if [[ ! -f .env ]] && [[ -f .env.example ]]; then cp -n .env.example .env || true fi +if [[ -f .env ]]; then + bash "$(dirname "${BASH_SOURCE[0]}")/ensure-env-ports.sh" +fi run_docker_compose() { local -a compose_args=(--env-file .env -f docker-compose.yakpanel.yml) diff --git a/scripts/ensure-env-ports.sh b/scripts/ensure-env-ports.sh new file mode 100644 index 00000000..8f60aa40 --- /dev/null +++ b/scripts/ensure-env-ports.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# Remap host ports in .env when they are already bound (e.g. system Redis on 6379). +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +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. +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 + exit 0 + fi +fi + +port_listening() { + local port="$1" + if command -v ss >/dev/null 2>&1; then + ss -tuln 2>/dev/null | grep -qE ":${port}($|[[:space:]])" && return 0 + fi + if command -v netstat >/dev/null 2>&1; then + netstat -tuln 2>/dev/null | grep -qE ":${port}($|[[:space:]])" && return 0 + fi + return 1 +} + +get_kv() { + grep -E "^${1}=" "$ENV_FILE" 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '\r' +} + +set_kv() { + local key="$1" val="$2" + if grep -qE "^${key}=" "$ENV_FILE"; then + sed -i "s/^${key}=.*/${key}=${val}/" "$ENV_FILE" + else + echo "${key}=${val}" >> "$ENV_FILE" + fi +} + +find_free_port() { + local start="$1" + local end=$((start + 400)) + local p + for ((p = start; p <= end; p++)); do + if ! port_listening "$p"; then + echo "$p" + return 0 + fi + done + echo "$start" +} + +remap_key() { + local key="$1" + local preferred_alt="$2" + local p alt + p=$(get_kv "$key") + [[ -z "$p" ]] && return 0 + if ! port_listening "$p"; then + return 0 + fi + alt="$preferred_alt" + if port_listening "$alt"; then + alt=$(find_free_port "$preferred_alt") + fi + echo "[yakpanel] Host port ${p} (${key}) is already in use; set ${key}=${alt} in .env" + set_kv "$key" "$alt" +} + +remap_key REDIS_PORT 16379 +remap_key POSTGRES_PORT 15432 +remap_key API_PORT 18080 +remap_key NATS_PORT 14222 +remap_key NATS_MONITOR_PORT 18222 +remap_key MINIO_PORT 19000 +remap_key MINIO_CONSOLE_PORT 19001 diff --git a/scripts/install-ubuntu.sh b/scripts/install-ubuntu.sh index 8350d0af..135cca2f 100644 --- a/scripts/install-ubuntu.sh +++ b/scripts/install-ubuntu.sh @@ -32,6 +32,7 @@ sudo usermod -aG docker "$USER" echo "[5/6] Initializing YakPanel environment file..." cd "$(dirname "$0")/.." cp -n .env.example .env || true +bash "$(dirname "$0")/ensure-env-ports.sh" echo "[6/6] Starting YakPanel dev stack..." # Use scripts/docker-compose.sh so compose works in this shell even when docker group @@ -41,10 +42,17 @@ bash "$(dirname "$0")/docker-compose.sh" run --rm db-migrate echo echo "YakPanel dev stack started." -echo "API: http://localhost:8080/health" -echo "PostgreSQL: localhost:5432" -echo "Redis: localhost:6379" -echo "NATS monitor: http://localhost:8222" -echo "MinIO console: http://localhost:9001" +dotenv_get() { grep -E "^${1}=" .env 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '\r'; } +_API="$(dotenv_get API_PORT)" +_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" +echo "PostgreSQL: localhost:${_PG}" +echo "Redis: localhost:${_RD}" +echo "NATS monitor: http://localhost:${_NATS_MON}" +echo "MinIO console: http://localhost:${_MINIO_C}" +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." diff --git a/scripts/migrate-dev.sh b/scripts/migrate-dev.sh index 5195a824..2c32e745 100644 --- a/scripts/migrate-dev.sh +++ b/scripts/migrate-dev.sh @@ -6,6 +6,7 @@ cd "$(dirname "$0")/.." if [[ ! -f .env ]]; then cp .env.example .env fi +bash "$(dirname "$0")/ensure-env-ports.sh" bash "$(dirname "$0")/docker-compose.sh" run --rm db-migrate echo "YakPanel database migrations applied."