updated to docker containers new name

This commit is contained in:
onysd 2026-07-27 23:35:20 +03:00
parent 0e5da4c8aa
commit d37ecf6071
9 changed files with 216 additions and 249 deletions

1
.docker_naming Normal file
View file

@ -0,0 +1 @@
owpengram

View file

@ -6,16 +6,20 @@
# 清空: docker compose down -v (连数据卷一起删,重置 schema/数据)
#
# server 端连接串见 internal/config/config.go 的默认值localhost:5432 / localhost:6399
name: telesrv
#
# 容器/卷命名可通过 TELESRV_DOCKER_PROJECT / TELESRV_DOCKER_PREFIX 覆盖(默认 owpengram
# start-server.sh 对已存在 telesrv_* 卷、且用户拒绝一次性改名迁移的安装,会把这两个变量
# 固定设为 telesrv从而永久保留旧命名不动用户现有的 telesrv_pgdata / telesrv_redisdata。
name: ${TELESRV_DOCKER_PROJECT:-owpengram}
services:
postgres:
image: postgres:17-alpine
container_name: telesrv-postgres
container_name: ${TELESRV_DOCKER_PREFIX:-owpengram}-postgres
# 全库已去分区普通表max_locks_per_transaction 默认 64 已够512 仅留余量,对内存近乎零开销。
# pg_stat_statements聚合各 SQL 的累计/平均耗时与调用次数,用于定位 postgres 容器 CPU 热点
# telesrv 是宿主进程docker stats 里的 CPU 尖峰是本容器)。需 CREATE EXTENSION 后才有视图:
# docker exec -i telesrv-postgres psql -U telesrv -d telesrv -c "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;"
# docker exec -i owpengram-postgres psql -U telesrv -d telesrv -c "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;"
command:
- "postgres"
- "-c"
@ -44,7 +48,7 @@ services:
redis:
image: redis:7-alpine
container_name: telesrv-redis
container_name: ${TELESRV_DOCKER_PREFIX:-owpengram}-redis
command: ["redis-server", "--appendonly", "yes"]
ports:
- "6399:6379" # 宿主 6379 常被其他项目占用telesrv 对外用 6399容器内仍 6379
@ -59,4 +63,6 @@ services:
volumes:
pgdata:
name: ${TELESRV_DOCKER_PREFIX:-owpengram}_pgdata
redisdata:
name: ${TELESRV_DOCKER_PREFIX:-owpengram}_redisdata

View file

