This commit is contained in:
76
.env.example
76
.env.example
@@ -1,34 +1,66 @@
|
|||||||
# Django настройки
|
# Django настройки
|
||||||
DJANGO_SECRET_KEY=django-insecure-your-secret-key-here-change-this-in-production
|
DJANGO_SECRET_KEY=
|
||||||
DJANGO_DEBUG=True
|
DJANGO_DEBUG=False
|
||||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,0.0.0.0
|
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
|
||||||
|
DJANGO_CSRF_TRUSTED_ORIGINS=
|
||||||
|
|
||||||
|
# CORS настройки
|
||||||
|
CORS_ALLOWED_ORIGINS=
|
||||||
|
CORS_ALLOW_ALL_ORIGINS=False
|
||||||
|
CORS_ALLOW_CREDENTIALS=True
|
||||||
|
CORS_ALLOW_HEADERS=accept,accept-encoding,authorization,content-type,dnt,origin,user-agent,x-csrftoken,x-requested-with
|
||||||
|
|
||||||
|
# Локализация
|
||||||
|
DJANGO_LANGUAGE_CODE=ru-ru
|
||||||
|
DJANGO_TIME_ZONE=UTC
|
||||||
|
DJANGO_USE_I18N=True
|
||||||
|
DJANGO_USE_TZ=True
|
||||||
|
|
||||||
|
# Статические файлы
|
||||||
|
DJANGO_STATIC_URL=/static/
|
||||||
|
DJANGO_MEDIA_URL=/storage/
|
||||||
|
|
||||||
|
# API настройки
|
||||||
|
DJANGO_APPEND_SLASH=False
|
||||||
|
|
||||||
|
# JWT настройки
|
||||||
|
JWT_ACCESS_TOKEN_LIFETIME_MINUTES=60
|
||||||
|
JWT_REFRESH_TOKEN_LIFETIME_DAYS=1
|
||||||
|
|
||||||
# База данных PostgreSQL
|
# База данных PostgreSQL
|
||||||
DATABASE_ENGINE=django.db.backends.postgresql
|
DATABASE_ENGINE=django.db.backends.postgresql
|
||||||
DATABASE_NAME=links_db
|
DATABASE_NAME=
|
||||||
DATABASE_USER=links_user
|
DATABASE_USER=
|
||||||
DATABASE_PASSWORD=links_password
|
DATABASE_PASSWORD=
|
||||||
DATABASE_HOST=db
|
DATABASE_HOST=db
|
||||||
DATABASE_PORT=5432
|
DATABASE_PORT=5432
|
||||||
|
|
||||||
# PostgreSQL настройки для контейнера
|
# PostgreSQL настройки для контейнера
|
||||||
POSTGRES_DB=links_db
|
POSTGRES_DB=
|
||||||
POSTGRES_USER=links_user
|
POSTGRES_USER=
|
||||||
POSTGRES_PASSWORD=links_password
|
POSTGRES_PASSWORD=
|
||||||
|
|
||||||
# Frontend настройки
|
# Frontend настройки
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
NEXT_PUBLIC_API_URL=
|
||||||
|
|
||||||
# Опциональные настройки
|
# Безопасность (для продакшена)
|
||||||
# DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
|
DJANGO_SECURE_SSL_REDIRECT=False
|
||||||
# DJANGO_EMAIL_HOST=
|
DJANGO_SECURE_HSTS_SECONDS=0
|
||||||
# DJANGO_EMAIL_PORT=587
|
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=False
|
||||||
# DJANGO_EMAIL_HOST_USER=
|
DJANGO_SECURE_HSTS_PRELOAD=False
|
||||||
# DJANGO_EMAIL_HOST_PASSWORD=
|
DJANGO_SECURE_CONTENT_TYPE_NOSNIFF=True
|
||||||
# DJANGO_EMAIL_USE_TLS=True
|
DJANGO_SECURE_BROWSER_XSS_FILTER=True
|
||||||
|
DJANGO_X_FRAME_OPTIONS=DENY
|
||||||
|
|
||||||
# Для продакшена
|
# Email настройки (опционально)
|
||||||
# DJANGO_SECURE_SSL_REDIRECT=True
|
DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
|
||||||
# DJANGO_SECURE_HSTS_SECONDS=31536000
|
DJANGO_EMAIL_HOST=
|
||||||
# DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=True
|
DJANGO_EMAIL_PORT=587
|
||||||
# DJANGO_SECURE_HSTS_PRELOAD=True
|
DJANGO_EMAIL_HOST_USER=
|
||||||
|
DJANGO_EMAIL_HOST_PASSWORD=
|
||||||
|
DJANGO_EMAIL_USE_TLS=True
|
||||||
|
|
||||||
|
# SSL настройки (для Let's Encrypt)
|
||||||
|
DOMAIN=
|
||||||
|
EMAIL=
|
||||||
|
ACME_CA_URI=https://acme-v02.api.letsencrypt.org/directory
|
||||||
@@ -29,35 +29,20 @@ SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
|
|||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = os.getenv('DJANGO_DEBUG', 'False') == 'True'
|
DEBUG = os.getenv('DJANGO_DEBUG', 'False') == 'True'
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*'] # Разрешаем доступ с любых хостов для разработки
|
# Allowed hosts из переменных окружения
|
||||||
|
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
|
||||||
|
|
||||||
|
# CSRF trusted origins из переменных окружения
|
||||||
|
CSRF_TRUSTED_ORIGINS = os.getenv('DJANGO_CSRF_TRUSTED_ORIGINS', '').split(',') if os.getenv('DJANGO_CSRF_TRUSTED_ORIGINS') else []
|
||||||
|
|
||||||
# Отключаем APPEND_SLASH для корректной работы API с Next.js proxy
|
# Отключаем APPEND_SLASH для корректной работы API с Next.js proxy
|
||||||
APPEND_SLASH = False
|
APPEND_SLASH = os.getenv('DJANGO_APPEND_SLASH', 'False') == 'True'
|
||||||
|
|
||||||
CORS_ALLOWED_ORIGINS = [
|
# CORS настройки из переменных окружения
|
||||||
"http://127.0.0.1:3000",
|
CORS_ALLOWED_ORIGINS = os.getenv('CORS_ALLOWED_ORIGINS', '').split(',') if os.getenv('CORS_ALLOWED_ORIGINS') else []
|
||||||
"http://localhost:3000",
|
CORS_ALLOW_ALL_ORIGINS = os.getenv('CORS_ALLOW_ALL_ORIGINS', 'False') == 'True'
|
||||||
"http://127.0.0.1:3001",
|
CORS_ALLOW_CREDENTIALS = os.getenv('CORS_ALLOW_CREDENTIALS', 'True') == 'True'
|
||||||
"http://localhost:3001",
|
CORS_ALLOW_HEADERS = os.getenv('CORS_ALLOW_HEADERS', 'accept,accept-encoding,authorization,content-type,dnt,origin,user-agent,x-csrftoken,x-requested-with').split(',')
|
||||||
"http://192.168.219.108:3000",
|
|
||||||
"http://192.168.219.108:3001",
|
|
||||||
"http://192.168.219.108:8000",
|
|
||||||
"http://192.168.219.108:8001",
|
|
||||||
]
|
|
||||||
|
|
||||||
CORS_ALLOW_ALL_ORIGINS = True # Для разработки
|
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
|
||||||
CORS_ALLOW_HEADERS = [
|
|
||||||
'accept',
|
|
||||||
'accept-encoding',
|
|
||||||
'authorization',
|
|
||||||
'content-type',
|
|
||||||
'dnt',
|
|
||||||
'origin',
|
|
||||||
'user-agent',
|
|
||||||
'x-csrftoken',
|
|
||||||
'x-requested-with',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
@@ -126,8 +111,8 @@ REST_FRAMEWORK = {
|
|||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
|
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=int(os.getenv('JWT_ACCESS_TOKEN_LIFETIME_MINUTES', '60'))),
|
||||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
'REFRESH_TOKEN_LIFETIME': timedelta(days=int(os.getenv('JWT_REFRESH_TOKEN_LIFETIME_DAYS', '1'))),
|
||||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,13 +155,13 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
||||||
|
|
||||||
LANGUAGE_CODE = 'ru-ru'
|
LANGUAGE_CODE = os.getenv('DJANGO_LANGUAGE_CODE', 'ru-ru')
|
||||||
|
|
||||||
TIME_ZONE = 'UTC'
|
TIME_ZONE = os.getenv('DJANGO_TIME_ZONE', 'UTC')
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = os.getenv('DJANGO_USE_I18N', 'True') == 'True'
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = os.getenv('DJANGO_USE_TZ', 'True') == 'True'
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
@@ -185,7 +170,7 @@ USE_TZ = True
|
|||||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||||
|
|
||||||
# URL, по которому статика будет доступна
|
# URL, по которому статика будет доступна
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = os.getenv('DJANGO_STATIC_URL', '/static/')
|
||||||
|
|
||||||
# WhiteNoise настройки
|
# WhiteNoise настройки
|
||||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||||
@@ -195,5 +180,14 @@ STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
|||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
MEDIA_URL = '/storage/'
|
MEDIA_URL = os.getenv('DJANGO_MEDIA_URL', '/storage/')
|
||||||
MEDIA_ROOT = BASE_DIR / 'storage'
|
MEDIA_ROOT = BASE_DIR / 'storage'
|
||||||
|
|
||||||
|
# Настройки безопасности из переменных окружения
|
||||||
|
SECURE_SSL_REDIRECT = os.getenv('DJANGO_SECURE_SSL_REDIRECT', 'False') == 'True'
|
||||||
|
SECURE_HSTS_SECONDS = int(os.getenv('DJANGO_SECURE_HSTS_SECONDS', '0'))
|
||||||
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = os.getenv('DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', 'False') == 'True'
|
||||||
|
SECURE_HSTS_PRELOAD = os.getenv('DJANGO_SECURE_HSTS_PRELOAD', 'False') == 'True'
|
||||||
|
SECURE_CONTENT_TYPE_NOSNIFF = os.getenv('DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', 'True') == 'True'
|
||||||
|
SECURE_BROWSER_XSS_FILTER = os.getenv('DJANGO_SECURE_BROWSER_XSS_FILTER', 'True') == 'True'
|
||||||
|
X_FRAME_OPTIONS = os.getenv('DJANGO_X_FRAME_OPTIONS', 'DENY')
|
||||||
94
scripts/README_env_generator.md
Normal file
94
scripts/README_env_generator.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# Environment Configuration Generator
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Скрипт `scripts/generate_env.sh` создает файл `.env` на основе шаблона `.env.example` с интерактивным вводом параметров или автоматической генерацией безопасных значений.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
### Интерактивный режим (разработка)
|
||||||
|
```bash
|
||||||
|
./scripts/generate_env.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Автоматический режим для продакшена
|
||||||
|
```bash
|
||||||
|
./scripts/generate_env.sh --production
|
||||||
|
```
|
||||||
|
|
||||||
|
### Неинтерактивный режим
|
||||||
|
```bash
|
||||||
|
./scripts/generate_env.sh --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Комбинированный режим
|
||||||
|
```bash
|
||||||
|
./scripts/generate_env.sh --production --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Функции
|
||||||
|
|
||||||
|
### 🔒 Автоматическая генерация безопасных паролей
|
||||||
|
- Django SECRET_KEY (криптографически стойкий)
|
||||||
|
- Пароли базы данных (случайные 25-символьные)
|
||||||
|
- Все пароли генерируются с использованием OpenSSL или Python secrets
|
||||||
|
|
||||||
|
### 🚀 Продакшен режим (`--production`)
|
||||||
|
- Автоматически устанавливает `DJANGO_DEBUG=False`
|
||||||
|
- Включает SSL настройки (HSTS, SSL redirect)
|
||||||
|
- Генерирует криптографически стойкие пароли
|
||||||
|
- Запрашивает домен и email для SSL сертификатов
|
||||||
|
- Настраивает CORS только для указанного домена
|
||||||
|
|
||||||
|
### ⚡ Неинтерактивный режим (`--yes`)
|
||||||
|
- Использует значения из переменных окружения
|
||||||
|
- Подходит для CI/CD и автоматизированного развертывания
|
||||||
|
- Сохраняет значения по умолчанию из `.env.example`
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
### Быстрая настройка для разработки
|
||||||
|
```bash
|
||||||
|
# Создаст .env с базовыми настройками для localhost
|
||||||
|
./scripts/generate_env.sh --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Настройка продакшена
|
||||||
|
```bash
|
||||||
|
# Интерактивная настройка с вводом домена
|
||||||
|
./scripts/generate_env.sh --production
|
||||||
|
|
||||||
|
# Или автоматически, если домен в переменной окружения
|
||||||
|
DOMAIN=example.com EMAIL=admin@example.com ./scripts/generate_env.sh --production --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Переменные окружения для автоматизации
|
||||||
|
```bash
|
||||||
|
export DJANGO_SECRET_KEY="your-secret-key"
|
||||||
|
export DATABASE_PASSWORD="your-db-password"
|
||||||
|
export DOMAIN="example.com"
|
||||||
|
export EMAIL="admin@example.com"
|
||||||
|
|
||||||
|
./scripts/generate_env.sh --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- Пароли генерируются криптографически стойкими методами
|
||||||
|
- Секретные ключи никогда не выводятся в консоль
|
||||||
|
- В продакшен режиме автоматически отключается DEBUG
|
||||||
|
- Включаются все необходимые заголовки безопасности
|
||||||
|
|
||||||
|
## Интеграция
|
||||||
|
|
||||||
|
Скрипт интегрирован в:
|
||||||
|
- `setup.sh` - основной скрипт установки
|
||||||
|
- `Makefile` - команды для управления проектом
|
||||||
|
- `scripts/master-deploy.sh` - скрипт развертывания
|
||||||
|
|
||||||
|
## Совместимость
|
||||||
|
|
||||||
|
- ✅ Linux/macOS/WSL
|
||||||
|
- ✅ Docker environments
|
||||||
|
- ✅ CI/CD pipelines
|
||||||
|
- ✅ OpenSSL и Python 3.x
|
||||||
@@ -3,23 +3,39 @@ set -euo pipefail
|
|||||||
|
|
||||||
# scripts/generate_env.sh
|
# scripts/generate_env.sh
|
||||||
# Interactive generator for .env from .env.example
|
# Interactive generator for .env from .env.example
|
||||||
# Usage: ./scripts/generate_env.sh [--yes]
|
# Usage: ./scripts/generate_env.sh [--yes] [--production]
|
||||||
|
|
||||||
BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
EXAMPLE="$BASE_DIR/.env.example"
|
EXAMPLE="$BASE_DIR/.env.example"
|
||||||
TARGET="$BASE_DIR/.env"
|
TARGET="$BASE_DIR/.env"
|
||||||
|
|
||||||
confirm=false
|
confirm=false
|
||||||
if [[ "${1:-}" == "--yes" ]]; then
|
production=false
|
||||||
confirm=true
|
|
||||||
fi
|
# Parse arguments
|
||||||
|
for arg in "$@"; do
|
||||||
|
case $arg in
|
||||||
|
--yes)
|
||||||
|
confirm=true
|
||||||
|
;;
|
||||||
|
--production)
|
||||||
|
production=true
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 [--yes] [--production]"
|
||||||
|
echo " --yes Non-interactive mode, use defaults or environment variables"
|
||||||
|
echo " --production Setup for production environment"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
if [[ ! -f "$EXAMPLE" ]]; then
|
if [[ ! -f "$EXAMPLE" ]]; then
|
||||||
echo "Error: .env.example not found at $EXAMPLE"
|
echo "Error: .env.example not found at $EXAMPLE"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Generating $TARGET from $EXAMPLE"
|
echo "🔧 Generating $TARGET from $EXAMPLE"
|
||||||
|
|
||||||
if [[ -f "$TARGET" && "$confirm" = false ]]; then
|
if [[ -f "$TARGET" && "$confirm" = false ]]; then
|
||||||
read -p "$TARGET exists. Overwrite? (y/N): " ans
|
read -p "$TARGET exists. Overwrite? (y/N): " ans
|
||||||
@@ -29,9 +45,75 @@ if [[ -f "$TARGET" && "$confirm" = false ]]; then
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Function to generate secure passwords
|
||||||
|
generate_password() {
|
||||||
|
openssl rand -base64 32 | tr -d "=+/" | cut -c1-25
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to generate Django secret key
|
||||||
|
generate_secret_key() {
|
||||||
|
python3 -c "
|
||||||
|
from django.core.management.utils import get_random_secret_key
|
||||||
|
print(get_random_secret_key())
|
||||||
|
" 2>/dev/null || openssl rand -base64 50 | tr -d "=+/"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to safely update env variable
|
||||||
|
update_env_var() {
|
||||||
|
local key="$1"
|
||||||
|
local value="$2"
|
||||||
|
local file="$3"
|
||||||
|
|
||||||
|
# Remove existing line and add new one
|
||||||
|
grep -v "^${key}=" "$file" > "${file}.tmp" 2>/dev/null || true
|
||||||
|
echo "${key}=${value}" >> "${file}.tmp"
|
||||||
|
mv "${file}.tmp" "$file"
|
||||||
|
}
|
||||||
|
|
||||||
# Copy example first
|
# Copy example first
|
||||||
cp "$EXAMPLE" "$TARGET"
|
cp "$EXAMPLE" "$TARGET"
|
||||||
|
|
||||||
|
# Production mode adjustments
|
||||||
|
if [[ "$production" = true ]]; then
|
||||||
|
echo "🚀 Setting up for production environment..."
|
||||||
|
|
||||||
|
# Generate secure values
|
||||||
|
SECRET_KEY=$(generate_secret_key)
|
||||||
|
DB_PASSWORD=$(generate_password)
|
||||||
|
|
||||||
|
# Set production values
|
||||||
|
update_env_var "DJANGO_SECRET_KEY" "$SECRET_KEY" "$TARGET"
|
||||||
|
update_env_var "DJANGO_DEBUG" "False" "$TARGET"
|
||||||
|
update_env_var "DATABASE_PASSWORD" "$DB_PASSWORD" "$TARGET"
|
||||||
|
update_env_var "POSTGRES_PASSWORD" "$DB_PASSWORD" "$TARGET"
|
||||||
|
update_env_var "DJANGO_SECURE_SSL_REDIRECT" "True" "$TARGET"
|
||||||
|
update_env_var "DJANGO_SECURE_HSTS_SECONDS" "31536000" "$TARGET"
|
||||||
|
update_env_var "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS" "True" "$TARGET"
|
||||||
|
update_env_var "DJANGO_SECURE_HSTS_PRELOAD" "True" "$TARGET"
|
||||||
|
|
||||||
|
# Prompt for domain
|
||||||
|
if [[ "$confirm" = false ]]; then
|
||||||
|
read -p "Enter your domain (e.g., example.com): " domain
|
||||||
|
read -p "Enter your email for SSL certificate: " email
|
||||||
|
|
||||||
|
if [[ -n "$domain" ]]; then
|
||||||
|
update_env_var "DOMAIN" "$domain" "$TARGET"
|
||||||
|
update_env_var "DJANGO_ALLOWED_HOSTS" "${domain},localhost,127.0.0.1" "$TARGET"
|
||||||
|
update_env_var "DJANGO_CSRF_TRUSTED_ORIGINS" "https://${domain}" "$TARGET"
|
||||||
|
update_env_var "CORS_ALLOWED_ORIGINS" "https://${domain}" "$TARGET"
|
||||||
|
update_env_var "NEXT_PUBLIC_API_URL" "https://${domain}" "$TARGET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$email" ]]; then
|
||||||
|
update_env_var "EMAIL" "$email" "$TARGET"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Production configuration generated with secure passwords"
|
||||||
|
echo "📝 Database password: $DB_PASSWORD"
|
||||||
|
echo "⚠️ Save this password securely!"
|
||||||
|
fi
|
||||||
|
|
||||||
# For each variable in example, prompt the user to keep or change
|
# For each variable in example, prompt the user to keep or change
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ "$line" =~ ^# ]] || [[ -z "$line" ]]; then
|
if [[ "$line" =~ ^# ]] || [[ -z "$line" ]]; then
|
||||||
@@ -56,26 +138,65 @@ while IFS= read -r line; do
|
|||||||
env_val="${!key}"
|
env_val="${!key}"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$env_val" ]]; then
|
if [[ -n "$env_val" ]]; then
|
||||||
sed -i "s|^$key=.*|$key=$env_val|" "$TARGET"
|
update_env_var "$key" "$env_val" "$TARGET"
|
||||||
fi
|
fi
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Skip if production mode already set the value
|
||||||
|
if [[ "$production" = true ]]; then
|
||||||
|
case "$key" in
|
||||||
|
DJANGO_SECRET_KEY|DATABASE_PASSWORD|POSTGRES_PASSWORD|DJANGO_DEBUG|DJANGO_SECURE_*|DOMAIN|EMAIL)
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
# Interactive mode: prompt user for each variable
|
# Interactive mode: prompt user for each variable
|
||||||
if read -t 1 -n 0 2>/dev/null; then
|
if read -t 1 -n 0 2>/dev/null; then
|
||||||
# stdin is available for reading
|
# Special prompts for certain variables
|
||||||
read -p "$key [$current_val]: " new_val || true
|
case "$key" in
|
||||||
|
DJANGO_SECRET_KEY)
|
||||||
|
if [[ -z "$current_val" ]]; then
|
||||||
|
read -p "$key (press Enter to generate): " new_val || true
|
||||||
|
if [[ -z "$new_val" ]]; then
|
||||||
|
new_val=$(generate_secret_key)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
read -p "$key [HIDDEN]: " new_val || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
DATABASE_PASSWORD|POSTGRES_PASSWORD)
|
||||||
|
if [[ -z "$current_val" ]]; then
|
||||||
|
read -p "$key (press Enter to generate): " new_val || true
|
||||||
|
if [[ -z "$new_val" ]]; then
|
||||||
|
new_val=$(generate_password)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
read -p "$key [HIDDEN]: " new_val || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
read -p "$key [$current_val]: " new_val || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
else
|
else
|
||||||
# no stdin available, skip prompting
|
# no stdin available, skip prompting
|
||||||
new_val=""
|
new_val=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$new_val" ]]; then
|
if [[ -n "$new_val" ]]; then
|
||||||
sed -i "s|^$key=.*|$key=$new_val|" "$TARGET"
|
update_env_var "$key" "$new_val" "$TARGET"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done < <(grep -E '^[A-Z0-9_]+=.*' "$EXAMPLE")
|
done < <(grep -E '^[A-Z0-9_]+=.*' "$EXAMPLE")
|
||||||
|
|
||||||
echo "Written $TARGET"
|
echo "✅ Written $TARGET"
|
||||||
|
|
||||||
echo "You can re-run this script with --yes to auto-fill from environment variables."
|
if [[ "$production" = false ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "💡 Tips:"
|
||||||
|
echo " - Run with --production for production setup with secure defaults"
|
||||||
|
echo " - Run with --yes to auto-fill from environment variables"
|
||||||
|
echo " - Check the generated .env file and adjust values as needed"
|
||||||
|
fi
|
||||||
|
|||||||
101
setup.sh
101
setup.sh
@@ -78,81 +78,54 @@ create_env_file() {
|
|||||||
|
|
||||||
if [ -f .env ]; then
|
if [ -f .env ]; then
|
||||||
print_info ".env файл уже существует"
|
print_info ".env файл уже существует"
|
||||||
read -p "Пересоздать? (y/N): " recreate
|
read -p "Пересоздать с помощью интерактивного генератора? (y/N): " recreate
|
||||||
if [[ ! $recreate =~ ^[Yy]$ ]]; then
|
if [[ $recreate =~ ^[Yy]$ ]]; then
|
||||||
|
print_info "Запуск интерактивного генератора .env..."
|
||||||
|
./scripts/generate_env.sh
|
||||||
|
return
|
||||||
|
else
|
||||||
print_info "Пропуск создания .env"
|
print_info "Пропуск создания .env"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Генерация SECRET_KEY
|
print_info "Запуск интерактивного генератора .env..."
|
||||||
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(50))" 2>/dev/null || openssl rand -base64 32)
|
|
||||||
|
|
||||||
# Запрос данных от пользователя
|
# Проверяем наличие скрипта генерации
|
||||||
echo ""
|
if [ -f "scripts/generate_env.sh" ]; then
|
||||||
read -p "Имя базы данных [links_db]: " DB_NAME
|
chmod +x scripts/generate_env.sh
|
||||||
DB_NAME=${DB_NAME:-links_db}
|
./scripts/generate_env.sh
|
||||||
|
else
|
||||||
|
print_warning "Скрипт генерации не найден, создаем базовый .env"
|
||||||
|
|
||||||
read -p "Пользователь БД [links_user]: " DB_USER
|
# Генерация SECRET_KEY
|
||||||
DB_USER=${DB_USER:-links_user}
|
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(50))" 2>/dev/null || openssl rand -base64 32)
|
||||||
|
|
||||||
read -p "Пароль БД [links_password]: " DB_PASSWORD
|
# Запрос основных данных
|
||||||
DB_PASSWORD=${DB_PASSWORD:-links_password}
|
echo ""
|
||||||
|
read -p "Имя базы данных [links_db]: " DB_NAME
|
||||||
|
DB_NAME=${DB_NAME:-links_db}
|
||||||
|
|
||||||
read -p "Хост БД [db]: " DB_HOST
|
read -p "Пользователь БД [links_user]: " DB_USER
|
||||||
DB_HOST=${DB_HOST:-db}
|
DB_USER=${DB_USER:-links_user}
|
||||||
|
|
||||||
read -p "Порт БД [5432]: " DB_PORT
|
read -p "Пароль БД (пустой для генерации): " DB_PASSWORD
|
||||||
DB_PORT=${DB_PORT:-5432}
|
if [ -z "$DB_PASSWORD" ]; then
|
||||||
|
DB_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
|
||||||
|
print_info "Сгенерирован пароль БД: $DB_PASSWORD"
|
||||||
|
fi
|
||||||
|
|
||||||
read -p "Домен для продакшена [localhost]: " DOMAIN
|
# Копируем из примера и заполняем основные поля
|
||||||
DOMAIN=${DOMAIN:-localhost}
|
cp .env.example .env
|
||||||
|
sed -i "s|^DJANGO_SECRET_KEY=.*|DJANGO_SECRET_KEY=$SECRET_KEY|" .env
|
||||||
read -p "Email для SSL сертификатов: " SSL_EMAIL
|
sed -i "s|^DATABASE_NAME=.*|DATABASE_NAME=$DB_NAME|" .env
|
||||||
|
sed -i "s|^DATABASE_USER=.*|DATABASE_USER=$DB_USER|" .env
|
||||||
# Создание .env файла
|
sed -i "s|^DATABASE_PASSWORD=.*|DATABASE_PASSWORD=$DB_PASSWORD|" .env
|
||||||
cat > .env << EOF
|
sed -i "s|^POSTGRES_DB=.*|POSTGRES_DB=$DB_NAME|" .env
|
||||||
# Django Configuration
|
sed -i "s|^POSTGRES_USER=.*|POSTGRES_USER=$DB_USER|" .env
|
||||||
SECRET_KEY=$SECRET_KEY
|
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$DB_PASSWORD|" .env
|
||||||
DEBUG=True
|
sed -i "s|^NEXT_PUBLIC_API_URL=.*|NEXT_PUBLIC_API_URL=http://localhost:8000|" .env
|
||||||
ALLOWED_HOSTS=localhost,127.0.0.1,$DOMAIN
|
fi
|
||||||
|
|
||||||
# Database Configuration
|
|
||||||
DATABASE_URL=postgresql://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/$DB_NAME
|
|
||||||
DB_NAME=$DB_NAME
|
|
||||||
DB_USER=$DB_USER
|
|
||||||
DB_PASSWORD=$DB_PASSWORD
|
|
||||||
DB_HOST=$DB_HOST
|
|
||||||
DB_PORT=$DB_PORT
|
|
||||||
|
|
||||||
# Production Settings
|
|
||||||
DOMAIN=$DOMAIN
|
|
||||||
SSL_EMAIL=$SSL_EMAIL
|
|
||||||
|
|
||||||
# CORS Settings
|
|
||||||
CORS_ALLOWED_ORIGINS=http://localhost:3000,https://$DOMAIN
|
|
||||||
|
|
||||||
# File Upload Settings
|
|
||||||
MAX_UPLOAD_SIZE=10485760
|
|
||||||
MEDIA_ROOT=/app/storage
|
|
||||||
|
|
||||||
# Cache Settings
|
|
||||||
CACHE_TTL=300
|
|
||||||
|
|
||||||
# Email Settings (optional)
|
|
||||||
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
|
|
||||||
EMAIL_HOST=
|
|
||||||
EMAIL_PORT=587
|
|
||||||
EMAIL_USE_TLS=True
|
|
||||||
EMAIL_HOST_USER=
|
|
||||||
EMAIL_HOST_PASSWORD=
|
|
||||||
|
|
||||||
# Redis Settings (optional)
|
|
||||||
REDIS_URL=redis://redis:6379/0
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
LOG_LEVEL=INFO
|
|
||||||
EOF
|
|
||||||
|
|
||||||
print_success ".env файл создан"
|
print_success ".env файл создан"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user