feat: expose web admin with auth by default

This commit is contained in:
Андрей Бобырев
2026-06-06 12:49:05 +03:00
parent 687d1dbadd
commit 4c635858c7
5 changed files with 95 additions and 25 deletions

View File

@@ -50,33 +50,32 @@ ssh root@SERVER 'chmod +x /opt/pcatelegram_web/install.sh /opt/pcatelegram_web/i
| `PCATELEGRAM_WEB_BASE` | `https://raw.githubusercontent.com/andrey271192/PCAtelegram_web/main` | база загрузки файлов |
| `PCATELEGRAM_WEB_INSTALL_DIR` | `/opt/pcatelegram_web` | путь установки |
| `GITHUB_TOKEN` / `GH_TOKEN` | пусто | token для private GitHub raw downloads |
| `PCATELEGRAM_WEB_ADMIN_HOST` | `127.0.0.1` | bind web-admin |
| `PCATELEGRAM_WEB_ADMIN_HOST` | `0.0.0.0` | bind web-admin |
| `PCATELEGRAM_WEB_ADMIN_PORT` | `1984` | port web-admin |
| `PCATELEGRAM_WEB_ADMIN_USER` | `admin` | Basic Auth login |
| `PCATELEGRAM_WEB_ADMIN_PASSWORD` | пусто | Basic Auth password; обязателен при public bind |
| `PCATELEGRAM_WEB_ADMIN_PASSWORD` | автогенерация | Basic Auth password |
## Web-admin
После первого запуска `pcatelegram_web` локальная web-admin панель ставится как `pcatelegram_web-admin.service`.
Безопасный локальный доступ через SSH tunnel:
После первого запуска `pcatelegram_web` web-admin панель ставится как `pcatelegram_web-admin.service` и слушает публично:
```bash
ssh -L 1984:127.0.0.1:1984 root@SERVER
open http://127.0.0.1:1984/
http://SERVER:1984/
```
Для public bind сначала задайте пароль через systemd override или reverse proxy:
Логин по умолчанию: `admin`. Пароль генерируется при установке и хранится на сервере:
```ini
[Service]
Environment=PCATELEGRAM_WEB_ADMIN_HOST=0.0.0.0
Environment=PCATELEGRAM_WEB_ADMIN_PORT=1984
Environment=PCATELEGRAM_WEB_ADMIN_USER=admin
Environment=PCATELEGRAM_WEB_ADMIN_PASSWORD=change-me
```bash
sudo cat /root/pcatelegram_web-admin.password
```
Без HTTPS public Basic Auth гонит пароль открытым текстом. Для постоянного доступа лучше reverse proxy с TLS.
Для своего пароля передайте env до установки:
```bash
PCATELEGRAM_WEB_ADMIN_PASSWORD='strong-password' bash bootstrap.sh
```
Без HTTPS Basic Auth гонит пароль открытым текстом. Для постоянного доступа лучше reverse proxy с TLS, но порт `1984` открыт по умолчанию по запросу проекта.
## Проверки

View File

@@ -2,9 +2,8 @@
"""
PCAtelegram_web local web admin.
The service is intentionally bound to 127.0.0.1:1984. Operators reach it
through an SSH tunnel by default. If exposed through a reverse proxy or public
bind, enable PCATELEGRAM_WEB_ADMIN_PASSWORD.
The service is publicly reachable by default and protected with Basic Auth.
Installers generate /root/pcatelegram_web-admin.password for credentials.
"""
from __future__ import annotations
@@ -49,7 +48,7 @@ SHARED_443_CONFIG = Path(os.getenv("PCATELEGRAM_WEB_SHARED_443", "/opt/pcatelegr
BACKUP_SCHEDULE_FILE = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_SCHEDULE", "/opt/pcatelegram_web/backup_schedule.json"))
BACKUP_RESTORE_LOG = Path(os.getenv("PCATELEGRAM_WEB_BACKUP_RESTORE_LOG", "/var/log/pcatelegram_web-restore.log"))
HOST = os.getenv("PCATELEGRAM_WEB_ADMIN_HOST", "127.0.0.1")
HOST = os.getenv("PCATELEGRAM_WEB_ADMIN_HOST", "0.0.0.0")
PORT = int(os.getenv("PCATELEGRAM_WEB_ADMIN_PORT", "1984"))
ADMIN_USER = os.getenv("PCATELEGRAM_WEB_ADMIN_USER", "admin")
ADMIN_PASSWORD = os.getenv("PCATELEGRAM_WEB_ADMIN_PASSWORD", "")
@@ -70,6 +69,17 @@ TRAFFIC_WINDOWS = {
}
def load_admin_password_file() -> str:
path = Path(os.getenv("PCATELEGRAM_WEB_ADMIN_AUTH_FILE", "/root/pcatelegram_web-admin.password"))
try:
for line in path.read_text(encoding="utf-8").splitlines():
if line.startswith("password="):
return line.split("=", 1)[1].strip()
except OSError:
return ""
return ""
def utc_now() -> str:
return datetime.now(timezone.utc).isoformat()
@@ -1288,7 +1298,7 @@ class AdminHandler(BaseHTTPRequestHandler):
print("%s - %s" % (self.address_string(), fmt % args))
def auth_enabled(self) -> bool:
return bool(ADMIN_PASSWORD)
return bool(ADMIN_PASSWORD or load_admin_password_file())
def is_authorized(self) -> bool:
if not self.auth_enabled():
@@ -1301,7 +1311,8 @@ class AdminHandler(BaseHTTPRequestHandler):
username, password = decoded.split(":", 1)
except Exception:
return False
return hmac.compare_digest(username, ADMIN_USER) and hmac.compare_digest(password, ADMIN_PASSWORD)
expected_password = ADMIN_PASSWORD or load_admin_password_file()
return hmac.compare_digest(username, ADMIN_USER) and hmac.compare_digest(password, expected_password)
def require_auth(self) -> bool:
if self.is_authorized():

View File

@@ -902,8 +902,9 @@ install_admin_web() {
chmod 755 "$ADMIN_WEB_DIR/server.py" "$ADMIN_WEB_DIR/static"
rm -f "$ADMIN_WEB_DIR/token" 2>/dev/null || true
local python_bin
local python_bin admin_password
python_bin=$(command -v python3)
admin_password=$(ensure_admin_web_password)
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << SVCEOF
[Unit]
Description=PCAtelegram_web v${PCATELEGRAM_WEB_VERSION} Local Web Admin
@@ -917,6 +918,8 @@ Restart=always
RestartSec=5
Environment=PCATELEGRAM_WEB_ADMIN_HOST=$ADMIN_WEB_HOST
Environment=PCATELEGRAM_WEB_ADMIN_PORT=$ADMIN_WEB_PORT
Environment=PCATELEGRAM_WEB_ADMIN_USER=${PCATELEGRAM_WEB_ADMIN_USER:-admin}
Environment=PCATELEGRAM_WEB_ADMIN_PASSWORD=$admin_password
[Install]
WantedBy=multi-user.target
@@ -928,7 +931,8 @@ SVCEOF
if type install_stats_collector &>/dev/null; then
install_stats_collector >/dev/null 2>&1 || log_warning "stats collector was not started; open Web Admin traffic page and use Repair"
fi
log_success "Web admin installed: ${ADMIN_WEB_HOST}:${ADMIN_WEB_PORT}"
log_success "Web admin installed: http://$(get_server_ip):${ADMIN_WEB_PORT}/"
log_info "Web admin login saved: $ADMIN_WEB_AUTH_FILE"
}
auto_install_admin_web_if_possible() {

View File

@@ -15,6 +15,32 @@ PCATELEGRAM_WEB_DIR="/opt/pcatelegram_web"
ADMIN_WEB_DIR="/opt/pcatelegram_web-admin"
ADMIN_WEB_SERVICE="pcatelegram_web-admin"
ADMIN_WEB_PORT="1984"
ADMIN_WEB_HOST="0.0.0.0"
ADMIN_WEB_AUTH_FILE="/root/pcatelegram_web-admin.password"
ensure_admin_web_password() {
local pw=""
if [ -n "${PCATELEGRAM_WEB_ADMIN_PASSWORD:-}" ]; then
pw="$PCATELEGRAM_WEB_ADMIN_PASSWORD"
elif [ -f "$ADMIN_WEB_AUTH_FILE" ] && [ -s "$ADMIN_WEB_AUTH_FILE" ]; then
pw=$(sed -n 's/^password=//p' "$ADMIN_WEB_AUTH_FILE" | head -1)
fi
if [ -z "$pw" ]; then
if command -v openssl >/dev/null 2>&1; then
pw=$(openssl rand -base64 24 | tr -d '\n')
else
pw=$(head -c 24 /dev/urandom | base64 | tr -d '\n')
fi
fi
umask 077
cat > "$ADMIN_WEB_AUTH_FILE" <<EOF
user=${PCATELEGRAM_WEB_ADMIN_USER:-admin}
password=${pw}
url=http://$(hostname -I 2>/dev/null | awk '{print $1}'):${ADMIN_WEB_PORT}/
EOF
chmod 600 "$ADMIN_WEB_AUTH_FILE" 2>/dev/null || true
printf '%s' "$pw"
}
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Запустите с sudo.${NC}"
@@ -128,6 +154,7 @@ if [ -f "$SCRIPT_DIR/admin-web/server.py" ]; then
rm -f "$ADMIN_WEB_DIR/token" 2>/dev/null || true
PYTHON_BIN=$(command -v python3)
ADMIN_WEB_PASSWORD=$(ensure_admin_web_password)
cat > "/etc/systemd/system/${ADMIN_WEB_SERVICE}.service" << EOF
[Unit]
Description=PCAtelegram_web v2.5.0 Local Web Admin
@@ -139,8 +166,10 @@ WorkingDirectory=$ADMIN_WEB_DIR
ExecStart=$PYTHON_BIN $ADMIN_WEB_DIR/server.py
Restart=always
RestartSec=5
Environment=PCATELEGRAM_WEB_ADMIN_HOST=127.0.0.1
Environment=PCATELEGRAM_WEB_ADMIN_HOST=$ADMIN_WEB_HOST
Environment=PCATELEGRAM_WEB_ADMIN_PORT=$ADMIN_WEB_PORT
Environment=PCATELEGRAM_WEB_ADMIN_USER=${PCATELEGRAM_WEB_ADMIN_USER:-admin}
Environment=PCATELEGRAM_WEB_ADMIN_PASSWORD=$ADMIN_WEB_PASSWORD
[Install]
WantedBy=multi-user.target

View File

@@ -20,8 +20,9 @@ LOG_FILE="/var/log/pcatelegram_web.log"
BOT_DIR="/opt/pcatelegram_web-bot"
ADMIN_WEB_DIR="/opt/pcatelegram_web-admin"
ADMIN_WEB_SERVICE="pcatelegram_web-admin"
ADMIN_WEB_HOST="127.0.0.1"
ADMIN_WEB_HOST="0.0.0.0"
ADMIN_WEB_PORT="1984"
ADMIN_WEB_AUTH_FILE="/root/pcatelegram_web-admin.password"
# ── V1 совместимость ─────────────────────────────────────────────────────────
V1_CONTAINER_NAME="mtproto-proxy"
@@ -738,3 +739,29 @@ init_dirs() {
mkdir -p "$PCATELEGRAM_WEB_DIR" "$BACKUP_DIR" /etc/telemt 2>/dev/null
touch "$LOG_FILE" 2>/dev/null
}
ensure_admin_web_password() {
local pw=""
if [ -n "${PCATELEGRAM_WEB_ADMIN_PASSWORD:-}" ]; then
pw="$PCATELEGRAM_WEB_ADMIN_PASSWORD"
elif [ -f "$ADMIN_WEB_AUTH_FILE" ] && [ -s "$ADMIN_WEB_AUTH_FILE" ]; then
pw=$(sed -n 's/^password=//p' "$ADMIN_WEB_AUTH_FILE" | head -1)
fi
if [ -z "$pw" ]; then
if command -v openssl >/dev/null 2>&1; then
pw=$(openssl rand -base64 24 | tr -d '\n')
else
pw=$(head -c 24 /dev/urandom | base64 | tr -d '\n')
fi
fi
umask 077
cat > "$ADMIN_WEB_AUTH_FILE" <<EOF
user=${PCATELEGRAM_WEB_ADMIN_USER:-admin}
password=${pw}
url=http://$(get_server_ip 2>/dev/null || hostname -I 2>/dev/null | awk '{print $1}'):${ADMIN_WEB_PORT}/
EOF
chmod 600 "$ADMIN_WEB_AUTH_FILE" 2>/dev/null || true
printf '%s' "$pw"
}