Link setup choices across server scripts
This commit is contained in:
parent
feaa85a39b
commit
ab7d3f6e03
6 changed files with 188 additions and 40 deletions
20
README.md
20
README.md
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
| Файл | Назначение | Можно запускать отдельно |
|
||||
| --- | --- | --- |
|
||||
| `ochenstarik-server-1.sh` | Создаёт swap-файл 2 ГБ и задаёт `vm.swappiness=20` | Да |
|
||||
| `ochenstarik-server-2.sh` | Обновляет систему, ставит серверные и офисные пакеты, настраивает часовой пояс и UFW | Да |
|
||||
| `ochenstarik-server-user-3.sh` | Создаёт администратора, позволяет выбрать SSH-порт, включает fail2ban или отдельно добавляет правила UFW | После установки необходимых пакетов; проще всего сначала запустить скрипт 2 |
|
||||
| `ochenstarik-server-1.sh` | Предлагает выбрать часовой пояс, создаёт swap-файл 2 ГБ и задаёт `vm.swappiness=20` | Да |
|
||||
| `ochenstarik-server-2.sh` | Предлагает выбрать будущий SSH-порт, обновляет систему, ставит пакеты и настраивает UFW | Да |
|
||||
| `ochenstarik-server-user-3.sh` | Создаёт администратора, переносит SSH на порт из этапа 2, проверяет права и включает fail2ban | После установки необходимых пакетов; проще всего сначала запустить скрипт 2 |
|
||||
| `ochenstarik-server-tg-4.sh` | Отправляет уведомления в Telegram при успешном входе по SSH | После установки OpenSSH и `curl`; обычно после скрипта 2 или 3 |
|
||||
| `ochenstarik-server-vpn-5.sh` | Устанавливает Xray и направляет системный трафик через VLESS + REALITY | Да; зависимости устанавливаются автоматически |
|
||||
|
||||
|
|
@ -37,11 +37,11 @@ chmod 700 ./*.sh
|
|||
bash -n ./ИМЯ-СКРИПТА.sh
|
||||
```
|
||||
|
||||
## 1. Настройка swap
|
||||
## 1. Часовой пояс и настройка swap
|
||||
|
||||
Файл: `ochenstarik-server-1.sh`.
|
||||
|
||||
Создаёт `/swapfile` размером 2 ГБ, добавляет его в `/etc/fstab` и устанавливает `vm.swappiness=20`. Повторный запуск предусмотрен.
|
||||
Сначала предлагает ввести часовой пояс в формате IANA, например `Asia/Novosibirsk`, `Europe/Moscow` или `UTC`, и проверяет его через `timedatectl`. Затем создаёт `/swapfile` размером 2 ГБ, добавляет его в `/etc/fstab` и устанавливает `vm.swappiness=20`. Повторный запуск предусмотрен.
|
||||
|
||||
```bash
|
||||
curl -fLO https://raw.githubusercontent.com/ochenstarik-ui/lightweight-server/main/ochenstarik-server-1.sh
|
||||
|
|
@ -61,12 +61,12 @@ sysctl vm.swappiness
|
|||
|
||||
Файл: `ochenstarik-server-2.sh`.
|
||||
|
||||
Скрипт обновляет систему, устанавливает OpenSSH, UFW, fail2ban, инструменты обработки документов, изображений, аудио и видео, а также задаёт часовой пояс `Asia/Novosibirsk`.
|
||||
Скрипт запрашивает SSH-порт, который будет применён на этапе 3, сохраняет его в `/etc/ochenstarik-server/ssh-port.conf`, обновляет систему и устанавливает OpenSSH, UFW, fail2ban, инструменты обработки документов, изображений, аудио и видео.
|
||||
|
||||
Открываются TCP-порты:
|
||||
|
||||
- `22` — временный SSH-порт;
|
||||
- `20202` — новый SSH-порт;
|
||||
- выбранный SSH-порт — будущий порт SSH;
|
||||
- `80`, `443` — HTTP и HTTPS;
|
||||
- `2096`, `40000`, `63636` — порты приложений.
|
||||
|
||||
|
|
@ -93,10 +93,12 @@ timedatectl
|
|||
1. новая установка или повторная настройка администратора и SSH;
|
||||
2. только добавление открытых портов в UFW без изменения пользователя и SSH.
|
||||
|
||||
В режиме новой установки скрипт интерактивно запрашивает имя администратора, SSH-порт, SSH-ключ и пароль. Затем он:
|
||||
В режиме новой установки скрипт интерактивно запрашивает имя администратора, SSH-ключ и пароль. SSH-порт автоматически читается из защищённого файла, созданного этапом 2. Если этап 2 не выполнялся, скрипт предложит выбрать порт вручную. Затем он:
|
||||
|
||||
- создаёт или обновляет пользователя;
|
||||
- добавляет пользователя в группу `sudo`;
|
||||
- назначает пользователю его домашнюю папку и всё содержимое `.ssh`;
|
||||
- устанавливает права `700` для `.ssh` и `600` для `authorized_keys` и остальных файлов ключей;
|
||||
- запрещает вход `root` по SSH;
|
||||
- переносит SSH на выбранный порт и добавляет для него правило UFW;
|
||||
- настраивает fail2ban;
|
||||
|
|
@ -162,7 +164,7 @@ sudo tail -f /var/log/ochenstarik-ssh-login-telegram.log
|
|||
|
||||
Файл: `ochenstarik-server-vpn-5.sh`.
|
||||
|
||||
Скрипт устанавливает Xray и необходимые пакеты, принимает прямую ссылку `vless://` либо HTTPS-ссылку подписки 3x-ui и настраивает маршрутизацию через `nftables`. Поддерживается VLESS с транспортом TCP/RAW и REALITY.
|
||||
Скрипт устанавливает Xray и необходимые пакеты, принимает прямую ссылку `vless://` либо HTTPS-ссылку подписки 3x-ui и настраивает маршрутизацию через `nftables`. Если подписка содержит VLESS-ссылки на нескольких портах, скрипт выводит доступные порты и просит выбрать нужный. Поддерживается VLESS с транспортом TCP/RAW и REALITY.
|
||||
|
||||
```bash
|
||||
curl -fLO https://raw.githubusercontent.com/ochenstarik-ui/lightweight-server/main/ochenstarik-server-vpn-5.sh
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Актуальная инструкция находится в README.md:
|
||||
https://github.com/ochenstarik-ui/lightweight-server#readme
|
||||
|
||||
Можно установить только нужный модуль. Пример для базовой настройки:
|
||||
Можно установить только нужный модуль. Первый скрипт предлагает выбрать часовой пояс, второй — будущий SSH-порт, а пятый — порт VLESS из подписки. Пример для базовой настройки:
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y curl
|
||||
|
|
|
|||
|
|
@ -7,13 +7,34 @@ readonly SWAPPINESS="20"
|
|||
readonly SYSCTL_FILE="/etc/sysctl.d/60-hermes-swap.conf"
|
||||
|
||||
log() { printf '[+] %s\n' "$*"; }
|
||||
warn() { printf '[!] %s\n' "$*" >&2; }
|
||||
die() { printf '[x] %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
choose_timezone() {
|
||||
local current_timezone timezone
|
||||
|
||||
current_timezone="$(timedatectl show --property=Timezone --value 2>/dev/null || true)"
|
||||
current_timezone="${current_timezone:-Asia/Novosibirsk}"
|
||||
printf 'Select an IANA timezone, for example Asia/Novosibirsk, Europe/Moscow or UTC.\n'
|
||||
while :; do
|
||||
read -rp "Timezone [${current_timezone}]: " timezone
|
||||
timezone="${timezone:-$current_timezone}"
|
||||
if timedatectl list-timezones | grep -Fqx -- "$timezone"; then
|
||||
timedatectl set-timezone "$timezone"
|
||||
log "Timezone set to ${timezone}"
|
||||
return 0
|
||||
fi
|
||||
warn "Unknown timezone: $timezone"
|
||||
done
|
||||
}
|
||||
|
||||
[[ "$EUID" -eq 0 ]] || die "Run this script as root"
|
||||
for command_name in awk blkid fallocate mkswap swapon sysctl; do
|
||||
for command_name in awk blkid fallocate grep mkswap swapon sysctl timedatectl; do
|
||||
command -v "$command_name" >/dev/null 2>&1 || die "Required command not found: $command_name"
|
||||
done
|
||||
|
||||
choose_timezone
|
||||
|
||||
log "Configuring ${SWAPSIZE} swap file"
|
||||
if [[ ! -e "$SWAPFILE" ]]; then
|
||||
fallocate -l "$SWAPSIZE" "$SWAPFILE"
|
||||
|
|
@ -44,5 +65,6 @@ chmod 644 "$SYSCTL_FILE"
|
|||
sysctl -p "$SYSCTL_FILE" >/dev/null
|
||||
|
||||
log "Server memory setup is complete"
|
||||
printf 'Timezone: %s\n' "$(timedatectl show --property=Timezone --value)"
|
||||
swapon --show
|
||||
printf '\nNow run ochenstarik-server-2.sh as root.\n'
|
||||
|
|
@ -1,13 +1,47 @@
|
|||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
readonly SSH_PORT="20202"
|
||||
readonly TIMEZONE="Asia/Novosibirsk"
|
||||
readonly SSH_PORT_CONFIG="/etc/ochenstarik-server/ssh-port.conf"
|
||||
readonly DEFAULT_SSH_PORT="20202"
|
||||
|
||||
log() { printf '[+] %s\n' "$*"; }
|
||||
warn() { printf '[!] %s\n' "$*" >&2; }
|
||||
die() { printf '[x] %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
is_valid_port() {
|
||||
local port="$1"
|
||||
[[ "$port" =~ ^[0-9]{1,5}$ ]] || return 1
|
||||
(( 10#$port >= 1 && 10#$port <= 65535 ))
|
||||
}
|
||||
|
||||
choose_ssh_port() {
|
||||
local default_port="$DEFAULT_SSH_PORT" saved_port selected_port
|
||||
|
||||
if [[ -e "$SSH_PORT_CONFIG" ]]; then
|
||||
[[ -f "$SSH_PORT_CONFIG" && ! -L "$SSH_PORT_CONFIG" ]] \
|
||||
|| die "$SSH_PORT_CONFIG must be a regular non-symlink file"
|
||||
saved_port="$(sed -n 's/^SSH_PORT=//p' "$SSH_PORT_CONFIG" | head -n1 | tr -d '\r')"
|
||||
if is_valid_port "$saved_port"; then
|
||||
default_port="$((10#$saved_port))"
|
||||
else
|
||||
warn "Ignoring invalid saved SSH port: ${saved_port:-empty}"
|
||||
fi
|
||||
fi
|
||||
|
||||
while :; do
|
||||
read -rp "SSH port for step 3 [${default_port}]: " selected_port
|
||||
selected_port="${selected_port:-$default_port}"
|
||||
if is_valid_port "$selected_port"; then
|
||||
SSH_PORT="$((10#$selected_port))"
|
||||
return 0
|
||||
fi
|
||||
warn "SSH port must be a number between 1 and 65535"
|
||||
done
|
||||
}
|
||||
|
||||
[[ "$EUID" -eq 0 ]] || die "Run this script as root"
|
||||
SSH_PORT=""
|
||||
choose_ssh_port
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
log "Updating the operating system"
|
||||
|
|
@ -23,11 +57,14 @@ apt-get install -y \
|
|||
ffmpeg mediainfo p7zip-full unzip zip unrar jq yq csvkit sqlite3 \
|
||||
python3-pip python3-venv mc
|
||||
|
||||
log "Setting timezone to ${TIMEZONE}"
|
||||
timedatectl set-timezone "$TIMEZONE"
|
||||
install -d -m 700 -o root -g root "$(dirname "$SSH_PORT_CONFIG")"
|
||||
printf 'SSH_PORT=%s\n' "$SSH_PORT" > "$SSH_PORT_CONFIG"
|
||||
chown root:root "$SSH_PORT_CONFIG"
|
||||
chmod 600 "$SSH_PORT_CONFIG"
|
||||
log "Saved SSH port ${SSH_PORT} for step 3"
|
||||
|
||||
log "Configuring UFW"
|
||||
# Keep port 22 open until step 3 moves SSH to 20202 and the new login is tested.
|
||||
# Keep port 22 open until step 3 moves SSH to the selected port and the new login is tested.
|
||||
ufw allow "22/tcp"
|
||||
ufw allow "${SSH_PORT}/tcp"
|
||||
ufw allow "80/tcp"
|
||||
|
|
@ -41,5 +78,6 @@ log "Installed versions"
|
|||
printf 'Timezone: %s\n' "$(timedatectl show --property=Timezone --value)"
|
||||
ufw status verbose
|
||||
|
||||
printf '\nDone. Now run ochenstarik-server-3.sh as root.\n'
|
||||
printf '\nDone. Now run ochenstarik-server-user-3.sh as root.\n'
|
||||
printf 'Step 3 will move SSH to port %s.\n' "$SSH_PORT"
|
||||
printf 'Do not remove the UFW rule for port 22 until SSH login on port %s succeeds.\n' "$SSH_PORT"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ readonly ENV_FILE="${ENV_FILE:-/root/setup-data/env.txt}"
|
|||
readonly HASH_FILE="${HASH_FILE:-/root/setup-data/password.hash}"
|
||||
readonly SSHD_DROPIN="/etc/ssh/sshd_config.d/00-hermes-hardening.conf"
|
||||
readonly FAIL2BAN_JAIL="/etc/fail2ban/jail.d/hermes.local"
|
||||
readonly SSH_PORT_CONFIG="/etc/ochenstarik-server/ssh-port.conf"
|
||||
|
||||
log() { printf '[+] %s\n' "$*"; }
|
||||
warn() { printf '[!] %s\n' "$*" >&2; }
|
||||
|
|
@ -151,7 +152,7 @@ add_ufw_ports_interactive() {
|
|||
}
|
||||
|
||||
collect_user_configuration() {
|
||||
local new_username ssh_port default_ssh_port saved_ssh_port
|
||||
local new_username ssh_port default_ssh_port saved_ssh_port selected_step2_port
|
||||
local ssh_public_key pass pass2 candidate_uid
|
||||
local key_method source_username source_home source_key_file candidate_key key_test
|
||||
|
||||
|
|
@ -174,13 +175,23 @@ collect_user_configuration() {
|
|||
done
|
||||
|
||||
default_ssh_port="20202"
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
if [[ -e "$SSH_PORT_CONFIG" ]]; then
|
||||
[[ -f "$SSH_PORT_CONFIG" && ! -L "$SSH_PORT_CONFIG" ]] \
|
||||
|| die "$SSH_PORT_CONFIG must be a regular non-symlink file"
|
||||
selected_step2_port="$(sed -n 's/^SSH_PORT=//p' "$SSH_PORT_CONFIG" | head -n1 | tr -d '\r')"
|
||||
is_valid_port "$selected_step2_port" \
|
||||
|| die "Invalid SSH port in $SSH_PORT_CONFIG"
|
||||
ssh_port="$((10#$selected_step2_port))"
|
||||
log "Using SSH port ${ssh_port} selected in step 2"
|
||||
elif [[ -f "$ENV_FILE" ]]; then
|
||||
saved_ssh_port="$(read_env_value SSH_PORT)"
|
||||
if is_valid_port "$saved_ssh_port"; then
|
||||
default_ssh_port="$saved_ssh_port"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${ssh_port:-}" ]]; then
|
||||
warn "The SSH port from step 2 was not found; select it now"
|
||||
while :; do
|
||||
read -rp "SSH port [${default_ssh_port}]: " ssh_port
|
||||
ssh_port="${ssh_port:-$default_ssh_port}"
|
||||
|
|
@ -190,6 +201,7 @@ collect_user_configuration() {
|
|||
fi
|
||||
warn "SSH port must be a number between 1 and 65535"
|
||||
done
|
||||
fi
|
||||
|
||||
while :; do
|
||||
printf '\nSSH key setup:\n'
|
||||
|
|
@ -329,7 +341,7 @@ fi
|
|||
|
||||
log "Checking packages installed by step 2"
|
||||
|
||||
for command_name in sshd ssh-keygen visudo systemctl; do
|
||||
for command_name in find sshd ssh-keygen visudo systemctl; do
|
||||
require_command "$command_name"
|
||||
done
|
||||
|
||||
|
|
@ -370,13 +382,28 @@ user_group="$(id -gn "$NEW_USERNAME")"
|
|||
# every run so an existing user can be fixed by running this script again.
|
||||
chown "$NEW_USERNAME:$user_group" "$user_home"
|
||||
chmod 750 "$user_home"
|
||||
[[ ! -L "$user_home/.ssh" ]] || die "Refusing to use a symbolic link as $user_home/.ssh"
|
||||
install -d -m 700 -o "$NEW_USERNAME" -g "$user_group" "$user_home/.ssh"
|
||||
[[ ! -L "$user_home/.ssh/authorized_keys" ]] \
|
||||
|| die "Refusing to use a symbolic link as $user_home/.ssh/authorized_keys"
|
||||
touch -- "$user_home/.ssh/authorized_keys"
|
||||
chown "$NEW_USERNAME:$user_group" "$user_home/.ssh/authorized_keys"
|
||||
chmod 600 "$user_home/.ssh/authorized_keys"
|
||||
if ! grep -Fqx -- "$SSH_PUBLIC_KEY" "$user_home/.ssh/authorized_keys"; then
|
||||
printf '%s\n' "$SSH_PUBLIC_KEY" >> "$user_home/.ssh/authorized_keys"
|
||||
fi
|
||||
chown -R --no-dereference "$NEW_USERNAME:$user_group" "$user_home/.ssh"
|
||||
find "$user_home/.ssh" -xdev -type d -exec chmod 700 {} +
|
||||
find "$user_home/.ssh" -xdev -type f -exec chmod 600 {} +
|
||||
|
||||
id -nG "$NEW_USERNAME" | tr ' ' '\n' | grep -Fqx sudo \
|
||||
|| die "$NEW_USERNAME was not added to the sudo group"
|
||||
[[ "$(stat -c '%U:%G' "$user_home/.ssh")" == "$NEW_USERNAME:$user_group" ]] \
|
||||
|| die "Incorrect owner for $user_home/.ssh"
|
||||
[[ "$(stat -c '%a' "$user_home/.ssh")" == 700 ]] \
|
||||
|| die "Incorrect permissions for $user_home/.ssh"
|
||||
[[ "$(stat -c '%U:%G' "$user_home/.ssh/authorized_keys")" == "$NEW_USERNAME:$user_group" ]] \
|
||||
|| die "Incorrect owner for authorized_keys"
|
||||
[[ "$(stat -c '%a' "$user_home/.ssh/authorized_keys")" == 600 ]] \
|
||||
|| die "Incorrect permissions for authorized_keys"
|
||||
|
||||
if command -v restorecon >/dev/null 2>&1; then
|
||||
restorecon -RF "$user_home/.ssh" || warn "SELinux context could not be restored"
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ printf '\n'
|
|||
TMP_DIR="$(mktemp -d)"
|
||||
chmod 700 "$TMP_DIR"
|
||||
RAW_FILE="${TMP_DIR}/subscription.txt"
|
||||
LINKS_FILE="${TMP_DIR}/vless-links.txt"
|
||||
LINK_FILE="${TMP_DIR}/vless-link.txt"
|
||||
PORTS_FILE="${TMP_DIR}/vless-ports.txt"
|
||||
GENERATED_CONFIG="${TMP_DIR}/config.json"
|
||||
INSTALLER_FILE="${TMP_DIR}/install-release.sh"
|
||||
|
||||
|
|
@ -98,36 +100,93 @@ fi
|
|||
unset SUBSCRIPTION_INPUT
|
||||
chmod 600 "$RAW_FILE"
|
||||
|
||||
python3 - "$RAW_FILE" "$LINK_FILE" <<'PY'
|
||||
python3 - "$RAW_FILE" "$LINKS_FILE" "$PORTS_FILE" <<'PY'
|
||||
import base64
|
||||
import pathlib
|
||||
import sys
|
||||
import urllib.parse
|
||||
|
||||
raw = pathlib.Path(sys.argv[1]).read_text(encoding="utf-8").strip()
|
||||
|
||||
def find_vless(text: str):
|
||||
result = []
|
||||
for line in text.replace("\r", "").split("\n"):
|
||||
line = line.strip()
|
||||
if line.startswith("vless://"):
|
||||
return line
|
||||
return None
|
||||
result.append(line)
|
||||
return result
|
||||
|
||||
link = find_vless(raw)
|
||||
if not link:
|
||||
links = find_vless(raw)
|
||||
if not links:
|
||||
try:
|
||||
padded = raw.replace("-", "+").replace("_", "/")
|
||||
padded += "=" * (-len(padded) % 4)
|
||||
decoded = base64.b64decode(padded, validate=False).decode("utf-8")
|
||||
except Exception as exc:
|
||||
raise SystemExit(f"Подписка не является Base64/VLESS: {exc}")
|
||||
link = find_vless(decoded)
|
||||
links = find_vless(decoded)
|
||||
|
||||
if not link:
|
||||
links = list(dict.fromkeys(links))
|
||||
if not links:
|
||||
raise SystemExit("В подписке не найдена ссылка vless://")
|
||||
|
||||
ports = []
|
||||
for link in links:
|
||||
try:
|
||||
port = urllib.parse.urlsplit(link).port
|
||||
except ValueError as exc:
|
||||
raise SystemExit(f"Некорректный порт в VLESS-ссылке: {exc}")
|
||||
if port is None:
|
||||
raise SystemExit("В одной из VLESS-ссылок отсутствует порт")
|
||||
if port not in ports:
|
||||
ports.append(port)
|
||||
|
||||
pathlib.Path(sys.argv[2]).write_text("\n".join(links) + "\n", encoding="utf-8")
|
||||
pathlib.Path(sys.argv[3]).write_text(
|
||||
"\n".join(str(port) for port in ports) + "\n", encoding="utf-8"
|
||||
)
|
||||
PY
|
||||
chmod 600 "$LINKS_FILE" "$PORTS_FILE"
|
||||
|
||||
mapfile -t SUBSCRIPTION_PORTS < "$PORTS_FILE"
|
||||
(( ${#SUBSCRIPTION_PORTS[@]} > 0 )) || die "В подписке не найдены доступные порты"
|
||||
printf 'Доступные порты в подписке: %s\n' "${SUBSCRIPTION_PORTS[*]}"
|
||||
|
||||
while :; do
|
||||
read -rp "Выберите порт подписки [${SUBSCRIPTION_PORTS[0]}]: " SUBSCRIPTION_PORT
|
||||
SUBSCRIPTION_PORT="${SUBSCRIPTION_PORT:-${SUBSCRIPTION_PORTS[0]}}"
|
||||
[[ "$SUBSCRIPTION_PORT" =~ ^[0-9]{1,5}$ ]] \
|
||||
&& (( 10#$SUBSCRIPTION_PORT >= 1 && 10#$SUBSCRIPTION_PORT <= 65535 )) \
|
||||
|| { warn "Порт должен быть числом от 1 до 65535"; continue; }
|
||||
SUBSCRIPTION_PORT="$((10#$SUBSCRIPTION_PORT))"
|
||||
|
||||
port_found="no"
|
||||
for available_port in "${SUBSCRIPTION_PORTS[@]}"; do
|
||||
if [[ "$SUBSCRIPTION_PORT" == "$available_port" ]]; then
|
||||
port_found="yes"
|
||||
break
|
||||
fi
|
||||
done
|
||||
[[ "$port_found" == yes ]] && break
|
||||
warn "Порт ${SUBSCRIPTION_PORT} отсутствует в подписке"
|
||||
done
|
||||
|
||||
python3 - "$LINKS_FILE" "$LINK_FILE" "$SUBSCRIPTION_PORT" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
import urllib.parse
|
||||
|
||||
links = pathlib.Path(sys.argv[1]).read_text(encoding="utf-8").splitlines()
|
||||
selected_port = int(sys.argv[3])
|
||||
for link in links:
|
||||
if urllib.parse.urlsplit(link).port == selected_port:
|
||||
pathlib.Path(sys.argv[2]).write_text(link, encoding="utf-8")
|
||||
break
|
||||
else:
|
||||
raise SystemExit(f"VLESS-ссылка для порта {selected_port} не найдена")
|
||||
PY
|
||||
chmod 600 "$LINK_FILE"
|
||||
log "Выбран порт подписки ${SUBSCRIPTION_PORT}"
|
||||
|
||||
VPN_IP="$(python3 - "$LINK_FILE" "$GENERATED_CONFIG" "$TPROXY_PORT" "$SOCKS_PORT" <<'PY'
|
||||
import json
|
||||
|
|
|
|||
Loading…
Reference in a new issue