rproxy v1.8.0: консолидация доменов и исправление SSL
This commit is contained in:
parent
08f753d9bf
commit
97c9e5a2f5
216
rproxy
216
rproxy
|
|
@ -3,7 +3,7 @@
|
||||||
# Публикация локальных сервисов через SSH-туннели + nginx на VPS
|
# Публикация локальных сервисов через SSH-туннели + nginx на VPS
|
||||||
# https://github.com/l-ptrol/rProxy
|
# https://github.com/l-ptrol/rProxy
|
||||||
|
|
||||||
VERSION="1.7.0"
|
VERSION="1.8.0"
|
||||||
export PATH="/opt/bin:/opt/sbin:$PATH"
|
export PATH="/opt/bin:/opt/sbin:$PATH"
|
||||||
CONF_DIR="/opt/etc/rproxy"
|
CONF_DIR="/opt/etc/rproxy"
|
||||||
CONF_FILE="$CONF_DIR/rproxy.conf"
|
CONF_FILE="$CONF_DIR/rproxy.conf"
|
||||||
|
|
@ -12,6 +12,7 @@ VPS_DIR="$CONF_DIR/vps"
|
||||||
PID_DIR="/opt/var/run/rproxy"
|
PID_DIR="/opt/var/run/rproxy"
|
||||||
SSH_KEY="$CONF_DIR/id_ed25519"
|
SSH_KEY="$CONF_DIR/id_ed25519"
|
||||||
REMOTE_NGINX_DIR="/etc/nginx/sites-enabled"
|
REMOTE_NGINX_DIR="/etc/nginx/sites-enabled"
|
||||||
|
REMOTE_LOCATIONS_DIR="/etc/nginx/rproxy_locations"
|
||||||
BASE_TUNNEL_PORT=10000
|
BASE_TUNNEL_PORT=10000
|
||||||
BASE_EXT_PORT=26000
|
BASE_EXT_PORT=26000
|
||||||
CERTBOT_EMAIL="" # Будет заполнено из конфига
|
CERTBOT_EMAIL="" # Будет заполнено из конфига
|
||||||
|
|
@ -595,10 +596,10 @@ do_add_interactive() {
|
||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
msg "Деплой конфигурации на VPS..."
|
||||||
local tmp="/tmp/rproxy_$name.conf"
|
local tmp="/tmp/rproxy_$name.conf"
|
||||||
generate_nginx_conf "$name" "$t_host" "$t_port" "$tunnel_port" "$domain" "$ext_port" "$use_ndm_auth" "$path" "$tmp"
|
generate_nginx_conf "$name" "$t_host" "$t_port" "$tunnel_port" "$domain" "$ext_port" "$use_ndm_auth" "$path" "$tmp"
|
||||||
|
|
||||||
# Деплой
|
|
||||||
# Деплой htpasswd если нужно
|
# Деплой htpasswd если нужно
|
||||||
if [ "$use_ndm_auth" = "yes" ]; then
|
if [ "$use_ndm_auth" = "yes" ]; then
|
||||||
local ht_tmp="/tmp/rproxy_$name.htpasswd"
|
local ht_tmp="/tmp/rproxy_$name.htpasswd"
|
||||||
|
|
@ -607,15 +608,35 @@ do_add_interactive() {
|
||||||
rm -f "$ht_tmp"
|
rm -f "$ht_tmp"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Деплой nginx
|
# Деплой сниппета локации
|
||||||
scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_$name.conf" || { err "Ошибка деплоя nginx"; rm -f "$tmp"; pause; return; }
|
local remote_loc_dir
|
||||||
rm -f "$tmp"
|
if [ -n "$domain" ]; then
|
||||||
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
remote_loc_dir="$REMOTE_LOCATIONS_DIR/$domain"
|
||||||
|
else
|
||||||
|
remote_loc_dir="$REMOTE_LOCATIONS_DIR/_ip_$name"
|
||||||
|
fi
|
||||||
|
|
||||||
# SSL если нужно
|
ssh_cmd "mkdir -p $remote_loc_dir"
|
||||||
|
scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$remote_loc_dir/$name.conf" || { err "Ошибка деплоя сниппета"; rm -f "$tmp"; pause; return; }
|
||||||
|
rm -f "$tmp"
|
||||||
|
|
||||||
|
# Пересборка основного конфига
|
||||||
|
if [ -n "$domain" ]; then
|
||||||
|
rebuild_vhost_config "$domain" "$ext_port" "$vps_id"
|
||||||
|
else
|
||||||
|
rebuild_ip_config "$name" "$ext_port" "$tunnel_port" "$vps_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# SSL (теперь Certbot вызывается только если сертификата НЕТ)
|
||||||
if [ "$use_ssl" = "yes" ]; then
|
if [ "$use_ssl" = "yes" ]; then
|
||||||
msg "Получаю SSL через Certbot (может занять время)..."
|
if ssh_cmd "[ ! -f /etc/letsencrypt/live/$domain/fullchain.pem ]"; then
|
||||||
|
msg "SSL сертификат не найден. Запускаю Certbot..."
|
||||||
ssh_cmd "certbot --nginx -d $domain --non-interactive --agree-tos -m $CERTBOT_EMAIL" || warn "Certbot вернул ошибку"
|
ssh_cmd "certbot --nginx -d $domain --non-interactive --agree-tos -m $CERTBOT_EMAIL" || warn "Certbot вернул ошибку"
|
||||||
|
# После Certbot пересобираем конфиг, чтобы он прописал SSL пути
|
||||||
|
rebuild_vhost_config "$domain" "$ext_port" "$vps_id"
|
||||||
|
else
|
||||||
|
msg "SSL сертификат уже существует на сервере. Пропускаю Certbot."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Сохранение конфига сервиса (используем printf для защиты от спецсимволов и одинарные кавычки)
|
# Сохранение конфига сервиса (используем printf для защиты от спецсимволов и одинарные кавычки)
|
||||||
|
|
@ -683,6 +704,9 @@ do_ssl_interactive() {
|
||||||
sed -i "s/SVC_SSL=.*/SVC_SSL=\"yes\"/" "$SERVICES_DIR/$name.conf"
|
sed -i "s/SVC_SSL=.*/SVC_SSL=\"yes\"/" "$SERVICES_DIR/$name.conf"
|
||||||
sed -i "s/SVC_EXT_PORT=.*/SVC_EXT_PORT=\"443\"/" "$SERVICES_DIR/$name.conf"
|
sed -i "s/SVC_EXT_PORT=.*/SVC_EXT_PORT=\"443\"/" "$SERVICES_DIR/$name.conf"
|
||||||
|
|
||||||
|
# Пересборка основного конфига (теперь он подхватит сертификат)
|
||||||
|
rebuild_vhost_config "$SVC_DOMAIN" "443" "$SVC_VPS"
|
||||||
|
|
||||||
# Проверка автопродления (добавляем таймер/крон если нет)
|
# Проверка автопродления (добавляем таймер/крон если нет)
|
||||||
ssh_cmd "systemctl is-active certbot.timer >/dev/null 2>&1 || (crontab -l 2>/dev/null | grep -q certbot || (crontab -l 2>/dev/null; echo \"0 0,12 * * * certbot renew -q\") | crontab -)"
|
ssh_cmd "systemctl is-active certbot.timer >/dev/null 2>&1 || (crontab -l 2>/dev/null | grep -q certbot || (crontab -l 2>/dev/null; echo \"0 0,12 * * * certbot renew -q\") | crontab -)"
|
||||||
else
|
else
|
||||||
|
|
@ -796,10 +820,34 @@ do_remove_interactive() {
|
||||||
load_service "$name" || { pause; return; }
|
load_service "$name" || { pause; return; }
|
||||||
is_running "$name" && do_stop_service "$name"
|
is_running "$name" && do_stop_service "$name"
|
||||||
|
|
||||||
msg "Удаляю конфиги Nginx и пароли на VPS..."
|
msg "Удаляю конфигурации на VPS..."
|
||||||
ssh_cmd "rm -f $REMOTE_NGINX_DIR/rproxy_$name.conf /etc/nginx/rproxy_$name.htpasswd && nginx -t && systemctl reload nginx" >/dev/null 2>&1 || {
|
local remote_loc_dir
|
||||||
warn "Не удалось полностью очистить VPS (возможно файлы уже удалены)"
|
local is_domain=0
|
||||||
}
|
if [ -n "$SVC_DOMAIN" ]; then
|
||||||
|
remote_loc_dir="$REMOTE_LOCATIONS_DIR/$SVC_DOMAIN"
|
||||||
|
is_domain=1
|
||||||
|
else
|
||||||
|
remote_loc_dir="$REMOTE_LOCATIONS_DIR/_ip_$name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Удаляем сниппет и htpasswd
|
||||||
|
ssh_cmd "rm -f $remote_loc_dir/$name.conf /etc/nginx/rproxy_$name.htpasswd"
|
||||||
|
|
||||||
|
if [ "$is_domain" -eq 1 ]; then
|
||||||
|
# Проверяем, остались ли другие сервисы для этого домена
|
||||||
|
local remaining=$(ssh_cmd "ls $remote_loc_dir/*.conf 2>/dev/null | wc -l")
|
||||||
|
if [ "$remaining" -gt 0 ]; then
|
||||||
|
msg "Пересборка конфига домена (осталось $remaining сервисов)..."
|
||||||
|
rebuild_vhost_config "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_VPS"
|
||||||
|
else
|
||||||
|
msg "Последний сервис для домена. Удаляю основной конфиг..."
|
||||||
|
ssh_cmd "rm -f $REMOTE_NGINX_DIR/rproxy_dom_$SVC_DOMAIN.conf && rmdir $remote_loc_dir"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ssh_cmd "rm -f $REMOTE_NGINX_DIR/rproxy_svc_$name.conf && rm -rf $remote_loc_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
||||||
|
|
||||||
rm -f "$SERVICES_DIR/$name.conf"
|
rm -f "$SERVICES_DIR/$name.conf"
|
||||||
rm -f "$(get_pid_file "$name")"
|
rm -f "$(get_pid_file "$name")"
|
||||||
|
|
@ -896,13 +944,36 @@ do_edit_interactive() {
|
||||||
local tmp="/tmp/rproxy_edit_$name.conf"
|
local tmp="/tmp/rproxy_edit_$name.conf"
|
||||||
generate_nginx_conf "$name" "$SVC_TARGET_HOST" "$SVC_TARGET_PORT" "$SVC_TUNNEL_PORT" "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_NDM_AUTH" "$SVC_PATH" "$tmp"
|
generate_nginx_conf "$name" "$SVC_TARGET_HOST" "$SVC_TARGET_PORT" "$SVC_TUNNEL_PORT" "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_NDM_AUTH" "$SVC_PATH" "$tmp"
|
||||||
|
|
||||||
scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_$name.conf"
|
local remote_loc_dir
|
||||||
rm -f "$tmp"
|
if [ -n "$SVC_DOMAIN" ]; then
|
||||||
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
remote_loc_dir="$REMOTE_LOCATIONS_DIR/$SVC_DOMAIN"
|
||||||
|
else
|
||||||
|
remote_loc_dir="$REMOTE_LOCATIONS_DIR/_ip_$name"
|
||||||
|
fi
|
||||||
|
|
||||||
# SSL если он был настроен - восстанавливаем слушателей 443
|
msg "Обновление конфигурации на VPS..."
|
||||||
if [ "$SVC_SSL" = "yes" ]; then
|
ssh_cmd "mkdir -p $remote_loc_dir"
|
||||||
ssh_cmd "certbot --nginx -d $SVC_DOMAIN --non-interactive --agree-tos -m $CERTBOT_EMAIL" >/dev/null 2>&1
|
# Удаляем старый файл если он был в корне sites-enabled (миграция)
|
||||||
|
ssh_cmd "rm -f $REMOTE_NGINX_DIR/rproxy_$name.conf"
|
||||||
|
|
||||||
|
scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$remote_loc_dir/$name.conf"
|
||||||
|
rm -f "$tmp"
|
||||||
|
|
||||||
|
# Пересборка основного конфига
|
||||||
|
if [ -n "$SVC_DOMAIN" ]; then
|
||||||
|
rebuild_vhost_config "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_VPS"
|
||||||
|
else
|
||||||
|
rebuild_ip_config "$name" "$SVC_EXT_PORT" "$SVC_TUNNEL_PORT" "$SVC_VPS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# SSL если он был настроен или сертификат уже есть
|
||||||
|
if [ "$SVC_SSL" = "yes" ] || { [ -n "$SVC_DOMAIN" ] && ssh_cmd "[ -f /etc/letsencrypt/live/$SVC_DOMAIN/fullchain.pem ]"; }; then
|
||||||
|
# Если SVC_SSL была "no", но сертификат нашли — помечаем как "yes"
|
||||||
|
if [ "$SVC_SSL" = "no" ]; then
|
||||||
|
sed -i "s/SVC_SSL=.*/SVC_SSL=\"yes\"/" "$SERVICES_DIR/$name.conf"
|
||||||
|
# Пересобираем vhost чтобы включить SSL блок
|
||||||
|
rebuild_vhost_config "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_VPS"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Обновление htpasswd на VPS если включено
|
# Обновление htpasswd на VPS если включено
|
||||||
|
|
@ -1144,13 +1215,9 @@ generate_nginx_conf() {
|
||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$domain" ]; then
|
# Теперь эта функция генерирует ТОЛЬКО блок location
|
||||||
|
# Основной конфиг сервера будет собираться отдельно
|
||||||
cat > "$target_file" << NGINXEOF
|
cat > "$target_file" << NGINXEOF
|
||||||
server {
|
|
||||||
listen $ext_port;
|
|
||||||
server_name "$domain";
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_request_buffering off;
|
|
||||||
location $path {
|
location $path {
|
||||||
$auth_config
|
$auth_config
|
||||||
proxy_pass http://127.0.0.1:$tunnel_port/;
|
proxy_pass http://127.0.0.1:$tunnel_port/;
|
||||||
|
|
@ -1166,30 +1233,97 @@ server {
|
||||||
proxy_cookie_domain "$t_host" "\$host";
|
proxy_cookie_domain "$t_host" "\$host";
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
NGINXEOF
|
NGINXEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Функция для сборки основного конфига Nginx на VPS
|
||||||
|
rebuild_vhost_config() {
|
||||||
|
local domain="$1"
|
||||||
|
local ext_port="$2"
|
||||||
|
local vps_id="$3"
|
||||||
|
|
||||||
|
load_vps "$vps_id"
|
||||||
|
|
||||||
|
msg "Пересборка конфигурации для домена $domain..."
|
||||||
|
|
||||||
|
# Создаем директорию для локаций
|
||||||
|
ssh_cmd "mkdir -p $REMOTE_LOCATIONS_DIR/$domain"
|
||||||
|
|
||||||
|
# Проверяем наличие SSL сертификата на VPS
|
||||||
|
local cert_file="/etc/letsencrypt/live/$domain/fullchain.pem"
|
||||||
|
local key_file="/etc/letsencrypt/live/$domain/privkey.pem"
|
||||||
|
local has_ssl=0
|
||||||
|
ssh_cmd "[ -f $cert_file ] && [ -f $key_file ]" && has_ssl=1
|
||||||
|
|
||||||
|
local tmp_vhost="/tmp/rproxy_vhost_$domain.conf"
|
||||||
|
|
||||||
|
if [ -n "$domain" ]; then
|
||||||
|
# Конфиг для домена
|
||||||
|
cat > "$tmp_vhost" << EOF
|
||||||
|
server {
|
||||||
|
listen $ext_port;
|
||||||
|
server_name "$domain";
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_request_buffering off;
|
||||||
|
|
||||||
|
include $REMOTE_LOCATIONS_DIR/$domain/*.conf;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ "$has_ssl" -eq 1 ]; then
|
||||||
|
cat >> "$tmp_vhost" << EOF
|
||||||
|
listen 443 ssl;
|
||||||
|
ssl_certificate $cert_file;
|
||||||
|
ssl_certificate_key $key_file;
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
echo "}" >> "$tmp_vhost"
|
||||||
|
|
||||||
|
# Редирект с 80 на 443 если есть SSL
|
||||||
|
if [ "$has_ssl" -eq 1 ] && [ "$ext_port" != "80" ]; then
|
||||||
|
cat >> "$tmp_vhost" << EOF
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name "$domain";
|
||||||
|
return 301 https://\$host\$request_uri;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
scp_cmd "$tmp_vhost" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_dom_$domain.conf"
|
||||||
else
|
else
|
||||||
cat > "$target_file" << NGINXEOF
|
# Это не должно вызываться для IP-публикаций напрямую через эту функцию
|
||||||
|
# Но на всякий случай оставим заглушку
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
rm -f "$tmp_vhost"
|
||||||
|
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Специальная функция для IP-публикаций (они остаются одиночными)
|
||||||
|
rebuild_ip_config() {
|
||||||
|
local name="$1"
|
||||||
|
local ext_port="$2"
|
||||||
|
local tunnel_port="$3"
|
||||||
|
local vps_id="$4"
|
||||||
|
|
||||||
|
load_vps "$vps_id"
|
||||||
|
local tmp_ip="/tmp/rproxy_ip_$name.conf"
|
||||||
|
|
||||||
|
cat > "$tmp_ip" << EOF
|
||||||
server {
|
server {
|
||||||
listen $ext_port;
|
listen $ext_port;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_request_buffering off;
|
proxy_request_buffering off;
|
||||||
location $path {
|
|
||||||
$auth_config
|
include $REMOTE_LOCATIONS_DIR/_ip_$name/*.conf;
|
||||||
proxy_pass http://127.0.0.1:$tunnel_port/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host "$stealth_host";
|
|
||||||
proxy_set_header Origin "http://$stealth_host";
|
|
||||||
proxy_set_header X-Real-IP \$remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
||||||
proxy_cookie_domain "$t_host" "\$host";
|
|
||||||
proxy_redirect off;
|
|
||||||
}
|
}
|
||||||
}
|
EOF
|
||||||
NGINXEOF
|
ssh_cmd "mkdir -p $REMOTE_LOCATIONS_DIR/_ip_$name"
|
||||||
fi
|
scp_cmd "$tmp_ip" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_svc_$name.conf"
|
||||||
|
rm -f "$tmp_ip"
|
||||||
|
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
do_start_all() {
|
do_start_all() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue