commit 6d3db3665a15cbfc922c3617c3d052ef93c90b81 Author: smolkik_adm Date: Wed Mar 11 18:17:29 2026 +0000 Добавить cert-gen.sh diff --git a/cert-gen.sh b/cert-gen.sh new file mode 100644 index 0000000..6741577 --- /dev/null +++ b/cert-gen.sh @@ -0,0 +1,538 @@ +#!/bin/bash + +# Цвета для вывода +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +MAGENTA='\033[0;35m' +NC='\033[0m' # No Color + +# Функции для вывода +print_success() { echo -e "${GREEN}[✓]${NC} $1"; } +print_error() { echo -e "${RED}[✗]${NC} $1"; } +print_info() { echo -e "${BLUE}[i]${NC} $1"; } +print_warning() { echo -e "${YELLOW}[!]${NC} $1"; } +print_step() { echo -e "${CYAN}[→]${NC} $1"; } +print_header() { echo -e "${MAGENTA}▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬${NC}"; } + +# Глобальные переменные +DOMAIN="" +BASE_DIR="$PWD/npm-certs" +CA_DIR="$BASE_DIR/ca" +DOMAIN_DIR="" +NPM_FORMAT="split" # split или single + +# Проверка зависимостей +check_dependencies() { + print_step "Проверка зависимостей..." + + local missing=0 + + if ! command -v openssl &> /dev/null; then + print_error "OpenSSL не установлен!" + print_info "Установите: sudo apt install openssl" + missing=1 + else + print_success "OpenSSL обнаружен" + fi + + if [ $missing -eq 1 ]; then + exit 1 + fi +} + +# Выбор формата +select_format() { + echo "" + print_header + echo -e "${CYAN} ВЫБОР ФОРМАТА ДЛЯ NGINX PROXY MANAGER${NC}" + print_header + echo "" + echo "NPM поддерживает 2 формата:" + echo "" + echo "1. ${GREEN}РАЗДЕЛЬНЫЙ (рекомендуется)${NC}" + echo " • Certificate: только доменный сертификат" + echo " • Intermediate: только промежуточный" + echo " • Key: приватный ключ" + echo "" + echo "2. ОБЪЕДИНЕННЫЙ" + echo " • Certificate: домен + intermediate" + echo " • Intermediate: оставить пустым" + echo " • Key: приватный ключ" + echo "" + + read -p "Выберите формат (1 или 2, по умолчанию 1): " choice + + case "$choice" in + 2) + NPM_FORMAT="single" + print_info "Выбран объединенный формат" + ;; + *) + NPM_FORMAT="split" + print_info "Выбран раздельный формат" + ;; + esac +} + +# Получение домена +get_domain() { + echo "" + while true; do + read -p "Введите домен (например: beszel.smolkik.local): " DOMAIN + + if [ -z "$DOMAIN" ]; then + print_error "Домен не может быть пустым!" + continue + fi + + # Простая проверка + if [[ "$DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)+$ ]]; then + DOMAIN_DIR="$BASE_DIR/$DOMAIN" + mkdir -p "$DOMAIN_DIR" + break + else + print_warning "Домен '$DOMAIN' выглядит подозрительно" + read -p "Продолжить? (y/N): " confirm + if [[ "$confirm" =~ ^[yYдД] ]]; then + DOMAIN_DIR="$BASE_DIR/$DOMAIN" + mkdir -p "$DOMAIN_DIR" + break + fi + fi + done + + # Запрос SAN + echo "" + read -p "Добавить wildcard (*.$DOMAIN)? (y/N): " add_wildcard + if [[ "$add_wildcard" =~ ^[yYдД] ]]; then + SAN="DNS:$DOMAIN, DNS:*.$DOMAIN, DNS:localhost, IP:127.0.0.1" + print_info "Добавлен wildcard: *.$DOMAIN" + else + SAN="DNS:$DOMAIN, DNS:localhost, IP:127.0.0.1" + fi + + # Дополнительные SAN + read -p "Добавить дополнительные домены/IP? (через запятую): " extra_sans + if [ -n "$extra_sans" ]; then + IFS=',' read -ra EXTRA <<< "$extra_sans" + for item in "${EXTRA[@]}"; do + item=$(echo "$item" | xargs) + if [[ "$item" =~ ^[0-9.]+\.[0-9.]+\.[0-9.]+\.[0-9.]+$ ]]; then + SAN="$SAN, IP:$item" + print_info "Добавлен IP: $item" + else + SAN="$SAN, DNS:$item" + print_info "Добавлен домен: $item" + fi + done + fi +} + +# Создание корневого CA +create_root_ca() { + print_step "Создание корневого CA..." + + if [ -f "$CA_DIR/root.key" ] && [ -f "$CA_DIR/root.crt" ]; then + print_info "Корневой CA уже существует, используем существующий" + return 0 + fi + + mkdir -p "$CA_DIR" + + # Создаем ключ + openssl genrsa -out "$CA_DIR/root.key" 4096 2>/dev/null + + # Создаем самоподписанный сертификат + openssl req -x509 -new -nodes -key "$CA_DIR/root.key" \ + -sha256 -days 8250 -out "$CA_DIR/root.crt" \ + -subj "/C=RU/ST=Moscow/L=Moscow/O=NPM Local CA/CN=NPM Root CA" \ + -config <(cat </dev/null + + # CSR + openssl req -new -key "$CA_DIR/intermediate.key" -out "$CA_DIR/intermediate.csr" \ + -subj "/C=RU/ST=Moscow/L=Moscow/O=NPM Local CA/CN=NPM Intermediate CA" 2>/dev/null + + # Подпись корневым CA + openssl x509 -req -in "$CA_DIR/intermediate.csr" \ + -CA "$CA_DIR/root.crt" -CAkey "$CA_DIR/root.key" -CAcreateserial \ + -out "$CA_DIR/intermediate.crt" -days 3650 -sha256 \ + -extfile <(cat </dev/null + + rm -f "$CA_DIR/intermediate.csr" "$CA_DIR/root.srl" + + print_success "Промежуточный CA создан: $CA_DIR/intermediate.crt" +} + +# Создание доменного сертификата +create_domain_cert() { + print_step "Создание сертификата для $DOMAIN..." + + # Ключ домена + openssl genrsa -out "$DOMAIN_DIR/$DOMAIN.key" 2048 2>/dev/null + + # CSR для домена + cat > "$DOMAIN_DIR/csr.cnf" << EOF +[req] +default_bits = 2048 +prompt = no +default_md = sha256 +distinguished_name = dn +req_extensions = req_ext + +[dn] +C = RU +ST = Moscow +L = Moscow +O = Local Development +CN = $DOMAIN + +[req_ext] +subjectAltName = $SAN +EOF + + openssl req -new -key "$DOMAIN_DIR/$DOMAIN.key" \ + -out "$DOMAIN_DIR/$DOMAIN.csr" \ + -config "$DOMAIN_DIR/csr.cnf" 2>/dev/null + + # Конфиг для подписи + cat > "$DOMAIN_DIR/cert.ext" << EOF +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +subjectAltName = $SAN +EOF + + # Подпись промежуточным CA + openssl x509 -req -in "$DOMAIN_DIR/$DOMAIN.csr" \ + -CA "$CA_DIR/intermediate.crt" -CAkey "$CA_DIR/intermediate.key" -CAcreateserial \ + -out "$DOMAIN_DIR/$DOMAIN.crt" -days 365 -sha256 \ + -extfile "$DOMAIN_DIR/cert.ext" 2>/dev/null + + # Очистка временных файлов + rm -f "$DOMAIN_DIR/csr.cnf" "$DOMAIN_DIR/cert.ext" "$DOMAIN_DIR/$DOMAIN.csr" "$CA_DIR/intermediate.srl" + + print_success "Доменный сертификат создан: $DOMAIN_DIR/$DOMAIN.crt" +} + +# Подготовка файлов для NPM (РАЗДЕЛЬНЫЙ формат) +prepare_npm_split() { + print_step "Подготовка файлов для NPM (раздельный формат)..." + + # 1. Доменный сертификат (ТОЛЬКО один!) + cp "$DOMAIN_DIR/$DOMAIN.crt" "$DOMAIN_DIR/npm-certificate.crt" + + # Проверяем что только один сертификат + local cert_count=$(grep -c "BEGIN CERTIFICATE" "$DOMAIN_DIR/npm-certificate.crt") + if [ "$cert_count" -gt 1 ]; then + print_warning "В доменном сертификате $cert_count сертификатов, оставляем первый" + awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{if(++count==1)print}' "$DOMAIN_DIR/$DOMAIN.crt" > "$DOMAIN_DIR/npm-certificate.crt" + fi + + # 2. Промежуточный сертификат (ТОЛЬКО один!) + cp "$CA_DIR/intermediate.crt" "$DOMAIN_DIR/npm-intermediate.crt" + + cert_count=$(grep -c "BEGIN CERTIFICATE" "$DOMAIN_DIR/npm-intermediate.crt") + if [ "$cert_count" -gt 1 ]; then + print_warning "В промежуточном $cert_count сертификатов, оставляем первый" + awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{if(++count==1)print}' "$CA_DIR/intermediate.crt" > "$DOMAIN_DIR/npm-intermediate.crt" + fi + + # 3. Приватный ключ + cp "$DOMAIN_DIR/$DOMAIN.key" "$DOMAIN_DIR/npm-private.key" + + # Конвертируем ключ в PKCS#8 если нужно + if grep -q "BEGIN RSA PRIVATE KEY" "$DOMAIN_DIR/npm-private.key"; then + print_info "Конвертируем ключ в PKCS#8 формат" + openssl pkcs8 -topk8 -nocrypt -in "$DOMAIN_DIR/npm-private.key" \ + -out "$DOMAIN_DIR/npm-private-pkcs8.key" 2>/dev/null + mv "$DOMAIN_DIR/npm-private-pkcs8.key" "$DOMAIN_DIR/npm-private.key" + fi + + # 4. Создаем chain.pem для других целей + cat "$DOMAIN_DIR/$DOMAIN.crt" "$CA_DIR/intermediate.crt" > "$DOMAIN_DIR/chain.pem" + + print_success "Файлы подготовлены (раздельный формат)" +} + +# Подготовка файлов для NPM (ОБЪЕДИНЕННЫЙ формат) +prepare_npm_single() { + print_step "Подготовка файлов для NPM (объединенный формат)..." + + # 1. Доменный сертификат + промежуточный + cat "$DOMAIN_DIR/$DOMAIN.crt" "$CA_DIR/intermediate.crt" > "$DOMAIN_DIR/npm-certificate-chain.crt" + + # 2. Приватный ключ + cp "$DOMAIN_DIR/$DOMAIN.key" "$DOMAIN_DIR/npm-private.key" + + # Конвертируем ключ в PKCS#8 если нужно + if grep -q "BEGIN RSA PRIVATE KEY" "$DOMAIN_DIR/npm-private.key"; then + print_info "Конвертируем ключ в PKCS#8 формат" + openssl pkcs8 -topk8 -nocrypt -in "$DOMAIN_DIR/npm-private.key" \ + -out "$DOMAIN_DIR/npm-private-pkcs8.key" 2>/dev/null + mv "$DOMAIN_DIR/npm-private-pkcs8.key" "$DOMAIN_DIR/npm-private.key" + fi + + print_success "Файлы подготовлены (объединенный формат)" +} + +# Проверка цепочки +verify_chain() { + print_step "Проверка цепочки сертификатов..." + + if openssl verify -CAfile "$CA_DIR/root.crt" \ + -untrusted "$CA_DIR/intermediate.crt" \ + "$DOMAIN_DIR/$DOMAIN.crt" &>/dev/null; then + print_success "✅ Цепочка сертификатов валидна!" + else + print_error "❌ Ошибка проверки цепочки" + print_info "Выполняем ручную проверку..." + openssl verify -CAfile "$CA_DIR/root.crt" \ + -untrusted "$CA_DIR/intermediate.crt" \ + "$DOMAIN_DIR/$DOMAIN.crt" + fi +} + +# Показать отпечатки +show_fingerprints() { + print_step "Отпечатки сертификатов:" + + echo -e "${YELLOW}Root CA:${NC}" + openssl x509 -in "$CA_DIR/root.crt" -fingerprint -sha256 -noout | sed 's/SHA256 Fingerprint=//' + + echo -e "${YELLOW}Intermediate CA:${NC}" + openssl x509 -in "$CA_DIR/intermediate.crt" -fingerprint -sha256 -noout | sed 's/SHA256 Fingerprint=//' + + echo -e "${YELLOW}Domain ($DOMAIN):${NC}" + openssl x509 -in "$DOMAIN_DIR/$DOMAIN.crt" -fingerprint -sha256 -noout | sed 's/SHA256 Fingerprint=//' +} + +# Создать инструкцию для NPM +create_npm_instructions() { + print_step "Создание инструкции для NPM..." + + cat > "$DOMAIN_DIR/NPM_INSTRUCTIONS.md" << EOF +# 🚀 Инструкция для Nginx Proxy Manager +# Домен: $DOMAIN + +## 📁 ФАЙЛЫ: + +$(if [ "$NPM_FORMAT" = "split" ]; then +echo "1. \`npm-private.key\` - Приватный ключ" +echo "2. \`npm-certificate.crt\` - Доменный сертификат" +echo "3. \`npm-intermediate.crt\` - Промежуточный сертификат" +else +echo "1. \`npm-private.key\` - Приватный ключ" +echo "2. \`npm-certificate-chain.crt\` - Домен + Intermediate" +fi) + +## 🖥️ КАК ДОБАВИТЬ В NPM: + +1. Откройте **Nginx Proxy Manager** → **SSL Certificates** → **Add SSL Certificate** + +2. Заполните поля: + + **Name:** $DOMAIN + + **Certificate Key:** $(if [ "$NPM_FORMAT" = "split" ]; then echo "Выберите файл \`npm-private.key\`"; else echo "Выберите файл \`npm-private.key\`"; fi) + + **Certificate:** $(if [ "$NPM_FORMAT" = "split" ]; then echo "Выберите файл \`npm-certificate.crt\`"; else echo "Выберите файл \`npm-certificate-chain.crt\`"; fi) + + $(if [ "$NPM_FORMAT" = "split" ]; then echo "**Intermediate Certificate:** Выберите файл \`npm-intermediate.crt\`"; else echo "**Intermediate Certificate:** ОСТАВЬТЕ ПУСТЫМ"; fi) + +3. Нажмите **Save** + +## 🔧 НАСТРОЙКА ПРОКСИ ХОСТА: + +1. Откройте **Proxy Hosts** +2. Выберите или создайте хост для \`$DOMAIN\` +3. Перейдите на вкладку **SSL** +4. Выберите созданный сертификат +5. Включите опции: + - ☑ Force SSL + - ☑ HTTP/2 Support + - ☐ HSTS Enabled (опционально) +6. Нажмите **Save** + +## 🌐 УСТАНОВКА КОРНЕВОГО СЕРТИФИКАТА: + +Для доверия в браузерах установите корневой сертификат: + +### Linux: +\`\`\`bash +sudo cp $CA_DIR/root.crt /usr/local/share/ca-certificates/ +sudo update-ca-certificates +\`\`\` + +### macOS: +\`\`\`bash +sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $CA_DIR/root.crt +\`\`\` + +## 📋 ПРОВЕРКА: + +\`\`\`bash +# Проверка цепочки +openssl verify -CAfile $CA_DIR/root.crt \\ + -untrusted $CA_DIR/intermediate.crt \\ + $DOMAIN_DIR/$DOMAIN.crt + +# Просмотр SAN +openssl x509 -in $DOMAIN_DIR/$DOMAIN.crt -text -noout | grep -A 5 "Subject Alternative Name" +\`\`\` + +## 🎯 ОТПЕЧАТКИ: + +- **Root CA:** $(openssl x509 -in "$CA_DIR/root.crt" -fingerprint -sha256 -noout | cut -d= -f2) +- **Intermediate:** $(openssl x509 -in "$CA_DIR/intermediate.crt" -fingerprint -sha256 -noout | cut -d= -f2) +- **Domain:** $(openssl x509 -in "$DOMAIN_DIR/$DOMAIN.crt" -fingerprint -sha256 -noout | cut -d= -f2) + +--- +*Создано $(date)* +EOF + + print_success "Инструкция создана: $DOMAIN_DIR/NPM_INSTRUCTIONS.md" +} + +# Создать скрипт для копирования +create_copy_script() { + cat > "$DOMAIN_DIR/copy-to-server.sh" << 'EOF' +#!/bin/bash +# Скрипт для копирования сертификатов на сервер + +if [ -z "$1" ]; then + echo "Использование: $0 " + exit 1 +fi + +SERVER="$1" +DOMAIN="$(basename "$(pwd)")" + +echo "Копирование сертификатов для $DOMAIN на $SERVER..." + +# Копируем файлы +scp npm-private.key npm-certificate.crt npm-intermediate.crt "$SERVER:/tmp/" + +echo "" +echo "✅ Файлы скопированы!" +echo "" +echo "На сервере выполните:" +echo "sudo mkdir -p /etc/nginx-proxy-manager/certs/" +echo "sudo cp /tmp/npm-*.crt /tmp/npm-*.key /etc/nginx-proxy-manager/certs/" +echo "sudo chown -R 1000:1000 /etc/nginx-proxy-manager/certs/" +echo "sudo docker restart nginx-proxy-manager" +EOF + + chmod +x "$DOMAIN_DIR/copy-to-server.sh" +} + +# Главное меню +show_main_menu() { + echo "" + print_header + echo -e "${CYAN} ГЕНЕРАТОР SSL ДЛЯ NGINX PROXY MANAGER${NC}" + print_header + echo "" +} + +# Основная функция +main() { + show_main_menu + check_dependencies + select_format + get_domain + create_root_ca + create_intermediate_ca + create_domain_cert + + if [ "$NPM_FORMAT" = "split" ]; then + prepare_npm_split + else + prepare_npm_single + fi + + verify_chain + show_fingerprints + create_npm_instructions + create_copy_script + + # Финальный вывод + echo "" + print_header + echo -e "${GREEN} УСПЕШНО ЗАВЕРШЕНО!${NC}" + print_header + echo "" + + echo -e "${YELLOW}📁 Ваши файлы:${NC}" + echo "Директория: $DOMAIN_DIR/" + echo "" + ls -la "$DOMAIN_DIR/" | grep -E "\.(crt|key|pem)$" | awk '{print " " $9 " (" $5 " bytes)"}' + + echo "" + echo -e "${YELLOW}🎯 Для NPM используйте:${NC}" + if [ "$NPM_FORMAT" = "split" ]; then + echo "1. Certificate Key: $(basename "$DOMAIN_DIR/npm-private.key")" + echo "2. Certificate: $(basename "$DOMAIN_DIR/npm-certificate.crt")" + echo "3. Intermediate: $(basename "$DOMAIN_DIR/npm-intermediate.crt")" + else + echo "1. Certificate Key: $(basename "$DOMAIN_DIR/npm-private.key")" + echo "2. Certificate: $(basename "$DOMAIN_DIR/npm-certificate-chain.crt")" + echo "3. Intermediate: (ОСТАВЬТЕ ПУСТЫМ)" + fi + + echo "" + echo -e "${YELLOW}📄 Подробная инструкция:${NC}" + echo " $DOMAIN_DIR/NPM_INSTRUCTIONS.md" + + echo "" + echo -e "${YELLOW}🚀 Быстрое копирование:${NC}" + echo " cd $DOMAIN_DIR" + echo " ./copy-to-server.sh user@your-server" + + echo "" + print_header +} + +# Запуск +main "$@" \ No newline at end of file