+ Приведены все функции приложения в рабочий вид
+ Наведен порядок в файлах проекта + Наведен порядок в документации + Настроены скрипты установки, развертки и так далее, расширен MakeFile
This commit is contained in:
605
setup.sh
Executable file → Normal file
605
setup.sh
Executable file → Normal file
@@ -1,128 +1,521 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
#!/bin/bash
|
||||
|
||||
# Запустите этот скрипт из корня вашего репозитория (~/links)
|
||||
# CatLink Setup Script
|
||||
# ====================
|
||||
# Автоматическая настройка среды разработки
|
||||
|
||||
# Переменные
|
||||
BACKEND_DIR="backend"
|
||||
FRONTEND_DIR="frontend"
|
||||
APPS=("users" "links" "customization")
|
||||
set -e # Остановить при ошибке
|
||||
|
||||
# 1. Создаем .gitignore и README
|
||||
cat > .gitignore << 'EOF'
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.env
|
||||
media/
|
||||
node_modules/
|
||||
dist/
|
||||
.venv/
|
||||
# Цвета для вывода
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Функции для цветного вывода
|
||||
print_header() {
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
# Проверка зависимостей
|
||||
check_dependencies() {
|
||||
print_header "Проверка зависимостей"
|
||||
|
||||
# Проверка Docker
|
||||
if ! command -v docker &> /dev/null; then
|
||||
print_error "Docker не установлен"
|
||||
print_info "Установите Docker: https://docs.docker.com/get-docker/"
|
||||
exit 1
|
||||
fi
|
||||
print_success "Docker найден: $(docker --version)"
|
||||
|
||||
# Проверка Docker Compose
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
print_error "Docker Compose не установлен"
|
||||
print_info "Установите Docker Compose: https://docs.docker.com/compose/install/"
|
||||
exit 1
|
||||
fi
|
||||
print_success "Docker Compose найден: $(docker-compose --version)"
|
||||
|
||||
# Проверка Git
|
||||
if ! command -v git &> /dev/null; then
|
||||
print_warning "Git не установлен (рекомендуется для обновлений)"
|
||||
else
|
||||
print_success "Git найден: $(git --version)"
|
||||
fi
|
||||
|
||||
# Проверка Make
|
||||
if ! command -v make &> /dev/null; then
|
||||
print_warning "Make не установлен (рекомендуется для удобства)"
|
||||
print_info "Установите: sudo apt-get install make"
|
||||
else
|
||||
print_success "Make найден: $(make --version | head -1)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Создание .env файла
|
||||
create_env_file() {
|
||||
print_header "Создание конфигурации (.env)"
|
||||
|
||||
if [ -f .env ]; then
|
||||
print_info ".env файл уже существует"
|
||||
read -p "Пересоздать? (y/N): " recreate
|
||||
if [[ ! $recreate =~ ^[Yy]$ ]]; then
|
||||
print_info "Пропуск создания .env"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# Генерация SECRET_KEY
|
||||
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(50))" 2>/dev/null || openssl rand -base64 32)
|
||||
|
||||
# Запрос данных от пользователя
|
||||
echo ""
|
||||
read -p "Имя базы данных [links_db]: " DB_NAME
|
||||
DB_NAME=${DB_NAME:-links_db}
|
||||
|
||||
read -p "Пользователь БД [links_user]: " DB_USER
|
||||
DB_USER=${DB_USER:-links_user}
|
||||
|
||||
read -p "Пароль БД [links_password]: " DB_PASSWORD
|
||||
DB_PASSWORD=${DB_PASSWORD:-links_password}
|
||||
|
||||
read -p "Хост БД [db]: " DB_HOST
|
||||
DB_HOST=${DB_HOST:-db}
|
||||
|
||||
read -p "Порт БД [5432]: " DB_PORT
|
||||
DB_PORT=${DB_PORT:-5432}
|
||||
|
||||
read -p "Домен для продакшена [localhost]: " DOMAIN
|
||||
DOMAIN=${DOMAIN:-localhost}
|
||||
|
||||
read -p "Email для SSL сертификатов: " SSL_EMAIL
|
||||
|
||||
# Создание .env файла
|
||||
cat > .env << EOF
|
||||
# Django Configuration
|
||||
SECRET_KEY=$SECRET_KEY
|
||||
DEBUG=True
|
||||
ALLOWED_HOSTS=localhost,127.0.0.1,$DOMAIN
|
||||
|
||||
# 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 файл создан"
|
||||
}
|
||||
|
||||
if [ ! -f README.md ]; then
|
||||
echo "# Клон Linktr.ee на Django" > README.md
|
||||
fi
|
||||
|
||||
echo "Настраиваем backend-проект"
|
||||
# 2. Создаем backend-проект
|
||||
mkdir -p $BACKEND_DIR && cd $BACKEND_DIR
|
||||
|
||||
# Виртуальное окружение
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# Устанавливаем зависимости
|
||||
pip install Django psycopg2-binary djangorestframework pillow django-tailwind whitenoise gunicorn
|
||||
|
||||
# Инициализируем Django-проект (если не создан)
|
||||
if [ ! -f config/manage.py ]; then
|
||||
django-admin startproject config .
|
||||
fi
|
||||
|
||||
# Создаем приложения, если их нет
|
||||
for app in "${APPS[@]}"; do
|
||||
if [ ! -d "$app" ]; then
|
||||
python manage.py startapp $app
|
||||
fi
|
||||
done
|
||||
|
||||
# Генерируем requirements.txt
|
||||
pip freeze > requirements.txt
|
||||
|
||||
deactivate
|
||||
cd ..
|
||||
|
||||
# 3. Dockerfile для backend
|
||||
cat > $BACKEND_DIR/Dockerfile << 'EOF'
|
||||
FROM python:3.10-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . .
|
||||
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||
EOF
|
||||
|
||||
echo "Создаем docker-compose.yml"
|
||||
# 4. docker-compose.yml в корне
|
||||
cat > docker-compose.yml << 'EOF'
|
||||
# Создание продакшен конфигурации
|
||||
create_production_config() {
|
||||
print_header "Создание продакшен конфигурации"
|
||||
|
||||
if [ ! -f docker-compose.prod.yml ]; then
|
||||
cat > docker-compose.prod.yml << 'EOF'
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build: ./backend
|
||||
environment:
|
||||
- DEBUG=False
|
||||
- DJANGO_SETTINGS_MODULE=backend.settings
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- media_volume:/app/media
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- db
|
||||
- ./storage:/app/storage
|
||||
- ./logs:/app/logs
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- NEXT_TELEMETRY_DISABLED=1
|
||||
restart: unless-stopped
|
||||
|
||||
db:
|
||||
image: postgres:14
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data/
|
||||
env_file:
|
||||
- .env
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./backups:/backups
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./ssl:/etc/nginx/ssl:ro
|
||||
- ./storage:/var/www/storage:ro
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||
depends_on:
|
||||
- web
|
||||
- frontend
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
media_volume:
|
||||
EOF
|
||||
print_success "docker-compose.prod.yml создан"
|
||||
else
|
||||
print_info "docker-compose.prod.yml уже существует"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Настраиваем frontend-проект"
|
||||
# 5. Frontend: инициализация
|
||||
mkdir -p $FRONTEND_DIR && cd $FRONTEND_DIR
|
||||
# Создание nginx конфигурации
|
||||
create_nginx_config() {
|
||||
print_header "Создание конфигурации Nginx"
|
||||
|
||||
if [ ! -f nginx.conf ]; then
|
||||
cat > nginx.conf << 'EOF'
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
if [ ! -f package.json ]; then
|
||||
npm init -y
|
||||
npm install axios react react-dom
|
||||
fi
|
||||
mkdir -p public src/components src/pages src/services src/styles
|
||||
|
||||
# public/index.html
|
||||
cat > public/index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Linktr Clone</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="../src/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
http {
|
||||
upstream backend {
|
||||
server web:8000;
|
||||
}
|
||||
|
||||
upstream frontend {
|
||||
server frontend:3000;
|
||||
}
|
||||
|
||||
# Redirect HTTP to HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS Server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name _;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
# Frontend
|
||||
location / {
|
||||
proxy_pass http://frontend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Backend API
|
||||
location /api/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Admin
|
||||
location /admin/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Static files
|
||||
location /storage/ {
|
||||
alias /var/www/storage/;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
print_success "nginx.conf создан"
|
||||
else
|
||||
print_info "nginx.conf уже существует"
|
||||
fi
|
||||
}
|
||||
|
||||
# src/index.js
|
||||
cat > src/index.js << 'EOF'
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
# Создание директорий
|
||||
create_directories() {
|
||||
print_header "Создание необходимых директорий"
|
||||
|
||||
directories=(
|
||||
"storage"
|
||||
"storage/avatars"
|
||||
"storage/images"
|
||||
"storage/images/links"
|
||||
"storage/images/link_groups"
|
||||
"storage/customization"
|
||||
"backups"
|
||||
"logs"
|
||||
"ssl"
|
||||
)
|
||||
|
||||
for dir in "${directories[@]}"; do
|
||||
if [ ! -d "$dir" ]; then
|
||||
mkdir -p "$dir"
|
||||
print_success "Создана директория: $dir"
|
||||
else
|
||||
print_info "Директория уже существует: $dir"
|
||||
fi
|
||||
done
|
||||
|
||||
# Установка прав доступа
|
||||
chmod 755 storage
|
||||
chmod -R 755 storage/
|
||||
print_success "Права доступа установлены"
|
||||
}
|
||||
|
||||
# Сборка и запуск контейнеров
|
||||
build_and_start() {
|
||||
print_header "Сборка и запуск контейнеров"
|
||||
|
||||
print_info "Остановка существующих контейнеров..."
|
||||
docker-compose down 2>/dev/null || true
|
||||
|
||||
print_info "Сборка контейнеров..."
|
||||
docker-compose build --no-cache
|
||||
|
||||
print_info "Запуск контейнеров..."
|
||||
docker-compose up -d
|
||||
|
||||
print_info "Ожидание запуска сервисов..."
|
||||
sleep 10
|
||||
|
||||
print_success "Контейнеры запущены"
|
||||
}
|
||||
|
||||
# Инициализация базы данных
|
||||
initialize_database() {
|
||||
print_header "Инициализация базы данных"
|
||||
|
||||
print_info "Ожидание готовности базы данных..."
|
||||
sleep 5
|
||||
|
||||
print_info "Выполнение миграций..."
|
||||
docker-compose exec -T web python manage.py migrate
|
||||
|
||||
print_info "Сбор статических файлов..."
|
||||
docker-compose exec -T web python manage.py collectstatic --noinput
|
||||
|
||||
print_success "База данных инициализирована"
|
||||
}
|
||||
|
||||
# Создание суперпользователя
|
||||
create_superuser() {
|
||||
print_header "Создание суперпользователя"
|
||||
|
||||
echo ""
|
||||
read -p "Создать суперпользователя? (Y/n): " create_user
|
||||
if [[ ! $create_user =~ ^[Nn]$ ]]; then
|
||||
print_info "Создание суперпользователя..."
|
||||
docker-compose exec web python manage.py createsuperuser
|
||||
print_success "Суперпользователь создан"
|
||||
else
|
||||
print_info "Пропуск создания суперпользователя"
|
||||
print_info "Вы можете создать его позже командой: make superuser"
|
||||
fi
|
||||
}
|
||||
|
||||
# Проверка здоровья системы
|
||||
health_check() {
|
||||
print_header "Проверка здоровья системы"
|
||||
|
||||
print_info "Проверка frontend..."
|
||||
if curl -s http://localhost:3000 > /dev/null; then
|
||||
print_success "Frontend доступен: http://localhost:3000"
|
||||
else
|
||||
print_error "Frontend недоступен"
|
||||
fi
|
||||
|
||||
print_info "Проверка backend..."
|
||||
if curl -s http://localhost:8000 > /dev/null; then
|
||||
print_success "Backend доступен: http://localhost:8000"
|
||||
else
|
||||
print_error "Backend недоступен"
|
||||
fi
|
||||
|
||||
print_info "Проверка базы данных..."
|
||||
if docker-compose exec -T db pg_isready -U links_user > /dev/null 2>&1; then
|
||||
print_success "База данных готова"
|
||||
else
|
||||
print_error "База данных недоступна"
|
||||
fi
|
||||
}
|
||||
|
||||
# Создание документации
|
||||
create_documentation() {
|
||||
print_header "Создание документации"
|
||||
|
||||
if [ ! -f DEPLOYMENT.md ]; then
|
||||
cat > DEPLOYMENT.md << 'EOF'
|
||||
# CatLink Deployment Guide
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
```bash
|
||||
# Первый запуск
|
||||
make install
|
||||
|
||||
# Режим разработки
|
||||
make dev
|
||||
|
||||
# Продакшен
|
||||
make deploy
|
||||
```
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Статус сервисов
|
||||
make status
|
||||
|
||||
# Логи
|
||||
make logs
|
||||
|
||||
# Перезапуск
|
||||
make restart
|
||||
|
||||
# Создание суперпользователя
|
||||
make superuser
|
||||
|
||||
# Бэкап базы данных
|
||||
make backup
|
||||
|
||||
# SSL настройка
|
||||
make ssl
|
||||
```
|
||||
|
||||
## Структура проекта
|
||||
|
||||
- `frontend/` - Next.js приложение
|
||||
- `backend/` - Django API
|
||||
- `storage/` - Загруженные файлы
|
||||
- `backups/` - Бэкапы базы данных
|
||||
- `logs/` - Логи приложения
|
||||
|
||||
## Продакшен
|
||||
|
||||
1. Настройте домен в `.env`
|
||||
2. Запустите `make ssl` для настройки HTTPS
|
||||
3. Используйте `make deploy` для развертывания
|
||||
|
||||
ReactDOM.render(<h1>Linktr Clone</h1>, document.getElementById('root'));
|
||||
EOF
|
||||
print_success "DEPLOYMENT.md создан"
|
||||
else
|
||||
print_info "DEPLOYMENT.md уже существует"
|
||||
fi
|
||||
}
|
||||
|
||||
cd ..
|
||||
# Финальный вывод
|
||||
print_final_info() {
|
||||
print_header "Установка завершена!"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}🎉 CatLink успешно установлен!${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}📱 Frontend:${NC} http://localhost:3000"
|
||||
echo -e "${BLUE}🔧 Backend API:${NC} http://localhost:8000/api/"
|
||||
echo -e "${BLUE}📊 Admin панель:${NC} http://localhost:8000/admin/"
|
||||
echo ""
|
||||
echo -e "${YELLOW}📚 Полезные команды:${NC}"
|
||||
echo " make help - Все доступные команды"
|
||||
echo " make status - Статус сервисов"
|
||||
echo " make logs - Просмотр логов"
|
||||
echo " make restart - Перезапуск"
|
||||
echo " make superuser - Создать суперпользователя"
|
||||
echo " make backup - Создать бэкап"
|
||||
echo ""
|
||||
echo -e "${BLUE}📖 Документация:${NC} DEPLOYMENT.md"
|
||||
echo ""
|
||||
}
|
||||
|
||||
echo "Проект настроен успешно!"
|
||||
# Основная функция
|
||||
main() {
|
||||
print_header "CatLink Setup Script v2.0"
|
||||
|
||||
# Проверка, что мы в правильной директории
|
||||
if [ ! -f "docker-compose.yml" ]; then
|
||||
print_error "docker-compose.yml не найден. Убедитесь, что вы в корневой директории проекта."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_dependencies
|
||||
create_env_file
|
||||
create_production_config
|
||||
create_nginx_config
|
||||
create_directories
|
||||
build_and_start
|
||||
initialize_database
|
||||
create_superuser
|
||||
health_check
|
||||
create_documentation
|
||||
print_final_info
|
||||
}
|
||||
|
||||
# Обработка ошибок
|
||||
trap 'print_error "Произошла ошибка. Установка прервана."' ERR
|
||||
|
||||
# Запуск основной функции
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user