added startup script

This commit is contained in:
onysd 2026-07-24 02:37:50 +03:00
parent 0a6c05404a
commit f22a568832
3 changed files with 452 additions and 0 deletions

5
.gitignore vendored
View file

@ -27,6 +27,11 @@ tmp/
.gocache/
.tdesktop-e2e/
# start-server.sh/bat generated files
.public_ip
.link_prefix
.secrets
# IDE
.idea/
.vscode/

234
start-server.bat Normal file
View file

@ -0,0 +1,234 @@
@echo off
setlocal enabledelayedexpansion
cd /d "%~dp0"
set "ENV_EXAMPLE=.env.example"
set "ENV_FILE=.env"
set "IP_FILE=.public_ip"
set "PREFIX_FILE=.link_prefix"
set "SECRETS_FILE=.secrets"
set "COMPOSE_FILE=deploy\docker-compose.yml"
set "NO_BUILD=false"
:parse_args
if "%~1"=="" goto done_args
if /i "%~1"=="--no-build" set "NO_BUILD=true"
shift
goto parse_args
:done_args
echo [cfg] script started, NO_BUILD=%NO_BUILD%
rem --- Public address (interactive) -----------------------------------------
set "DEFAULT_IP="
if exist "%IP_FILE%" (
set /p DEFAULT_IP=<"%IP_FILE%"
echo [cfg] loaded saved IP: !DEFAULT_IP!
)
if not defined DEFAULT_IP (
echo [cfg] detecting public IP...
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "(Invoke-WebRequest -Uri 'https://api.ipify.org' -TimeoutSec 5 -UseBasicParsing).Content" 2^>nul`) do set "DEFAULT_IP=%%i"
if defined DEFAULT_IP echo [cfg] detected IP: !DEFAULT_IP!
)
if defined DEFAULT_IP (
set /p "PUBLIC_IP=Public server IP/host [!DEFAULT_IP!]: "
) else (
set /p "PUBLIC_IP=Public server IP/host: "
)
if not defined PUBLIC_IP set "PUBLIC_IP=!DEFAULT_IP!"
if not defined PUBLIC_IP (
echo [ERROR] public IP/host is required.
pause
exit /b 1
)
> "%IP_FILE%" echo !PUBLIC_IP!
echo [cfg] public address = !PUBLIC_IP!
rem --- Link prefix / me_url_prefix (interactive) ----------------------------
set "DEFAULT_PREFIX=!PUBLIC_IP!"
if exist "%PREFIX_FILE%" set /p DEFAULT_PREFIX=<"%PREFIX_FILE%"
set /p "LINK_PREFIX=Link prefix [!DEFAULT_PREFIX!]: "
if not defined LINK_PREFIX set "LINK_PREFIX=!DEFAULT_PREFIX!"
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$p='!LINK_PREFIX!'; $p=$p -replace '^https?://','' -replace '/+$',''; Write-Output $p"`) do set "LINK_PREFIX=%%i"
if not defined LINK_PREFIX (
echo [ERROR] link prefix is required.
pause
exit /b 1
)
> "%PREFIX_FILE%" echo !LINK_PREFIX!
echo [cfg] link prefix = !LINK_PREFIX!
rem --- Secrets (generated once, cached) -------------------------------------
set "ADMIN_TOKEN="
set "ADMIN_PASSWORD="
set "SESSION_KEY="
set "SECRETS_CHANGED="
if exist "%SECRETS_FILE%" (
echo [cfg] loading secrets from %SECRETS_FILE%
for /f "usebackq tokens=1,* delims==" %%A in (`type "%SECRETS_FILE%"`) do (
if "%%A"=="ADMIN_TOKEN" set "ADMIN_TOKEN=%%B"
if "%%A"=="ADMIN_PASSWORD" set "ADMIN_PASSWORD=%%B"
if "%%A"=="SESSION_KEY" set "SESSION_KEY=%%B"
)
)
if not defined ADMIN_TOKEN (
echo [cfg] generating ADMIN_TOKEN...
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$bytes=New-Object byte[] 32; [System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes); ($bytes | ForEach-Object { $_.ToString('x2') }) -join ''"`) do set "ADMIN_TOKEN=%%i"
set "SECRETS_CHANGED=1"
)
if not defined ADMIN_PASSWORD (
echo [cfg] generating ADMIN_PASSWORD...
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; -join (1..24 | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })"`) do set "ADMIN_PASSWORD=%%i"
set "SECRETS_CHANGED=1"
)
if not defined SESSION_KEY (
echo [cfg] generating SESSION_KEY...
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; -join (1..48 | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })"`) do set "SESSION_KEY=%%i"
set "SECRETS_CHANGED=1"
)
if defined SECRETS_CHANGED (
> "%SECRETS_FILE%" echo ADMIN_TOKEN=!ADMIN_TOKEN!
>> "%SECRETS_FILE%" echo ADMIN_PASSWORD=!ADMIN_PASSWORD!
>> "%SECRETS_FILE%" echo SESSION_KEY=!SESSION_KEY!
echo [cfg] secrets written to %SECRETS_FILE%
) else (
echo [cfg] secrets loaded from %SECRETS_FILE%
)
rem --- Generate .env from .env.example --------------------------------------
if not exist "%ENV_EXAMPLE%" (
echo [ERROR] template file %ENV_EXAMPLE% not found
pause
exit /b 1
)
copy /Y "%ENV_EXAMPLE%" "%ENV_FILE%" >nul
echo [cfg] copied %ENV_EXAMPLE% to %ENV_FILE%
echo [cfg] patching .env values...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$f='%ENV_FILE%'; " ^
"$enc=New-Object System.Text.UTF8Encoding($false); " ^
"$t=[System.IO.File]::ReadAllText($f,$enc); " ^
"$map=[ordered]@{ " ^
" 'TELESRV_ADVERTISE_IP'='!PUBLIC_IP!'; " ^
" 'TELESRV_TURN_ADVERTISE_IP'='!PUBLIC_IP!'; " ^
" 'TELESRV_SFU_ADVERTISE_IP'='!PUBLIC_IP!'; " ^
" 'TELESRV_PUBLIC_BASE_URL'='https://!LINK_PREFIX!'; " ^
" 'TELESRV_PASSKEY_RP_ID'='!LINK_PREFIX!'; " ^
" 'TELESRV_PUBLIC_APP_SCHEME'='owpg'; " ^
" 'TELESRV_PUBLIC_APP_NAME'='OwpenGram'; " ^
" 'TELESRV_ADMIN_API_TOKEN'='!ADMIN_TOKEN!'; " ^
" 'TELESRV_ADMIN_UI_PASSWORD'='!ADMIN_PASSWORD!'; " ^
" 'TELESRV_ADMIN_SESSION_KEY'='!SESSION_KEY!'; " ^
" 'TELESRV_ADMIN_UI_ADDR'='127.0.0.1:2600'; " ^
" 'TELESRV_ADMIN_API_ADDR'='127.0.0.1:2399'; " ^
" 'TELESRV_PUBLIC_LINK_WEB_ADDR'='127.0.0.1:2401' " ^
"}; " ^
"foreach ($k in $map.Keys) { " ^
" $pat='(?m)^' + [regex]::Escape($k) + '=.*$'; " ^
" $rep=$k + '=' + $map[$k]; " ^
" if ($t -match $pat) { $t=[regex]::Replace($t,$pat,$rep) } " ^
" else { $t+=\"`r`n\"+$rep } " ^
"}; " ^
"[System.IO.File]::WriteAllText($f,$t,$enc); " ^
"Write-Output 'ok'"
if %ERRORLEVEL% neq 0 (
echo [ERROR] failed to patch .env
pause
exit /b 1
)
echo [cfg] .env written
rem --- Start infrastructure (PostgreSQL + Redis) ----------------------------
echo.
echo == [1/4] Starting infrastructure (PostgreSQL + Redis) ==
docker compose -f "%COMPOSE_FILE%" up -d
if %ERRORLEVEL% neq 0 (
echo [ERROR] docker compose failed
pause
exit /b 1
)
rem --- Wait for PostgreSQL --------------------------------------------------
echo.
echo == [2/4] Waiting for PostgreSQL ==
set /a "_pgw=0"
:wait_pg
docker exec telesrv-postgres pg_isready -U telesrv -d telesrv >nul 2>&1
if not errorlevel 1 goto pg_ready
set /a "_pgw+=1"
if !_pgw! gtr 30 (
echo [ERROR] PostgreSQL not ready after 60s
pause
exit /b 1
)
echo [cfg] waiting for PostgreSQL... !_pgw!/30
timeout /t 2 >nul
goto wait_pg
:pg_ready
echo [ok] PostgreSQL is ready
rem --- Build ------------------------------------------------------------------
echo.
echo == [3/4] Building server binaries ==
if /i "%NO_BUILD%"=="true" (
echo [cfg] skipping build (--no-build)
if not exist "bin\telesrv.exe" (
if not exist "bin\telesrv-admin.exe" (
echo [ERROR] no binaries found in bin\ - run without --no-build first
pause
exit /b 1
)
)
) else (
if not exist bin mkdir bin
echo [cfg] building telesrv...
go build -o bin\telesrv.exe .\cmd\telesrv
if %ERRORLEVEL% neq 0 (
echo [ERROR] failed to build telesrv
pause
exit /b 1
)
echo [cfg] building telesrv-admin...
go build -o bin\telesrv-admin.exe .\cmd\telesrv-admin
if %ERRORLEVEL% neq 0 (
echo [ERROR] failed to build telesrv-admin
pause
exit /b 1
)
echo [ok] binaries built
)
rem --- Start servers ----------------------------------------------------------
echo.
echo == [4/4] Starting telesrv + telesrv-admin ==
start "telesrv" /B bin\telesrv.exe
echo [ok] telesrv started
start "telesrv-admin" /B bin\telesrv-admin.exe
echo [ok] telesrv-admin started
echo.
echo ============================================
echo OwpenGram server is running
echo ============================================
echo.
echo MTProto: !PUBLIC_IP!:2398
echo Admin UI: http://127.0.0.1:2600
echo Admin API: http://127.0.0.1:2399
echo.
echo Admin login password: !ADMIN_PASSWORD!
echo.
echo Ports to open in firewall:
echo TCP 2398 - MTProto (login / chats / media)
echo TCP 12400 - TURN/STUN control (calls)
echo UDP 12500-12999 - TURN media relay (calls)
echo UDP 12399 - SFU group calls
echo TCP 2400 - RTMP livestream ingest
echo.
echo ============================================
exit /b 0

