Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:26:06 +05:30
parent 2826d3e7f3
commit 38568a474b
5 changed files with 44 additions and 17 deletions

View File

@@ -49,7 +49,7 @@ All native installs require **root**. Use `sudo -E ...` when you set environment
| Variable | Meaning | Default | | Variable | Meaning | Default |
| --- | --- | --- | | --- | --- | --- |
| `REPO_URL` | Git URL to clone | `https://github.com/YakPanel/YakPanel.git` (optional: `https://source.yakpanel.com/yakpanel.git` when your mirror is live) | | `REPO_URL` | Git URL to clone | `https://source.yakpanel.com/admin/yakpanel-core` (fallback: `https://github.com/YakPanel/YakPanel.git`) |
| `YAKPANEL_BRANCH` | Branch/tag for shallow clone | default branch | | `YAKPANEL_BRANCH` | Branch/tag for shallow clone | default branch |
| `GIT_REF` | Alias for `YAKPANEL_BRANCH` | — | | `GIT_REF` | Alias for `YAKPANEL_BRANCH` | — |
| `INSTALL_PATH` | Install directory | `/www/server/YakPanel-server` | | `INSTALL_PATH` | Install directory | `/www/server/YakPanel-server` |
@@ -103,7 +103,7 @@ sudo bash scripts/install.sh
Uses `docker-compose.yml` in this directory — **not** the same layout as native (no host Nginx unit from `install.sh`). Uses `docker-compose.yml` in this directory — **not** the same layout as native (no host Nginx unit from `install.sh`).
```bash ```bash
git clone --depth 1 https://github.com/YakPanel/YakPanel.git git clone --depth 1 https://source.yakpanel.com/admin/yakpanel-core
# Then cd to this folder (in the full monorepo it is under YakPanel-master/YakPanel-server). # Then cd to this folder (in the full monorepo it is under YakPanel-master/YakPanel-server).
cd YakPanel-master/YakPanel-server cd YakPanel-master/YakPanel-server
docker compose up -d docker compose up -d

View File

@@ -1,5 +1,6 @@
# YakPanel - Environment # YakPanel - Environment
SECRET_KEY=change-this-in-production SECRET_KEY=change-this-in-production
# Resolved against backend directory (see app/core/database.py), safe when CWD is not backend/
DATABASE_URL=sqlite+aiosqlite:///./data/default.db DATABASE_URL=sqlite+aiosqlite:///./data/default.db
REDIS_URL=redis://localhost:6379/0 REDIS_URL=redis://localhost:6379/0
DEBUG=false DEBUG=false

View File

@@ -21,7 +21,7 @@ class Settings(BaseSettings):
www_logs: str = "/www/wwwlogs" www_logs: str = "/www/wwwlogs"
vhost_path: str = "/www/server/panel/vhost" vhost_path: str = "/www/server/panel/vhost"
# Database (use absolute path for SQLite) # Database (relative SQLite paths are resolved to backend/data/, not process CWD)
database_url: str = "sqlite+aiosqlite:///./data/default.db" database_url: str = "sqlite+aiosqlite:///./data/default.db"
# Redis # Redis

View File

