diff --git a/.github/workflows/build_caddy.yml b/.github/workflows/build_caddy.yml index cfb48f0..339bed1 100644 --- a/.github/workflows/build_caddy.yml +++ b/.github/workflows/build_caddy.yml @@ -29,6 +29,7 @@ jobs: --with github.com/caddyserver/forwardproxy mkdir -p dist tar -czvf dist/caddy-${VERSION}.tar.gz caddy + (cd dist && sha256sum caddy-${VERSION}.tar.gz > caddy-${VERSION}.tar.gz.sha256) echo "RELEASE_TAG=${VERSION}" >> $GITHUB_ENV echo "RELEASE_NAME=Monthly Build (${DATE})" >> $GITHUB_ENV @@ -37,7 +38,9 @@ jobs: with: tag_name: ${{ env.RELEASE_TAG }} name: ${{ env.RELEASE_NAME }} - files: dist/*.tar.gz + files: | + dist/*.tar.gz + dist/*.sha256 draft: false prerelease: false update_release: true # 自动更新已有 Release(覆盖上传) diff --git a/.github/workflows/shell_quality.yml b/.github/workflows/shell_quality.yml new file mode 100644 index 0000000..7985f8c --- /dev/null +++ b/.github/workflows/shell_quality.yml @@ -0,0 +1,40 @@ +name: Shell Quality + +on: + push: + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install shellcheck + run: | + sudo apt-get update -y + sudo apt-get install -y shellcheck + + - name: Set up Go for shfmt + uses: actions/setup-go@v5 + with: + go-version: '1.21' + + - name: Install shfmt + run: | + go install mvdan.cc/sh/v3/cmd/shfmt@latest + echo "${HOME}/go/bin" >> $GITHUB_PATH + + - name: Run shellcheck + run: | + set -e + echo "Running shellcheck..." + find . -type f -name "*.sh" -print0 | xargs -0 -I{} bash -lc 'shellcheck -x "{}"' + + - name: Run shfmt diff + run: | + set -e + echo "Running shfmt..." + shfmt -d . + diff --git a/README.md b/README.md index 66ec40c..e3032da 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ Ubuntu 16.04, 18.04, 20.04, 22.04 CentOS 7 -* WSS客户端配置信息保存在: -`cat /usr/local/etc/v2ray/client.json` +* WSS客户端配置信息: + - 机器可读 JSON: `/usr/local/etc/v2ray/client.json` + - 可读文本: `/usr/local/etc/v2ray/client.txt` * Shadowsocks客户端配置信息: `cat /etc/shadowsocks/config.json` @@ -32,10 +33,33 @@ CentOS 7 * Hysteria2客户端配置信息保存在: `cat /etc/hysteria/hyclient.json` -* Https正向代理客户端配置信息保存在: -`cat /etc/caddy/https.json` +* Https正向代理客户端配置信息: + - 机器可读 JSON: `/etc/caddy/https.json` + - 可读文本: `/etc/caddy/https.txt` 卸载方法如下: https://1024.day/d/1296 **提醒:连不上的朋友,建议先检查一下服务器自带防火墙有没有关闭?** + +环境变量与参数(可选): + +- `TZ_AUTO=1` 与可选 `TZ_VALUE=Asia/Shanghai`:启用脚本内时区设置(默认不修改时区)。 +- `ACME_EMAIL=you@example.com`:`v2ray+ws+tls` 与 HTTPS(Caddy)申请证书使用的邮箱(默认 `admin@example.com`)。 +- `HY2_CERT=/path/server.crt`、`HY2_KEY=/path/server.key`、`HY2_SNI=example.com`:Hysteria2 使用真实证书(存在时客户端将不再跳过证书验证)。 +- `SS_VERSION=vX.Y.Z`、`SS_SHA256=`:固定安装 Shadowsocks-rust 的版本并可选校验下载的完整性。 +- `FIREWALL_AUTO=1`:安装后自动尝试放通所需端口(UFW/Firewalld)。 + - WS/WSS: 80、443(WSS 可自定义端口) + - Reality: 指定 TCP 端口 + - Hysteria2: 指定 UDP 端口 + - HTTPS 正向代理: 80、443 + +TCP/系统调优脚本(可选): + +- 使用方式:`bash tcp-window.sh --apply` 应用调优;`--revert` 回滚;`--status` 查看状态。 +- 实现:通过 `/etc/sysctl.d/99-tuning.conf` 和 `/etc/security/limits.d/99-nofile.conf` 等 drop-in 文件实现,避免覆盖系统默认配置;不再强制重启。 + +辅助脚本: + +- 诊断:`bash doctor.sh` 输出服务状态、监听端口、证书情况、防火墙信息。 +- 卸载:`bash uninstall.sh` 选择性移除 V2Ray/Xray/Hysteria2/Shadowsocks/Caddy/Nginx 站点配置。 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md new file mode 100644 index 0000000..ec1eb85 --- /dev/null +++ b/docs/CHANGELOG.md @@ -0,0 +1,69 @@ +# Changelog + +## Phase 1 — Baseline Hardening + +Date: YYYY-MM-DD + +Changes: +- Shebangs unified to `#!/usr/bin/env bash` across all scripts +- Enabled strict mode: `set -Eeuo pipefail` and safe IFS +- Timezone changes gated by `TZ_AUTO=1` (default off) +- ACME email in `tcp-wss.sh` parameterized via `ACME_EMAIL` (default `admin@example.com`) +- Removed self-deleting lines from all scripts (retain scripts for troubleshooting) +- No behavioral protocol changes yet (kept for Phase 2) + +Notes: +- Subsequent phases will refine protocol configs, TLS settings, and idempotency. + +## Phase 2 — Protocol & Web Server Correctness + +Date: YYYY-MM-DD + +Changes: +- tcp-wss.sh: Switched ACME issuance to webroot mode; added two-stage Nginx setup (80-only for ACME, then TLS site) with modern TLS (1.2/1.3) and enabled logs +- tcp-wss.sh: Stopped overwriting `nginx.conf`; now uses `conf.d` site files +- tcp-wss.sh: Client output encryption label aligned to `none` for VMess +- ws.sh: Inbound `streamSettings.security` set to `none`; share link `method` set to `none`; client output aligned + - Normalized client outputs: now write machine-readable JSON and human-readable TXT for VMess (ws/wss) + - https.sh: Switched to domain-hosted Caddyfile (auto HTTP->HTTPS), added global ACME email, checksum verification for Caddy tarball + +Pending: +- HTTPS forward proxy Caddy: clarify auto-cert behavior; add checksum validation +- Further VMess link field normalization if needed across clients + +## Phase 3 — Reality/Hy2/SS-rust Enhancements + +Date: YYYY-MM-DD + +Changes: +- reality.sh: Parse X25519 public key only from Public/PublicKey fields; generate random hex shortId; propagate into config and share-link +- reality.sh: Client output and saved JSON now include dynamic shortId +- hy2.sh: Support using real certificate/key via `HY2_CERT`/`HY2_KEY`; SNI via `HY2_SNI`; client `insecure` auto-set based on certificate type +- ss-rust.sh: Allow version pin using `SS_VERSION`; optional tarball integrity check via `SS_SHA256` + +Pending: +- reality.sh: Optional multi-user/multi-port support +- ss-rust.sh: 2022 ciphers option + +## Phase 4 — System Tuning & Idempotency + +Date: YYYY-MM-DD + +Changes: +- Rewrote `tcp-window.sh` to an idempotent, CLI-driven script using `/etc/sysctl.d` and `/etc/security/limits.d` drop-ins +- Added `--apply`, `--revert`, and `--status` commands; removed forced reboot + +Notes: +- Some settings may require service restart or reboot to take effect + +## Phase 5 — Automation & Docs + +Date: YYYY-MM-DD + +Changes: +- Added CI workflow for ShellCheck and shfmt to enforce script quality +- Updated README with environment variables and tuning script usage + - Added uninstall.sh and doctor.sh helper scripts + +Pending: +- Add uninstall and doctor scripts; expand docs for firewall/SELinux diff --git a/docs/IMPROVEMENT_PLAN.md b/docs/IMPROVEMENT_PLAN.md new file mode 100644 index 0000000..6481dc0 --- /dev/null +++ b/docs/IMPROVEMENT_PLAN.md @@ -0,0 +1,52 @@ +# Improvement Plan and Progress + +This document tracks the ongoing optimization roadmap and stage-by-stage progress. + +## Overview + +Goal: Improve security, correctness, portability, and maintainability of the installation scripts and tooling for Shadowsocks-rust, V2Ray (WS/WSS), Reality (Xray), Hysteria2, and HTTPS forward proxy. + +## Phases + +1) Baseline Hardening (In Progress) +- Unify shebangs to bash and enable strict mode +- Add safe defaults and environment toggles (e.g., TZ gating) +- Remove in-script self-deletions +- Parameterize ACME email +- Prepare for idempotent operations and safer downloads + +2) Protocol & Web Server Correctness (In Progress) +- Nginx: separate site config, modern TLS (1.2/1.3), ciphers, enable logs [done] +- ACME: switch to webroot; customizable email [done] +- V2Ray (VMess+WS): align inbound and share-link fields; fix `security` [done for ws.sh; wss prints aligned] +- HTTPS proxy (Caddy): clarified auto-cert via host matcher and global email; checksum validation for release tarball [done] +- Client outputs normalized: machine-readable JSON + human-readable TXT [done] + +3) Reality/Hy2/SS-rust Enhancements (In Progress) +- Reality: robust key parsing (PublicKey) [done], random shortIds [done], multi-user optional [todo] +- Hysteria2: real-cert option via HY2_CERT/HY2_KEY and HY2_SNI [done]; QUIC windows defaults [kept] +- Shadowsocks-rust: version pin via SS_VERSION and checksum via SS_SHA256 [done]; 2022 ciphers option [todo] + +4) System Tuning & Idempotency (In Progress) +- Converted `tcp-window.sh` to idempotent tuning via sysctl.d/limits.d [done] +- Removed forced reboot; added `--apply`/`--revert`/`--status` [done] + +5) Automation & Docs (In Progress) +- ShellCheck/shfmt CI [done] +- Expanded README with env flags and tuning usage [done] +- Firewall/SELinux guidance [todo] +- Add `uninstall.sh` and `doctor.sh` [done] + +## Stage Logs + +### Phase 1 — Baseline Hardening +Applied: +- Shebangs unified to `#!/usr/bin/env bash` +- Added `set -Eeuo pipefail` and safe IFS +- Timezone change gated behind `TZ_AUTO=1` (default off) +- ACME email parameterized via `ACME_EMAIL` (default `admin@example.com`) +- Removed in-script self-deletion lines + +Next: +- Introduce common utility library without breaking standalone usage +- Add optional checksum verification helpers diff --git a/doctor.sh b/doctor.sh new file mode 100644 index 0000000..b35f3d2 --- /dev/null +++ b/doctor.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# Diagnostic helper for this repository + +set -Eeuo pipefail +IFS=$'\n\t' + +bold() { printf "\033[1m%s\033[0m\n" "$*"; } + +section() { + echo; bold "== $* =="; } + +cmd_ok() { command -v "$1" >/dev/null 2>&1; } + +service_status() { + local svc="$1" + if cmd_ok systemctl; then + systemctl is-active --quiet "$svc" && echo active || echo inactive + else + echo unknown + fi +} + +show_port_listen() { + if cmd_ok ss; then + ss -lntup || true + elif cmd_ok netstat; then + netstat -lntup || true + else + echo "No ss/netstat available" + fi +} + +extract_domain_nginx() { + awk '/server_name/{print $2}' /etc/nginx/conf.d/v2ray_wss_tls.conf 2>/dev/null | tr -d ';' | head -1 || true +} + +extract_domain_caddy() { + awk 'NF && $1 !~ /^[{#]/ {print $1; exit}' /etc/caddy/https.caddyfile 2>/dev/null || true +} + +check_cert() { + local crt="$1" + [[ -f "$crt" ]] || { echo "Not found"; return; } + openssl x509 -noout -dates -in "$crt" 2>/dev/null || echo "Unable to parse" +} + +section "System" +uname -a || true +if [[ -f /etc/os-release ]]; then . /etc/os-release; echo "$NAME $VERSION"; fi + +section "Services" +for s in nginx v2ray xray hysteria-server caddy shadowsocks; do + printf "%-18s %s\n" "$s" "$(service_status "$s")" +done + +section "Listening Ports" +show_port_listen + +section "Nginx" +cmd_ok nginx && (nginx -t || true) +domain_nginx="$(extract_domain_nginx)" +if [[ -n "$domain_nginx" ]]; then + echo "Detected domain: $domain_nginx" + echo "Certificate: /etc/letsencrypt/live/$domain_nginx/fullchain.pem" + check_cert "/etc/letsencrypt/live/$domain_nginx/fullchain.pem" +fi + +section "Caddy" +if [[ -f /etc/caddy/https.caddyfile ]]; then + echo "Caddyfile present: /etc/caddy/https.caddyfile" + domain_caddy="$(extract_domain_caddy)" + [[ -n "$domain_caddy" ]] && echo "Detected site: $domain_caddy" +fi + +section "V2Ray/Xray Versions" +/usr/local/bin/v2ray version 2>/dev/null || true +/usr/local/bin/xray version 2>/dev/null || true + +section "Firewall" +if cmd_ok ufw; then + ufw status || true +elif cmd_ok firewall-cmd; then + firewall-cmd --state || true + firewall-cmd --list-ports || true +else + echo "No ufw/firewalld detected" +fi + +echo +bold "Diagnostics completed." + diff --git a/https.sh b/https.sh index 882172f..5664d5a 100644 --- a/https.sh +++ b/https.sh @@ -1,8 +1,11 @@ -#!/bin/sh -# HTTPS Poxy Installation Script +#!/usr/bin/env bash +# HTTPS Proxy Installation Script # Author: https://1024.day -if [[ $EUID -ne 0 ]]; then +set -Eeuo pipefail +IFS=$'\n\t' + +if [[ ${EUID:-$(id -u)} -ne 0 ]]; then clear echo "Error: This script must be run as root!" 1>&2 exit 1 @@ -10,14 +13,36 @@ fi Passwd=$(cat /dev/urandom | head -1 | md5sum | head -c 12) -wget https://github.com/yeahwu/v2ray-wss/releases/download/v-monthly/caddy-v-monthly.tar.gz -O - | tar -xz -C /usr/local/ +# Download Caddy (monthly build) with checksum verification +CADDY_VERSION="v-monthly" +CADDY_BASE_URL="https://github.com/yeahwu/v2ray-wss/releases/download/${CADDY_VERSION}" +CADDY_TARBALL="caddy-${CADDY_VERSION}.tar.gz" +CADDY_SHA256="${CADDY_TARBALL}.sha256" + +tmpdir=$(mktemp -d) +trap 'rm -rf "$tmpdir"' EXIT + +echo "Downloading Caddy ${CADDY_VERSION}..." +wget -q "${CADDY_BASE_URL}/${CADDY_TARBALL}" -O "${tmpdir}/${CADDY_TARBALL}" +if [[ -s "${tmpdir}/${CADDY_TARBALL}" ]]; then + if wget -q "${CADDY_BASE_URL}/${CADDY_SHA256}" -O "${tmpdir}/${CADDY_SHA256}"; then + echo "Verifying checksum..." + (cd "$tmpdir" && sha256sum -c "${CADDY_SHA256}") + else + echo "Warning: checksum file not found, skipping verification" + fi + tar -xzf "${tmpdir}/${CADDY_TARBALL}" -C /usr/local/ +else + echo "Error: failed to download Caddy tarball" 1>&2 + exit 1 +fi chmod +x /usr/local/caddy echo "====输入已经DNS解析好的域名====" read domain - isPort=`netstat -ntlp| grep -E ':80 |:443 '` + isPort=`netstat -ntlp| grep -E ':80 |:443 ' || true` if [ "$isPort" != "" ];then clear echo " ================================================== " @@ -31,15 +56,24 @@ read domain mkdir -p /etc/caddy +email="${ACME_EMAIL:-admin@example.com}" +user="${HTTPS_USER:-1024}" +pass="$Passwd" + cat >/etc/caddy/https.caddyfile</dev/null 2>&1; then + if ufw status | grep -qi "Status: active"; then + ufw allow "${port}/tcp" || true + fi + elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then + firewall-cmd --add-port="${port}/tcp" --permanent || true + firewall-cmd --reload || true + fi + } +} +open_firewall_tcp 80 +open_firewall_tcp 443 cat >/etc/caddy/https.json</etc/caddy/https.txt< /dev/null; then chown hysteria:hysteria /etc/hysteria/server.key /etc/hysteria/server.crt @@ -190,13 +200,21 @@ EOF else echo "请手动启动 Hysteria2 服务" fi + open_firewall_udp "$SERVER_PORT" + CLIENT_SNI="${HY2_SNI:-bing.com}" + if [[ "$REAL_CERT_USED" -eq 1 ]]; then + CLIENT_INSECURE=false + else + CLIENT_INSECURE=true + fi + cat > /etc/hysteria/hyclient.json << EOF { "server": "$(get_server_ip):${SERVER_PORT}", "auth": "${HYSTERIA_PASSWORD}", "tls": { - "sni": "bing.com", - "insecure": true + "sni": "${CLIENT_SNI}", + "insecure": ${CLIENT_INSECURE} }, "quic": { "initStreamReceiveWindow": 26843545, @@ -206,7 +224,7 @@ EOF } } EOF - rm -f tcp-wss.sh hy2.sh + # keep scripts for troubleshooting; do not self-delete clear } @@ -233,7 +251,12 @@ check_service_status() { show_client_config() { local server_ip server_ip=$(get_server_ip) - local connection_link="${HYSTERIA_PASSWORD}@${server_ip}:${SERVER_PORT}/?insecure=1&sni=bing.com#1024-Hysteria2" + local sni_val="${HY2_SNI:-bing.com}" + local insecure_flag=1 + if [[ "${REAL_CERT_USED:-0}" -eq 1 ]]; then + insecure_flag=0 + fi + local connection_link="${HYSTERIA_PASSWORD}@${server_ip}:${SERVER_PORT}/?insecure=${insecure_flag}&sni=${sni_val}#1024-Hysteria2" echo echo -e "${GREEN}===== Hysteria2 安装完成 =====${RESET}" @@ -242,9 +265,9 @@ show_client_config() { echo -e "服务器地址: ${YELLOW}${server_ip}${RESET}" echo -e "端口: ${YELLOW}${SERVER_PORT}${RESET}" echo -e "密码: ${YELLOW}${HYSTERIA_PASSWORD}${RESET}" - echo -e "SNI: ${YELLOW}bing.com${RESET}" + echo -e "SNI: ${YELLOW}${sni_val}${RESET}" echo -e "传输协议: ${YELLOW}QUIC over TLS${RESET}" - echo -e "跳过证书验证: ${YELLOW}true${RESET}" + echo -e "跳过证书验证: ${YELLOW}$([[ $insecure_flag -eq 1 ]] && echo true || echo false)${RESET}" echo -e "${CYAN}==================================${RESET}" echo echo -e "${CYAN}连接链接:${RESET}" @@ -277,3 +300,16 @@ main() { # 执行主函数 main +# Optional firewall opening when FIREWALL_AUTO=1 +open_firewall_udp() { + local port="$1" + [[ "${FIREWALL_AUTO:-0}" != "1" ]] && return 0 + if command -v ufw >/dev/null 2>&1; then + if ufw status | grep -qi "Status: active"; then + ufw allow "${port}/udp" || true + fi + elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then + firewall-cmd --add-port="${port}/udp" --permanent || true + firewall-cmd --reload || true + fi +} diff --git a/reality.sh b/reality.sh index 40ea86b..6b84eee 100755 --- a/reality.sh +++ b/reality.sh @@ -1,6 +1,9 @@ -#!/bin/bash +#!/usr/bin/env bash # forum: https://1024.day +set -Eeuo pipefail +IFS=$'\n\t' + # 确保以root用户运行 if [[ $EUID -ne 0 ]]; then clear @@ -439,14 +442,8 @@ generate_keys() { # 解析私钥 RE_PRIVATE_KEY=$(echo "$raw" | grep -iE "(private|privatekey)" | awk -F ':' '{print $2}' | tr -d ' \r\n\t' || true) - - # 解析公钥,优先级:Password优先,然后Public - RE_PUBLIC_KEY=$(echo "$raw" | grep -iE "password" | awk -F ':' '{print $2}' | tr -d ' \r\n\t' || true) - - # 如果没有Password字段,尝试Public字段 - if [[ -z "$RE_PUBLIC_KEY" ]]; then - RE_PUBLIC_KEY=$(echo "$raw" | grep -iE "(public|publickey)" | awk -F ':' '{print $2}' | tr -d ' \r\n\t' || true) - fi + # 解析公钥,仅使用 Public/PublicKey 字段 + RE_PUBLIC_KEY=$(echo "$raw" | grep -iE "(public|publickey)" | awk -F ':' '{print $2}' | tr -d ' \r\n\t' || true) # 验证提取的密钥 if [[ -z "$RE_PRIVATE_KEY" || -z "$RE_PUBLIC_KEY" ]]; then @@ -472,7 +469,18 @@ generate_keys() { print_green "密钥生成成功" log_info "私钥: ${RE_PRIVATE_KEY:0:10}..." - log_info "公钥 (来源: $(echo "$raw" | grep -q "Password" && echo "Password字段" || echo "Public字段")): ${RE_PUBLIC_KEY:0:10}..." + log_info "公钥: ${RE_PUBLIC_KEY:0:10}..." +} + +# 生成 shortId(1-8 字节十六进制,默认 2 字节) +generate_short_id() { + local bytes=${1:-2} + bytes=$(( bytes < 1 ? 1 : (bytes > 8 ? 8 : bytes) )) + local sid="" + for ((i=0; i "$temp_config" </dev/null 2>&1; then + if ufw status | grep -qi "Status: active"; then + ufw allow "${port}/tcp" || true + fi + elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then + firewall-cmd --add-port="${port}/tcp" --permanent || true + firewall-cmd --reload || true + fi +} diff --git a/ss-rust.sh b/ss-rust.sh index 4fe0a30..df2c5dc 100644 --- a/ss-rust.sh +++ b/ss-rust.sh @@ -1,7 +1,10 @@ -#!/bin/bash +#!/usr/bin/env bash # Shadowsocks Rust Installation Script # Author: https://1024.day +set -Eeuo pipefail +IFS=$'\n\t' + # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' @@ -124,36 +127,45 @@ detect_architecture() { install_shadowsocks() { echo -e "${CYAN}下载Shadowsocks Rust...${PLAIN}" - # 获取最新版本 - LATEST_VERSION=$(wget -qO- https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases | - jq -r '[.[] | select(.prerelease == false) | select(.draft == false) | .tag_name] | .[0]') - - if [[ -z "$LATEST_VERSION" ]]; then - echo -e "${RED}无法获取最新版本信息,请检查网络连接或者GitHub API限制${PLAIN}" - exit 1 + # 获取版本:优先使用环境变量 SS_VERSION,否则查询最新版本 + VERSION="${SS_VERSION:-}" + if [[ -z "$VERSION" ]]; then + LATEST_VERSION=$(wget -qO- https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases | \ + jq -r '[.[] | select(.prerelease == false) | select(.draft == false) | .tag_name] | .[0]') + if [[ -z "$LATEST_VERSION" ]]; then + echo -e "${RED}无法获取最新版本信息,请检查网络连接或者GitHub API限制${PLAIN}" + exit 1 + fi + VERSION="$LATEST_VERSION" fi - echo -e "${GREEN}最新版本: $LATEST_VERSION${PLAIN}" + echo -e "${GREEN}目标版本: $VERSION${PLAIN}" # 下载文件 - DOWNLOAD_URL="https://github.com/shadowsocks/shadowsocks-rust/releases/download/${LATEST_VERSION}/shadowsocks-${LATEST_VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" + DOWNLOAD_URL="https://github.com/shadowsocks/shadowsocks-rust/releases/download/${VERSION}/shadowsocks-${VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" echo -e "${CYAN}正在从 $DOWNLOAD_URL 下载...${PLAIN}" + FILE_NAME="shadowsocks-${VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" wget --no-check-certificate -q --show-progress -N "$DOWNLOAD_URL" - if [[ $? -ne 0 || ! -e "shadowsocks-${LATEST_VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" ]]; then + if [[ $? -ne 0 || ! -e "$FILE_NAME" ]]; then echo -e "${RED}下载失败!尝试备用方法...${PLAIN}" - curl -L --progress-bar -o "shadowsocks-${LATEST_VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" "$DOWNLOAD_URL" + curl -L --progress-bar -o "$FILE_NAME" "$DOWNLOAD_URL" - if [[ $? -ne 0 || ! -e "shadowsocks-${LATEST_VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" ]]; then + if [[ $? -ne 0 || ! -e "$FILE_NAME" ]]; then echo -e "${RED}Shadowsocks Rust 下载失败!请检查网络连接或手动下载${PLAIN}" exit 1 fi fi + # 可选校验:如果设置了 SS_SHA256 则进行校验 + if [[ -n "${SS_SHA256:-}" ]]; then + echo "${SS_SHA256} ${FILE_NAME}" | sha256sum -c - + fi + # 解压文件 echo -e "${CYAN}解压文件...${PLAIN}" - tar -xf "shadowsocks-${LATEST_VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" + tar -xf "$FILE_NAME" if [[ ! -e "ssserver" ]]; then echo -e "${RED}解压失败!${PLAIN}" @@ -165,7 +177,7 @@ install_shadowsocks() { mv -f ssserver /usr/local/bin/ # 清理其他文件 - rm -f "shadowsocks-${LATEST_VERSION}.${ARCH}-unknown-linux-gnu.tar.xz" + rm -f "$FILE_NAME" rm -f sslocal ssmanager ssservice ssurl 2>/dev/null echo -e "${GREEN}Shadowsocks Rust 安装完成!${PLAIN}" @@ -211,8 +223,7 @@ EOF systemctl enable shadowsocks.service systemctl restart shadowsocks.service - # 清理临时文件 - rm -f tcp-wss.sh ss-rust.sh 2>/dev/null + # 保留脚本以便排查问题与复用,不再自删除 echo -e "${GREEN}Shadowsocks 配置完成!${PLAIN}" } diff --git a/tcp-window.sh b/tcp-window.sh index e3b8bac..d8340d6 100644 --- a/tcp-window.sh +++ b/tcp-window.sh @@ -1,52 +1,103 @@ -##!/bin/sh +#!/usr/bin/env bash # Issues https://1024.day -if [[ $EUID -ne 0 ]]; then - clear +set -Eeuo pipefail +IFS=$'\n\t' + +if [[ ${EUID:-$(id -u)} -ne 0 ]]; then echo "Error: This script must be run as root!" exit 1 fi -cat >/etc/security/limits.conf< "$LIMITS_D_FILE" <> /etc/pam.d/common-session - -echo "session required pam_limits.so" >> /etc/pam.d/common-session-noninteractive - -echo "DefaultLimitNOFILE=262144" >> /etc/systemd/system.conf - -echo "DefaultLimitNPROC=131072" >> /etc/systemd/system.conf + # Ensure pam_limits is active (best-effort) + for pamf in /etc/pam.d/common-session /etc/pam.d/common-session-noninteractive; do + if [[ -f "$pamf" ]] && ! grep -q "^session\s\+required\s\+pam_limits.so" "$pamf"; then + echo "session required pam_limits.so" >> "$pamf" + fi + done -cp /etc/sysctl.conf /etc/sysctl.conf.bak.$(date +%F-%T) + # systemd limits via drop-in + mkdir -p "$SYSTEMD_DROPIN_DIR" + cat > "$SYSTEMD_DROPIN_FILE" </etc/sysctl.conf< "$SYSCTL_D_FILE" </dev/null 2>&1 || sysctl -p "$SYSCTL_D_FILE" || true +} + +revert() { + rm -f "$LIMITS_D_FILE" "$SYSCTL_D_FILE" + rm -f "$SYSTEMD_DROPIN_FILE" + echo -e "${GREEN}Reverted tuning files. You may need to restart services to apply changes.${RESET}" +} + +status() { + echo -e "${YELLOW}Limits file:${RESET} $LIMITS_D_FILE $( [[ -f "$LIMITS_D_FILE" ]] && echo '[present]' || echo '[missing]' )" + echo -e "${YELLOW}Sysctl file:${RESET} $SYSCTL_D_FILE $( [[ -f "$SYSCTL_D_FILE" ]] && echo '[present]' || echo '[missing]' )" + echo -e "${YELLOW}Systemd drop-in:${RESET} $SYSTEMD_DROPIN_FILE $( [[ -f "$SYSTEMD_DROPIN_FILE" ]] && echo '[present]' || echo '[missing]' )" + echo -e "${YELLOW}Current tcp_congestion_control:${RESET} $(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null || echo 'unknown')" +} + +usage() { + cat </dev/null 2>&1 diff --git a/tcp-wss.sh b/tcp-wss.sh index ea19e7b..cd78263 100644 --- a/tcp-wss.sh +++ b/tcp-wss.sh @@ -1,13 +1,19 @@ -##!/bin/sh +#!/usr/bin/env bash # forum: https://1024.day -if [[ $EUID -ne 0 ]]; then +set -Eeuo pipefail +IFS=$'\n\t' + +if [[ ${EUID:-$(id -u)} -ne 0 ]]; then clear echo "Error: This script must be run as root!" 1>&2 exit 1 fi -timedatectl set-timezone Asia/Shanghai +# Optional timezone change: enable by exporting TZ_AUTO=1 (default off) +if [[ "${TZ_AUTO:-0}" == "1" ]]; then + timedatectl set-timezone "${TZ_VALUE:-Asia/Shanghai}" || true +fi v2path=$(cat /dev/urandom | head -1 | md5sum | head -c 6) v2uuid=$(cat /proc/sys/kernel/random/uuid) ssport=$(shuf -i 2000-65000 -n 1) @@ -53,73 +59,87 @@ install_precheck(){ fi } -install_nginx(){ +install_nginx_80_only(){ if [ -f "/usr/bin/apt-get" ];then apt-get install -y nginx cron socat else yum install -y nginx cronie socat fi -cat >/etc/nginx/nginx.conf</etc/nginx/conf.d/v2ray_wss.conf</etc/nginx/conf.d/v2ray_wss_tls.conf</usr/local/etc/v2ray/config.json</usr/local/etc/v2ray/client.json</usr/local/etc/v2ray/client.txt</dev/null 2>&1; then + if ufw status | grep -qi "Status: active"; then + ufw allow "${port}/${proto}" || true + fi + elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then + firewall-cmd --add-port="${port}/${proto}" --permanent || true + firewall-cmd --reload || true + fi +} diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 0000000..305a268 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# Uninstall helper for this repository + +set -Eeuo pipefail +IFS=$'\n\t' + +if [[ ${EUID:-$(id -u)} -ne 0 ]]; then + echo "Error: must run as root" 1>&2 + exit 1 +fi + +confirm() { read -r -p "$1 [y/N]: " _ans; [[ "${_ans,,}" == "y" ]]; } + +remove_v2ray() { + systemctl stop v2ray.service 2>/dev/null || true + systemctl disable v2ray.service 2>/dev/null || true + rm -rf /usr/local/etc/v2ray 2>/dev/null || true + echo "V2Ray removed (config)." +} + +remove_nginx_site() { + rm -f /etc/nginx/conf.d/v2ray_wss.conf /etc/nginx/conf.d/v2ray_wss_tls.conf 2>/dev/null || true + nginx -t && systemctl reload nginx || true + echo "Nginx v2ray site removed." +} + +remove_xray() { + systemctl stop xray.service 2>/dev/null || true + systemctl disable xray.service 2>/dev/null || true + rm -rf /usr/local/etc/xray 2>/dev/null || true + echo "Xray (Reality) removed (config)." +} + +remove_hysteria() { + systemctl stop hysteria-server.service 2>/dev/null || true + systemctl disable hysteria-server.service 2>/dev/null || true + rm -rf /etc/hysteria 2>/dev/null || true + echo "Hysteria2 removed (config)." +} + +remove_shadowsocks() { + systemctl stop shadowsocks.service 2>/dev/null || true + systemctl disable shadowsocks.service 2>/dev/null || true + rm -rf /etc/shadowsocks 2>/dev/null || true + echo "Shadowsocks-rust removed (config)." +} + +remove_caddy() { + systemctl stop caddy.service 2>/dev/null || true + systemctl disable caddy.service 2>/dev/null || true + rm -f /etc/systemd/system/caddy.service 2>/dev/null || true + systemctl daemon-reload || true + rm -rf /etc/caddy 2>/dev/null || true + rm -f /usr/local/caddy 2>/dev/null || true + echo "Caddy removed." +} + +remove_all() { + remove_v2ray + remove_nginx_site + remove_xray + remove_hysteria + remove_shadowsocks + remove_caddy + echo "All components removed (configs/binaries where safe)." +} + +show_menu() { + clear + local line="+------------------------------------------+" + echo "$line" + printf "| %-40s |\n" "卸载工具 / Uninstall" + echo "$line" + printf "| %-40s |\n" " 1) 移除 V2Ray (配置)" + printf "| %-40s |\n" " 2) 移除 Nginx 站点配置" + printf "| %-40s |\n" " 3) 移除 Xray (Reality 配置)" + printf "| %-40s |\n" " 4) 移除 Hysteria2 (配置)" + printf "| %-40s |\n" " 5) 移除 Shadowsocks-rust (配置)" + printf "| %-40s |\n" " 6) 移除 Caddy" + printf "| %-40s |\n" " 7) 全部移除" + printf "| %-40s |\n" " 0) 退出" + echo "$line" + echo + read -p "请选择 [0-7]: " num + case "$num" in + 1) confirm "确认移除 V2Ray?" && remove_v2ray ;; + 2) confirm "确认移除 Nginx 站点?" && remove_nginx_site ;; + 3) confirm "确认移除 Xray (Reality)?" && remove_xray ;; + 4) confirm "确认移除 Hysteria2?" && remove_hysteria ;; + 5) confirm "确认移除 Shadowsocks-rust?" && remove_shadowsocks ;; + 6) confirm "确认移除 Caddy?" && remove_caddy ;; + 7) confirm "确认全部移除?" && remove_all ;; + 0) exit 0 ;; + *) echo "无效选项"; sleep 1 ;; + esac +} + +while true; do + show_menu +done + diff --git a/ws.sh b/ws.sh index cfa9d25..2829638 100644 --- a/ws.sh +++ b/ws.sh @@ -1,13 +1,19 @@ -#!/bin/sh +#!/usr/bin/env bash # forum: https://1024.day -if [[ $EUID -ne 0 ]]; then +set -Eeuo pipefail +IFS=$'\n\t' + +if [[ ${EUID:-$(id -u)} -ne 0 ]]; then clear echo "Error: This script must be run as root!" 1>&2 exit 1 fi -timedatectl set-timezone Asia/Shanghai +# Optional timezone change: enable by exporting TZ_AUTO=1 (default off) +if [[ "${TZ_AUTO:-0}" == "1" ]]; then + timedatectl set-timezone "${TZ_VALUE:-Asia/Shanghai}" || true +fi v2uuid=$(cat /proc/sys/kernel/random/uuid) v2path=$(cat /dev/urandom | head -1 | md5sum | head -c 6) v2port=$(shuf -i 2000-65000 -n 1) @@ -50,7 +56,7 @@ cat >/usr/local/etc/v2ray/config.json</usr/local/etc/v2ray/config.json</usr/local/etc/v2ray/client.json</usr/local/etc/v2ray/client.txt</dev/null 2>&1; then + if ufw status | grep -qi "Status: active"; then + ufw allow "${port}/${proto}" || true + fi + elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then + firewall-cmd --add-port="${port}/${proto}" --permanent || true + firewall-cmd --reload || true + fi +}