Initial commit: add installer, README, and license

Add install.sh for automated HY proxy and nginx deployment with SSL, a comprehensive README with usage instructions, and the MIT license. This sets up the project foundation for one-command server setup on Debian/Ubuntu.
This commit is contained in:
xixu-me committed 2025-12-19 16:17:52 +08:00
commit 3e5f89c706
3 files changed
+553

No files matched your search

+282
View File
@@ -0,0 +1,282 @@
#!/usr/bin/env bash
set -euo pipefail
# Constants
DOMAIN=""
EMAIL=""
HY_PASS=""
NO_UFW=0
NO_SYSCTL=0
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
log() { echo -e "${GREEN}[+] $*${NC}"; }
warn() { echo -e "${YELLOW}[!] $*${NC}" >&2; }
err() { echo -e "${RED}[✗] $*${NC}" >&2; exit 1; }
need_root() {
[[ "${EUID}" -eq 0 ]] || err "Please run as root: sudo bash $0 ..."
}
check_os() {
if [[ -f /etc/os-release ]]; then
source /etc/os-release
if [[ "${ID}" != "ubuntu" && "${ID}" != "debian" ]]; then
warn "This script is optimized for Debian/Ubuntu. Your OS (${ID}) might not be supported."
read -r -p "Press ENTER to continue anyway, or Ctrl+C to abort..."
fi
else
err "Cannot detect OS. /etc/os-release not found."
fi
}
has_cmd() { command -v "$1" >/dev/null 2>&1; }
usage() {
cat <<EOF
Usage:
sudo bash $0 -d <domain> -e <email> [-p <password>] [--no-ufw] [--no-sysctl]
Options:
-d, --domain Domain name (required)
-e, --email Email for Let's Encrypt registration (required)
-p, --password HY password (optional; auto-generated if omitted)
--no-ufw Do not enable/modify UFW (firewall)
--no-sysctl Do not apply sysctl tuning (UDP buffers)
-h, --help Show this help message
Example:
sudo bash $0 -d example.com -e admin@example.com
EOF
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
-d|--domain) DOMAIN="${2:-}"; shift 2;;
-e|--email) EMAIL="${2:-}"; shift 2;;
-p|--password) HY_PASS="${2:-}"; shift 2;;
--no-ufw) NO_UFW=1; shift 1;;
--no-sysctl) NO_SYSCTL=1; shift 1;;
-h|--help) usage; exit 0;;
*) err "Unknown argument: $1 (use -h for help)";;
esac
done
# Interactive prompts if missing args
if [[ -z "${DOMAIN}" ]]; then
read -r -p "Enter your domain (e.g., example.com): " DOMAIN
fi
if [[ -z "${EMAIL}" ]]; then
read -r -p "Enter your email for Let's Encrypt: " EMAIL
fi
# Generate password if missing
if [[ -z "${HY_PASS}" ]]; then
if has_cmd openssl; then
HY_PASS="$(openssl rand -base64 24 | tr -d '\n')"
else
HY_PASS="$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 32)"
fi
fi
# Validations
[[ "${DOMAIN}" =~ ^[A-Za-z0-9.-]+$ ]] || err "Invalid domain format: ${DOMAIN}"
[[ "${EMAIL}" =~ ^[^@]+@[^@]+\.[^@]+$ ]] || warn "Email looks simple, but proceeding: ${EMAIL}"
}
apt_install() {
log "Updating system and installing dependencies..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y curl ca-certificates gnupg lsb-release \
nginx \
certbot python3-certbot-nginx \
ufw
systemctl enable --now nginx
}
setup_nginx_site() {
log "Configuring nginx site for ${DOMAIN}..."
local webroot="/var/www/${DOMAIN}"
mkdir -p "${webroot}"
# Create a nice masquerade page
cat > "${webroot}/index.html" <<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to ${DOMAIN}</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: #f0f2f5; color: #1c1e21; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
.container { text-align: center; padding: 2rem; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
h1 { margin-bottom: 0.5rem; }
p { color: #606770; }
</style>
</head>
<body>
<div class="container">
<h1>${DOMAIN}</h1>
<p>Site is under construction.</p>
</div>
</body>
</html>
EOF
chown -R www-data:www-data "${webroot}"
local site_avail="/etc/nginx/sites-available/${DOMAIN}"
if [[ -f "${site_avail}" ]]; then
cp -a "${site_avail}" "${site_avail}.$(date +%F_%H%M%S).bak"
warn "Existing nginx config found. Backed up to ${site_avail}.bak"
fi
cat > "${site_avail}" <<EOF
server {
listen 80;
server_name ${DOMAIN};
root ${webroot};
index index.html;
location / {
try_files \$uri \$uri/ =404;
}
}
EOF
ln -sf "${site_avail}" "/etc/nginx/sites-enabled/${DOMAIN}"
rm -f /etc/nginx/sites-enabled/default || true
nginx -t
systemctl reload nginx
}
issue_cert() {
log "Issuing SSL certificate via Certbot..."
if ! certbot --nginx -d "${DOMAIN}" \
-m "${EMAIL}" --agree-tos --redirect --non-interactive --no-eff-email; then
err "Certbot failed. Check your DNS and firewall settings.\nEnsure ${DOMAIN} points to valid IP: $(curl -s ifconfig.me)"
fi
nginx -t
systemctl reload nginx
}
install_hy() {
log "Installing HY..."
# Always get latest
HYSTERIA_USER=root bash <(curl -fsSL https://get.hy2.sh/)
}
configure_hy() {
log "Configuring HY..."
local cert="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
local key="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
[[ -f "${cert}" ]] || err "Certificate not found: ${cert}"
[[ -f "${key}" ]] || err "Private key not found: ${key}"
mkdir -p /etc/hysteria
# HY Config
# Uses UDP/443. Nginx handles TCP/443.
cat > /etc/hysteria/config.yaml <<EOF
listen: :443
tls:
cert: ${cert}
key: ${key}
auth:
type: password
password: "${HY_PASS}"
masquerade:
type: proxy
proxy:
url: https://${DOMAIN}/
rewriteHost: true
EOF
systemctl enable --now hysteria-server.service
systemctl restart hysteria-server.service
}
tune_sysctl() {
[[ "${NO_SYSCTL}" -eq 1 ]] && { warn "Skipping sysctl tuning."; return 0; }
log "Applying UDP buffer tuning..."
cat > /etc/sysctl.d/99-hy.conf <<'EOF'
net.core.rmem_max=16777216
net.core.wmem_max=16777216
EOF
sysctl --system >/dev/null
}
setup_ufw() {
[[ "${NO_UFW}" -eq 1 ]] && { warn "Skipping UFW setup."; return 0; }
log "Configuring UFW firewall..."
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw allow 443/udp # HY (QUIC)
if ufw status | grep -qi "inactive"; then
echo "y" | ufw enable >/dev/null || true
fi
}
print_proxies() {
echo
echo "========== Client Config Snippet =========="
cat <<EOF
proxies:
- name: "hy2-${DOMAIN}"
type: hysteria2
server: ${DOMAIN}
port: 443
password: "${HY_PASS}"
skip-cert-verify: false
alpn:
- h3
EOF
}
verify() {
log "Installation Complete! Verifying services..."
echo "------------------------------------------------"
echo " Nginx Status: $(systemctl is-active nginx)"
echo " HY Status: $(systemctl is-active hysteria-server.service)"
echo "------------------------------------------------"
print_proxies
echo
echo "Logs: journalctl -u hysteria-server.service -f"
echo "Enjoy!"
}
main() {
need_root
check_os
parse_args "$@"
apt_install
setup_nginx_site
issue_cert
install_hy
tune_sysctl
configure_hy
setup_ufw
verify
}
main "$@"