@@ -1,20 +1,36 @@
"""YakPanel - Database configuration""" """YakPanel - Database configuration"""
import os from pathlib import Path
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.engine.url import URL, make_url
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import DeclarativeBase
from app.core.config import get_settings from app.core.config import get_settings
settings = get_settings() def _resolve_database_url(raw_url: str) -> str:
"""Anchor relative SQLite paths to the backend directory (not process CWD)."""
url = make_url(raw_url)
if not url.drivername.startswith("sqlite"):
return raw_url
db_path = url.database
if db_path is None or db_path.startswith(":"):
return raw_url
path = Path(db_path)
backend_dir = Path(__file__).resolve().parent.parent
if not path.is_absolute():
path = (backend_dir / path).resolve()
else:
path = path.resolve()
path.parent.mkdir(parents=True, exist_ok=True)
return str(URL.create(drivername=url.drivername, database=str(path)))
# Ensure data directory exists for SQLite
if "sqlite" in settings.database_url: settings = get_settings()
backend_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DATABASE_URL = _resolve_database_url(settings.database_url)
data_dir = os.path.join(backend_dir, "data")
os.makedirs(data_dir, exist_ok=True)
engine = create_async_engine( engine = create_async_engine(
settings.database_url, DATABASE_URL,
echo=settings.debug, echo=settings.debug,
) )
@@ -29,6 +45,7 @@ AsyncSessionLocal = async_sessionmaker(
class Base(DeclarativeBase): class Base(DeclarativeBase):
"""SQLAlchemy declarative base""" """SQLAlchemy declarative base"""
pass pass
@@ -48,13 +65,22 @@ async def get_db():
def _run_migrations(conn): def _run_migrations(conn):
"""Add new columns to existing tables (SQLite).""" """Add new columns to existing tables (SQLite)."""
import sqlalchemy import sqlalchemy
try: try:
r = conn.execute(sqlalchemy.text("PRAGMA table_info(sites)")) r = conn.execute(sqlalchemy.text("PRAGMA table_info(sites)"))
cols = [row[1] for row in r.fetchall()] cols = [row[1] for row in r.fetchall()]
if "php_version" not in cols: if "php_version" not in cols:
conn.execute(sqlalchemy.text("ALTER TABLE sites ADD COLUMN php_version VARCHAR(16) DEFAULT '74'")) conn.execute(
sqlalchemy.text(
"ALTER TABLE sites ADD COLUMN php_version VARCHAR(16) DEFAULT '74'"
)
)
if "force_https" not in cols: if "force_https" not in cols:
conn.execute(sqlalchemy.text("ALTER TABLE sites ADD COLUMN force_https INTEGER DEFAULT 0")) conn.execute(
sqlalchemy.text(
"ALTER TABLE sites ADD COLUMN force_https INTEGER DEFAULT 0"
)
)
except Exception: except Exception:
pass pass
# Create backup_plans if not exists (create_all handles new installs) # Create backup_plans if not exists (create_all handles new installs)
@@ -91,6 +117,7 @@ def _run_migrations(conn):
async def init_db(): async def init_db():
"""Initialize database tables""" """Initialize database tables"""
import app.models # noqa: F401 - register all models with Base.metadata import app.models # noqa: F401 - register all models with Base.metadata
async with engine.begin() as conn: async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all) await conn.run_sync(Base.metadata.create_all)
if "sqlite" in str(engine.url): if "sqlite" in str(engine.url):

View File

@@ -9,7 +9,7 @@
# sudo -E bash install.sh # sudo -E bash install.sh
# #
# Environment (optional): # Environment (optional):
# REPO_URL Git URL (default: public GitHub; use source.yakpanel.com when mirror is live) # REPO_URL Git URL (default: https://source.yakpanel.com/admin/yakpanel-core)
# YAKPANEL_BRANCH Branch/tag for shallow clone (default: default branch) # YAKPANEL_BRANCH Branch/tag for shallow clone (default: default branch)
# GIT_REF Alias for YAKPANEL_BRANCH # GIT_REF Alias for YAKPANEL_BRANCH
# INSTALL_PATH Install dir (default: /www/server/YakPanel-server) # INSTALL_PATH Install dir (default: /www/server/YakPanel-server)
@@ -209,8 +209,7 @@ else
CLONE_ARGS+=("$REPO_URL" "$TMP_DIR/repo") CLONE_ARGS+=("$REPO_URL" "$TMP_DIR/repo")
if ! "${CLONE_ARGS[@]}"; then if ! "${CLONE_ARGS[@]}"; then
echo "Git clone failed. Check REPO_URL=$REPO_URL, DNS, and outbound HTTPS." echo "Git clone failed. Check REPO_URL=$REPO_URL, DNS, and outbound HTTPS."
echo "Try: sudo -E env REPO_URL=https://github.com/YakPanel/YakPanel.git bash install.sh" echo "Try public fallback: sudo -E env REPO_URL=https://github.com/YakPanel/YakPanel.git bash install.sh"
echo "Own mirror: REPO_URL=https://source.yakpanel.com/yakpanel.git (requires bare repo published; see HOSTING.txt)."
exit 1 exit 1
fi fi
SRC_DIR="$(find_yakpanel_root_in_tree "$TMP_DIR/repo")" SRC_DIR="$(find_yakpanel_root_in_tree "$TMP_DIR/repo")"