Last active
October 12, 2025 18:13
-
-
Save bibendi/8ed34b528313ac9dfa1bcba82e65f44a to your computer and use it in GitHub Desktop.
Linux Shadowsocks Client Proxy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| IFS=$'\n\t' | |
| # 1) Установить privoxy (если ещё не установлен) | |
| sudo apt update | |
| sudo apt install -y privoxy | |
| # 2) Бэкап текущего конфига | |
| sudo cp /etc/privoxy/config /etc/privoxy/config.bak | |
| # 3) Прописать listen-address 0.0.0.0:8118 (заменит существующую строку или добавит) | |
| sudo sed -i '/^listen-address/ d' /etc/privoxy/config | |
| echo "listen-address 0.0.0.0:8118" | sudo tee -a /etc/privoxy/config >/dev/null | |
| # 4) Добавить forward-socks5t правило (перенаправлять через локальный SOCKS5 127.0.0.1:1080) | |
| # Если строка уже есть — команда добавит ещё одну (это безопасно), можно удалить дубликаты вручную при необходимости. | |
| grep -q "^forward-socks5t / 127.0.0.1:1080 \\." /etc/privoxy/config || \ | |
| echo "forward-socks5t / 127.0.0.1:1080 ." | sudo tee -a /etc/privoxy/config >/dev/null | |
| # 5) Перезапустить privoxy | |
| sudo systemctl restart privoxy | |
| sudo systemctl enable privoxy | |
| # --- тест подключения --- | |
| echo | |
| echo "→ Тестируем внешний IP через SOCKS5 127.0.0.1:1080" | |
| IP_BEFORE=$(curl -s https://api.ipify.org || echo "нет сети") | |
| IP_AFTER=$(curl -s -x 127.0.0.1:8118 https://api.ipify.org || echo "нет прокси") | |
| echo " IP без прокси : $IP_BEFORE" | |
| echo " IP через SOCKS: $IP_AFTER" | |
| if [[ "$IP_AFTER" != "$IP_BEFORE" && -n "$IP_AFTER" ]]; then | |
| echo | |
| echo "✅ Готово — трафик идёт через $SERVER (виден внешний IP прокси)." | |
| else | |
| echo | |
| echo "⚠️ Внимание: IP не изменился. Проверь пароль/порт/доступность сервера." | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| IFS=$'\n\t' | |
| CONFIG_DIR="/etc/shadowsocks-libev" | |
| CONFIG_FILE="$CONFIG_DIR/config.json" | |
| SERVICE_CLIENT="shadowsocks-local.service" | |
| SERVICE_SERVER="shadowsocks-libev.service" | |
| banner(){ echo -e "\n=== $1 ==="; } | |
| banner "Установка Shadowsocks-libev (клиент) — простая версия (без obfs)" | |
| read -rp "Вставь ss:// ссылку (из Outline Manager или аналог): " SSURL | |
| if [[ ! "$SSURL" =~ ^ss:// ]]; then | |
| echo "Ошибка: строка должна начинаться с ss://" | |
| exit 1 | |
| fi | |
| banner "Установка пакетов..." | |
| apt update -y | |
| apt install -y shadowsocks-libev curl || { echo "Ошибка установки пакетов"; exit 1; } | |
| # --- парсим ss:// --- | |
| # убираем префикс и возможный ?outline=1 | |
| TMP=$(echo "$SSURL" | sed -E 's#^ss://##; s#/?outline=1##; s#/$##') | |
| USERINFO=${TMP%@*} | |
| HOSTPART=${TMP#*@} | |
| # Попытка декодировать userinfo как base64(method:password) | |
| DECODED=$(echo "$USERINFO" | sed 's/-/+/g; s/_/\//g' | base64 -d 2>/dev/null || true) | |
| if [[ "$DECODED" == *:* ]]; then | |
| METHOD=${DECODED%%:*} | |
| PASSWORD=${DECODED#*:} | |
| else | |
| # формат method:password@host:port (не base64) | |
| METHOD=${USERINFO%%:*} | |
| PASSWORD=${USERINFO#*:} | |
| fi | |
| # Сервер и порт (порт может содержать /..., отрезаем) | |
| SERVER=$(echo "$HOSTPART" | cut -d: -f1) | |
| PORT=$(echo "$HOSTPART" | cut -d: -f2 | cut -d'/' -f1) | |
| # валидация | |
| if [[ -z "$SERVER" || -z "$PORT" || -z "$PASSWORD" || -z "$METHOD" ]]; then | |
| echo "Ошибка парсинга ss:// строки. Проверь формат." | |
| exit 1 | |
| fi | |
| echo | |
| echo "→ Параметры:" | |
| echo " server = $SERVER" | |
| echo " port = $PORT" | |
| echo " method = $METHOD" | |
| # --- создаём конфиг (plain, без obfs) --- | |
| echo | |
| echo "→ Пишем конфиг в $CONFIG_FILE" | |
| mkdir -p "$CONFIG_DIR" | |
| cat > /tmp/ss-config.json <<EOF | |
| { | |
| "server": "$SERVER", | |
| "server_port": $PORT, | |
| "local_address": "0.0.0.0", | |
| "local_port": 1080, | |
| "password": "$PASSWORD", | |
| "method": "$METHOD", | |
| "mode": "tcp_and_udp" | |
| } | |
| EOF | |
| # перемещаем в /etc с правами | |
| mv /tmp/ss-config.json "$CONFIG_FILE" | |
| chmod 644 "$CONFIG_FILE" | |
| chown root:root "$CONFIG_FILE" | |
| chmod 755 "$CONFIG_DIR" | |
| # --- отключаем серверный юнит, если он активен (чтобы не конфликтовал) --- | |
| if systemctl list-unit-files | grep -q "^${SERVICE_SERVER}"; then | |
| if systemctl is-active --quiet "${SERVICE_SERVER}"; then | |
| echo "→ Отключаем и останавливаем серверный юнит ${SERVICE_SERVER} (чтобы не мешал клиенту)" | |
| systemctl disable --now "${SERVICE_SERVER}" || true | |
| fi | |
| fi | |
| # --- создаём unit для клиента --- | |
| echo | |
| echo "→ Создаём systemd‑юнит $SERVICE_CLIENT" | |
| cat > /etc/systemd/system/${SERVICE_CLIENT} <<'UNIT' | |
| [Unit] | |
| Description=Shadowsocks-libev local (client) | |
| After=network-online.target | |
| Wants=network-online.target | |
| [Service] | |
| ExecStart=/usr/bin/ss-local -c /etc/shadowsocks-libev/config.json | |
| Restart=always | |
| User=root | |
| NoNewPrivileges=true | |
| [Install] | |
| WantedBy=multi-user.target | |
| UNIT | |
| # Перезагрузка systemd и запуск | |
| systemctl daemon-reload | |
| systemctl enable --now "${SERVICE_CLIENT}" | |
| sleep 2 | |
| if systemctl is-active --quiet "${SERVICE_CLIENT}"; then | |
| echo "✅ Служба ${SERVICE_CLIENT} запущена" | |
| else | |
| echo "❌ Не удалось запустить ${SERVICE_CLIENT}. Смотри лог:" | |
| journalctl -u "${SERVICE_CLIENT}" -n 50 --no-pager | |
| exit 1 | |
| fi | |
| # --- тест подключения --- | |
| echo | |
| echo "→ Тестируем внешний IP через SOCKS5 127.0.0.1:1080" | |
| IP_BEFORE=$(curl -s https://api.ipify.org || echo "нет сети") | |
| IP_AFTER=$(curl -s --socks5 127.0.0.1:1080 https://api.ipify.org || echo "нет прокси") | |
| echo " IP без прокси : $IP_BEFORE" | |
| echo " IP через SOCKS: $IP_AFTER" | |
| if [[ "$IP_AFTER" != "$IP_BEFORE" && -n "$IP_AFTER" ]]; then | |
| echo | |
| echo "✅ Готово — трафик идёт через $SERVER (виден внешний IP прокси)." | |
| else | |
| echo | |
| echo "⚠️ Внимание: IP не изменился. Проверь пароль/порт/доступность сервера." | |
| echo "Просмотр последних логов службы:" | |
| journalctl -u "${SERVICE_CLIENT}" -n 50 --no-pager | |
| fi | |
| echo | |
| echo "Файл конфига: $CONFIG_FILE" | |
| echo "Юнит службы : /etc/systemd/system/${SERVICE_CLIENT}" | |
| echo "Локальный SOCKS5: 127.0.0.1:1080" | |
| echo |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| SERVICE = shadowsocks-local | |
| CONFIG = /etc/shadowsocks-libev/config.json | |
| GREEN = \033[0;32m | |
| RED = \033[0;31m | |
| RESET = \033[0m | |
| .PHONY: help install start stop status enable disable test logs | |
| help: | |
| @echo "Доступные цели:" | |
| @echo " make install – установить и настроить клиент" | |
| @echo " make start – запустить службу" | |
| @echo " make stop – остановить службу" | |
| @echo " make status – показать состояние" | |
| @echo " make enable – включить автозапуск" | |
| @echo " make disable – выключить автозапуск" | |
| @echo " make test – проверить IP‑адрес через SOCKS" | |
| @echo " make logs – последние строки лога" | |
| install: | |
| @bash ./install-ss-client.sh | |
| @bash ./install-privoxy.sh | |
| start: | |
| sudo systemctl start $(SERVICE) | |
| stop: | |
| sudo systemctl stop $(SERVICE) | |
| status: | |
| sudo systemctl status $(SERVICE) --no-pager | |
| enable: | |
| sudo systemctl enable $(SERVICE) | |
| disable: | |
| sudo systemctl disable $(SERVICE) | |
| test: | |
| @echo "Проверяем IP..." | |
| @IP_NORMAL=$$(curl -s https://api.ipify.org); \ | |
| IP_PROXY=$$(curl -s -x 127.0.0.1:8118 https://api.ipify.org); \ | |
| echo "IP без прокси : $$IP_NORMAL"; \ | |
| echo "IP через прокси: $$IP_PROXY"; \ | |
| if [ "$$IP_NORMAL" != "$$IP_PROXY" ] && [ -n "$$IP_PROXY" ]; then \ | |
| echo -e "$(GREEN)✅ ОК — соединение через Outline$(RESET)"; \ | |
| else \ | |
| echo -e "$(RED)❌ FAIL — IP не изменился$(RESET)"; \ | |
| fi | |
| logs: | |
| sudo journalctl -u $(SERVICE) -n 50 --no-pager |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment