Files
ssl-gen-local/cert-gen.sh

538 lines
18 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 "$@"