@ -0,0 +1,122 @@
<#
Resolves (and, once, offers to migrate) the Docker project/container/volume
naming used by deploy/docker-compose.yml.
The project used to be named "telesrv" in Docker (containers telesrv-postgres /
telesrv-redis, volumes telesrv_pgdata / telesrv_redisdata). It's now
"owpengram" by default, so a gramsrv instance running on the same machine
can't be confused with this one at a glance in `docker ps` / Docker Desktop.
Existing installs may still have telesrv_* volumes with real data in them.
This script asks, at most once, whether to copy that data over to owpengram_*
naming. The answer is cached in a state file next to .secrets/.public_ip:
- accepted -> volumes are copied (old telesrv_* volumes are left in place,
untouched, as a backup), state becomes "owpengram", never asked again.
- declined -> state becomes "telesrv", the install keeps the old naming
forever, never asked again.
- fresh install (no telesrv_* volumes found) -> silently uses "owpengram",
nothing to migrate.
Prints exactly two lines to stdout: the resolved project name, then the
resolved container/volume prefix. Everything else (prompts, progress) goes to
stderr, so a caller can safely capture just stdout.
#>
[CmdletBinding()]
param(
[string]$ComposeFile = "deploy\docker-compose.yml",
[string]$StateFile = ".docker_naming"
)
function Write-Info([string]$Message) {
[Console]::Error.WriteLine($Message)
}
function Write-Result([string]$Project, [string]$Prefix) {
[Console]::Out.WriteLine($Project)
[Console]::Out.WriteLine($Prefix)
}
function Test-DockerVolume([string]$Name) {
docker volume inspect $Name *> $null
return $LASTEXITCODE -eq 0
}
$state = $null
if (Test-Path $StateFile) {
$state = (Get-Content $StateFile -Raw -ErrorAction SilentlyContinue)
if ($state) { $state = $state.Trim() }
}
if ($state -eq "owpengram") {
Write-Result "owpengram" "owpengram"
exit 0
}
if ($state -eq "telesrv") {
Write-Result "telesrv" "telesrv"
exit 0
}
$oldPg = Test-DockerVolume "telesrv_pgdata"
$oldRedis = Test-DockerVolume "telesrv_redisdata"
if (-not $oldPg -and -not $oldRedis) {
# Fresh install: nothing to migrate, just adopt the new naming.
Set-Content -Path $StateFile -Value "owpengram" -NoNewline
Write-Result "owpengram" "owpengram"
exit 0
}
if ([Console]::IsInputRedirected) {
# Can't prompt right now (piped/non-interactive run). Keep old naming for
# this run only — don't cache a decision nobody actually made.
Write-Info "[cfg] old 'telesrv_*' Docker volumes found but running non-interactively; keeping old naming for now"
Write-Result "telesrv" "telesrv"
exit 0
}
Write-Info ""
Write-Info "== Docker container/volume naming =="
Write-Info "Found existing Docker volumes named 'telesrv_*' (from before the project was"
Write-Info "renamed to OwpenGram). Renaming them to 'owpengram_*' avoids confusing this"
Write-Info "server with a gramsrv instance running on the same machine. Recommended."
$reply = Read-Host "Migrate Docker containers/volumes from 'telesrv' to 'owpengram' naming now? [Y/n]"
if ($reply -match '^[Nn]') {
Set-Content -Path $StateFile -Value "telesrv" -NoNewline
Write-Info "[cfg] keeping 'telesrv' Docker naming (won't ask again)"
Write-Result "telesrv" "telesrv"
exit 0
}
Write-Info "[cfg] migrating Docker volumes: telesrv_* -> owpengram_*"
$env:TELESRV_DOCKER_PROJECT = "telesrv"
$env:TELESRV_DOCKER_PREFIX = "telesrv"
docker compose -f $ComposeFile -p telesrv stop postgres redis *> $null
Remove-Item Env:\TELESRV_DOCKER_PROJECT, Env:\TELESRV_DOCKER_PREFIX -ErrorAction SilentlyContinue
if ($oldPg) {
docker volume create owpengram_pgdata *> $null
docker run --rm -v telesrv_pgdata:/from -v owpengram_pgdata:/to alpine sh -c "cp -a /from/. /to/"
if ($LASTEXITCODE -ne 0) {
Write-Info "[ERROR] failed to copy pgdata volume"
exit 1
}
}
if ($oldRedis) {
docker volume create owpengram_redisdata *> $null
docker run --rm -v telesrv_redisdata:/from -v owpengram_redisdata:/to alpine sh -c "cp -a /from/. /to/"
if ($LASTEXITCODE -ne 0) {
Write-Info "[ERROR] failed to copy redisdata volume"
exit 1
}
}
$env:TELESRV_DOCKER_PROJECT = "telesrv"
$env:TELESRV_DOCKER_PREFIX = "telesrv"
docker compose -f $ComposeFile -p telesrv down *> $null
Remove-Item Env:\TELESRV_DOCKER_PROJECT, Env:\TELESRV_DOCKER_PREFIX -ErrorAction SilentlyContinue
Set-Content -Path $StateFile -Value "owpengram" -NoNewline
Write-Info "[ok] migration complete - old 'telesrv_*' volumes were left in place, untouched, as a backup"
Write-Result "owpengram" "owpengram"

View file