213
start-server.sh Normal file
View file

@ -0,0 +1,213 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
ENV_EXAMPLE=".env.example"
ENV_FILE=".env"
IP_FILE=".public_ip"
PREFIX_FILE=".link_prefix"
SECRETS_FILE=".secrets"
COMPOSE_FILE="deploy/docker-compose.yml"
NO_BUILD=false
for arg in "$@"; do
case "$arg" in
--no-build) NO_BUILD=true ;;
-h|--help)
echo "Usage: $0 [--no-build]"
echo ""
echo " --no-build Skip Go compilation (reuse existing binaries in bin/)"
exit 0
;;
esac
done
# --- Helpers ----------------------------------------------------------------
log() { echo "[cfg] $*"; }
step() { echo; echo "== $* =="; }
die() { echo "[ERROR] $*" >&2; exit 1; }
random_hex() {
local bytes="${1:-32}"
openssl rand -hex "$bytes" 2>/dev/null || head -c "$bytes" /dev/urandom | xxd -p | tr -d '\n' | head -c $((bytes * 2))
}
random_string() {
local len="${1:-24}"
openssl rand -base64 "$((len * 2))" 2>/dev/null | tr -dc 'a-zA-Z0-9' | head -c "$len" \
|| head -c 256 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c "$len"
}
# --- Public address (interactive) ------------------------------------------
DEFAULT_IP=""
[[ -f "$IP_FILE" ]] && DEFAULT_IP="$(tr -d '[:space:]' < "$IP_FILE")"
if [[ -z "$DEFAULT_IP" ]]; then
DEFAULT_IP="$(curl -fsS --max-time 3 https://api.ipify.org 2>/dev/null || true)"
fi
if [[ -n "$DEFAULT_IP" ]]; then
read -rp "Public server IP/host [${DEFAULT_IP}]: " PUBLIC_IP
else
read -rp "Public server IP/host: " PUBLIC_IP
fi
PUBLIC_IP="${PUBLIC_IP:-$DEFAULT_IP}"
[[ -z "$PUBLIC_IP" ]] && die "public IP/host is required."
echo "$PUBLIC_IP" > "$IP_FILE"
log "public address = ${PUBLIC_IP}"
# --- Link prefix / me_url_prefix (interactive) -----------------------------
DEFAULT_PREFIX="$PUBLIC_IP"
[[ -f "$PREFIX_FILE" ]] && DEFAULT_PREFIX="$(tr -d '[:space:]' < "$PREFIX_FILE")"
read -rp "Link prefix (me_url_prefix, e.g. ${PUBLIC_IP} or chat.example.com) [${DEFAULT_PREFIX}]: " LINK_PREFIX
LINK_PREFIX="${LINK_PREFIX:-$DEFAULT_PREFIX}"
LINK_PREFIX="$(printf '%s' "$LINK_PREFIX" | sed -E 's#^https?://##; s#/+$##')"
[[ -z "$LINK_PREFIX" ]] && die "link prefix is required."
echo "$LINK_PREFIX" > "$PREFIX_FILE"
log "link prefix (me_url_prefix) = ${LINK_PREFIX}"
# --- Secrets (generated once, cached) --------------------------------------
load_or_gen_secrets() {
local admin_token="" admin_password="" session_key=""
if [[ -f "$SECRETS_FILE" ]]; then
# shellcheck disable=SC1090
source "$SECRETS_FILE" 2>/dev/null || true
fi
if [[ -z "${ADMIN_TOKEN:-}" ]]; then
ADMIN_TOKEN="$(random_hex 32)"
fi
if [[ -z "${ADMIN_PASSWORD:-}" ]]; then
ADMIN_PASSWORD="$(random_string 24)"
fi
if [[ -z "${SESSION_KEY:-}" ]]; then
SESSION_KEY="$(random_string 48)"
fi
cat > "$SECRETS_FILE" <<EOF
ADMIN_TOKEN=${ADMIN_TOKEN}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
SESSION_KEY=${SESSION_KEY}
EOF
chmod 600 "$SECRETS_FILE"
log "secrets loaded from ${SECRETS_FILE}"
}
load_or_gen_secrets
# --- Generate .env from .env.example --------------------------------------
if [[ ! -f "$ENV_EXAMPLE" ]]; then
die "template file ${ENV_EXAMPLE} not found"
fi
cp "$ENV_EXAMPLE" "$ENV_FILE"
set_env() {
local key="$1" value="$2"
if grep -qE "^${key}=" "$ENV_FILE"; then
sed -i -E "s|^${key}=.*|${key}=${value}|" "$ENV_FILE"
else
echo "${key}=${value}" >> "$ENV_FILE"
fi
}
set_env "TELESRV_ADVERTISE_IP" "$PUBLIC_IP"
set_env "TELESRV_TURN_ADVERTISE_IP" "$PUBLIC_IP"
set_env "TELESRV_SFU_ADVERTISE_IP" "$PUBLIC_IP"
set_env "TELESRV_PUBLIC_BASE_URL" "https://${LINK_PREFIX}"
set_env "TELESRV_PASSKEY_RP_ID" "$LINK_PREFIX"
set_env "TELESRV_PUBLIC_APP_SCHEME" "owpg"
set_env "TELESRV_PUBLIC_APP_NAME" "OwpenGram"
set_env "TELESRV_ADMIN_API_TOKEN" "$ADMIN_TOKEN"
set_env "TELESRV_ADMIN_UI_PASSWORD" "$ADMIN_PASSWORD"
set_env "TELESRV_ADMIN_SESSION_KEY" "$SESSION_KEY"
set_env "TELESRV_ADMIN_UI_ADDR" "127.0.0.1:2600"
set_env "TELESRV_ADMIN_API_ADDR" "127.0.0.1:2399"
set_env "TELESRV_PUBLIC_LINK_WEB_ADDR" "127.0.0.1:2401"
log ".env written (${ENV_FILE})"
# --- Start infrastructure (PostgreSQL + Redis) -----------------------------
step "[1/4] Starting infrastructure (PostgreSQL + Redis)"
docker compose -f "$COMPOSE_FILE" up -d
# --- Wait for PostgreSQL ---------------------------------------------------
step "[2/4] Waiting for PostgreSQL"
for i in $(seq 1 30); do
if docker exec telesrv-postgres pg_isready -U telesrv -d telesrv >/dev/null 2>&1; then
echo "[ok] PostgreSQL is ready"
break
fi
if [ "$i" -eq 30 ]; then
die "PostgreSQL not ready after 60s"
fi
sleep 2
done
# --- Build ------------------------------------------------------------------
step "[3/4] Building server binaries"
if [ "$NO_BUILD" = true ]; then
log "skipping build (--no-build)"
if [[ ! -f "bin/telesrv" ]] && [[ ! -f "bin/telesrv.exe" ]]; then
die "no binaries found in bin/ — run without --no-build first"
fi
else
mkdir -p bin
echo " building telesrv ..."
go build -o bin/telesrv ./cmd/telesrv
echo " building telesrv-admin ..."
go build -o bin/telesrv-admin ./cmd/telesrv-admin
echo "[ok] binaries built in bin/"
fi
# --- Start servers ----------------------------------------------------------
step "[4/4] Starting telesrv + telesrv-admin"
cleanup() {
echo
echo "[stop] stopping telesrv and telesrv-admin ..."
kill "$TELESRV_PID" 2>/dev/null || true
kill "$ADMIN_PID" 2>/dev/null || true
wait "$TELESRV_PID" 2>/dev/null || true
wait "$ADMIN_PID" 2>/dev/null || true
echo "[ok] stopped."
}
trap cleanup EXIT INT TERM
# Start telesrv (main server)
BIN="./bin/telesrv"
[[ -f "bin/telesrv.exe" ]] && BIN="./bin/telesrv.exe"
$BIN &
TELESRV_PID=$!
echo "[ok] telesrv started (PID ${TELESRV_PID})"
# Start telesrv-admin (admin panel)
ADMIN_BIN="./bin/telesrv-admin"
[[ -f "bin/telesrv-admin.exe" ]] && ADMIN_BIN="./bin/telesrv-admin.exe"
$ADMIN_BIN &
ADMIN_PID=$!
echo "[ok] telesrv-admin started (PID ${ADMIN_PID})"
echo
echo "============================================"
echo " OwpenGram server is running"
echo "============================================"
echo ""
echo " MTProto: ${PUBLIC_IP}:2398"
echo " Admin UI: http://127.0.0.1:2600"
echo " Admin API: http://127.0.0.1:2399"
echo ""
echo " Admin login password: ${ADMIN_PASSWORD}"
echo ""
echo " Ports to open in firewall:"
echo " TCP 2398 - MTProto (login / chats / media)"
echo " TCP 12400 - TURN/STUN control (calls)"
echo " UDP 12500-12999 - TURN media relay (calls)"
echo " UDP 12399 - SFU group calls"
echo " TCP 2400 - RTMP livestream ingest"
echo ""
echo " Press Ctrl+C to stop."
echo "============================================"
wait "$TELESRV_PID" 2>/dev/null || true
wait "$ADMIN_PID" 2>/dev/null || true