Добавить cert-gen.sh

This commit is contained in:
2026-03-11 18:17:29 +00:00
commit 6d3db3665a

538
cert-gen.sh Normal file
View File

@@ -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 <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
C = RU
ST = Moscow
L = Moscow
O = NPM Local CA
CN = NPM Root CA
[v3_ca]
basicConstraints = critical, CA:TRUE
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
EOF
)
print_success "Корневой CA создан: $CA_DIR/root.crt"
}
# Создание промежуточного CA
create_intermediate_ca() {
print_step "Создание промежуточного CA..."
if [ -f "$CA_DIR/intermediate.key" ] && [ -f "$CA_DIR/intermediate.crt" ]; then
print_info "Промежуточный CA уже существует, используем существующий"
return 0
fi
# Ключ
openssl genrsa -out "$CA_DIR/intermediate.key" 2048 2>/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 <<EOF
basicConstraints = critical, CA:TRUE, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
EOF
) 2>/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 <user@server>"
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 "$@"