@ -13,7 +13,7 @@ param(
[string]$ServerLogPath,
[string]$AndroidPackage = "org.telegram.messenger.beta",
[string]$DeviceSerial,
[string]$PostgresContainer = "telesrv-postgres",
[string]$PostgresContainer = "owpengram-postgres",
[string]$Database = "telesrv",
[string]$DbUser = "telesrv",
[int]$RecentLogLines = 1200,

View file

@ -19,7 +19,7 @@ param(
[string]$AndroidPackage = "org.telegram.messenger.beta",
[string]$DeviceSerial,
[string]$PostgresContainer = "telesrv-postgres",
[string]$PostgresContainer = "owpengram-postgres",
[string]$Database = "telesrv",
[string]$DbUser = "telesrv",

View file

@ -31,7 +31,7 @@ param(
[string]$AndroidPackage = "org.telegram.messenger.beta",
[string]$DeviceSerial,
[string]$PostgresContainer = "telesrv-postgres",
[string]$PostgresContainer = "owpengram-postgres",
[string]$Database = "telesrv",
[string]$DbUser = "telesrv",

View file

@ -22,7 +22,7 @@ param(
[string]$AndroidPackage = "org.telegram.messenger.beta",
[string]$DeviceSerial,
[string]$PostgresContainer = "telesrv-postgres",
[string]$PostgresContainer = "owpengram-postgres",
[string]$Database = "telesrv",
[string]$DbUser = "telesrv",

View file

@ -2,11 +2,7 @@
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 "LOG_DIR=logs"
@ -20,127 +16,31 @@ goto parse_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.
rem This script only starts the server -- it never writes or edits .env. Set
rem up .env yourself (from .env.example) before running it.
if not exist "%ENV_FILE%" (
echo [ERROR] %ENV_FILE% not found - copy .env.example to %ENV_FILE% and configure it first
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.
rem --- Docker container/volume naming (telesrv -> owpengram), one-time, opt-in
rem Resolves whether this install uses the new "owpengram" Docker naming or
rem (if telesrv_* volumes exist and the user declined migrating them) keeps
rem the old "telesrv" naming permanently. See deploy\migrate-docker-naming.ps1.
set "DOCKER_PROJECT="
set "DOCKER_PREFIX="
for /f "usebackq delims=" %%i in (`powershell -NoProfile -ExecutionPolicy Bypass -File deploy\migrate-docker-naming.ps1`) do (
if not defined DOCKER_PROJECT (set "DOCKER_PROJECT=%%i") else if not defined DOCKER_PREFIX (set "DOCKER_PREFIX=%%i")
)
if not defined DOCKER_PROJECT (
echo [ERROR] docker naming resolution failed
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
set "TELESRV_DOCKER_PROJECT=%DOCKER_PROJECT%"
set "TELESRV_DOCKER_PREFIX=%DOCKER_PREFIX%"
echo [cfg] docker naming = %DOCKER_PREFIX% (project %DOCKER_PROJECT%)
rem --- Start infrastructure (PostgreSQL + Redis) ----------------------------
echo.
@ -157,7 +57,7 @@ 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
docker exec %DOCKER_PREFIX%-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 (
@ -175,7 +75,7 @@ rem --- Build ------------------------------------------------------------------
echo.
echo == [3/4] Building server binaries ==
if /i "%NO_BUILD%"=="true" (
echo [cfg] skipping build (--no-build)
echo [cfg] skipping build, --no-build set
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
@ -210,23 +110,38 @@ if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
set "TELESRV_LOG=%LOG_DIR%\telesrv.log"
set "ADMIN_LOG=%LOG_DIR%\telesrv-admin.log"
start "telesrv" /B cmd /c "bin\telesrv.exe >> "%TELESRV_LOG%" 2>&1"
echo [ok] telesrv started, logs -^> %TELESRV_LOG%
rem "start /B cmd /c ..." creates no window, so the earlier WINDOWTITLE-based
rem taskkill in stop_server below never matched anything and silently killed
rem nothing. Launch via Start-Process -PassThru instead and track the real
rem PID. Still routed through cmd.exe /c so ">>log 2>&1" can merge stdout and
rem stderr into one file the way the bash script does (telesrv's own zap
rem logger writes to stderr, so splitting the streams would leave the "main"
rem log file nearly empty); "taskkill /T" below kills the whole cmd+exe tree,
rem not just the cmd.exe wrapper, so this still actually stops the process.
set "TELESRV_PID="
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "(Start-Process -FilePath 'cmd.exe' -ArgumentList '/c bin\telesrv.exe >> \"%TELESRV_LOG%\" 2>&1' -WindowStyle Hidden -PassThru).Id"`) do set "TELESRV_PID=%%i"
if not defined TELESRV_PID (
echo [ERROR] failed to start telesrv
pause
exit /b 1
)
echo [ok] telesrv started (PID %TELESRV_PID%), logs -^> %TELESRV_LOG%
start "telesrv-admin" /B cmd /c "bin\telesrv-admin.exe >> "%ADMIN_LOG%" 2>&1"
echo [ok] telesrv-admin started, logs -^> %ADMIN_LOG%
set "ADMIN_PID="
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "(Start-Process -FilePath 'cmd.exe' -ArgumentList '/c bin\telesrv-admin.exe >> \"%ADMIN_LOG%\" 2>&1' -WindowStyle Hidden -PassThru).Id"`) do set "ADMIN_PID=%%i"
if not defined ADMIN_PID (
echo [ERROR] failed to start telesrv-admin
taskkill /PID %TELESRV_PID% /T /F >nul 2>&1
pause
exit /b 1
)
echo [ok] telesrv-admin started (PID %ADMIN_PID%), logs -^> %ADMIN_LOG%
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 Logs:
echo telesrv: type %TELESRV_LOG%
echo telesrv-admin: type %ADMIN_LOG%
@ -235,6 +150,23 @@ echo ============================================
rem --- Interactive menu ------------------------------------------------------
:menu
tasklist /FI "PID eq %TELESRV_PID%" 2>nul | find "%TELESRV_PID%" >nul
if errorlevel 1 (
echo [WARN] telesrv PID %TELESRV_PID% exited unexpectedly
echo Check %TELESRV_LOG% for details
taskkill /PID %ADMIN_PID% /T /F >nul 2>&1
pause
exit /b 1
)
tasklist /FI "PID eq %ADMIN_PID%" 2>nul | find "%ADMIN_PID%" >nul
if errorlevel 1 (
echo [WARN] telesrv-admin PID %ADMIN_PID% exited unexpectedly
echo Check %ADMIN_LOG% for details
taskkill /PID %TELESRV_PID% /T /F >nul 2>&1
pause
exit /b 1
)
echo.
echo [1] View telesrv logs (last 50 lines)
echo [2] View telesrv-admin logs (last 50 lines)
@ -277,7 +209,7 @@ goto menu
:stop_server
echo.
echo [stop] stopping telesrv and telesrv-admin ...
taskkill /FI "WINDOWTITLE eq telesrv*" /F >nul 2>&1
taskkill /FI "WINDOWTITLE eq telesrv-admin*" /F >nul 2>&1
if defined TELESRV_PID taskkill /PID %TELESRV_PID% /T /F >nul 2>&1
if defined ADMIN_PID taskkill /PID %ADMIN_PID% /T /F >nul 2>&1
echo [ok] stopped.
exit /b 0

View file

@ -2,11 +2,7 @@
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"
LOG_DIR="logs"
@ -28,105 +24,21 @@ 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))
}
# This script only starts the server — it never writes or edits .env. Set up
# .env yourself (from .env.example) before running it.
[[ -f "$ENV_FILE" ]] || die "${ENV_FILE} not found — copy .env.example to ${ENV_FILE} and configure it first"
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})"
# --- Docker container/volume naming (telesrv -> owpengram), one-time, opt-in
# Resolves whether this install uses the new "owpengram" Docker naming or (if
# telesrv_* volumes exist and the user declined migrating them) keeps the old
# "telesrv" naming permanently. See deploy/migrate-docker-naming.ps1.
NAMING_OUT="$(powershell -NoProfile -ExecutionPolicy Bypass -File deploy/migrate-docker-naming.ps1)" \
|| die "docker naming resolution failed"
DOCKER_PROJECT="$(sed -n '1p' <<<"$NAMING_OUT")"
DOCKER_PREFIX="$(sed -n '2p' <<<"$NAMING_OUT")"
export TELESRV_DOCKER_PROJECT="$DOCKER_PROJECT"
export TELESRV_DOCKER_PREFIX="$DOCKER_PREFIX"
log "docker naming = ${DOCKER_PREFIX} (project ${DOCKER_PROJECT})"
# --- Start infrastructure (PostgreSQL + Redis) -----------------------------
step "[1/4] Starting infrastructure (PostgreSQL + Redis)"
@ -135,7 +47,7 @@ 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
if docker exec "${DOCKER_PREFIX}-postgres" pg_isready -U telesrv -d telesrv >/dev/null 2>&1; then
echo "[ok] PostgreSQL is ready"
break
fi
@ -198,12 +110,6 @@ 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 " Logs:"
echo " telesrv: tail -f ${TELESRV_LOG}"
echo " telesrv-admin: tail -f ${ADMIN_LOG}"