#!/usr/bin/env bash # ============================================================================== # Script de aprovisionamiento de proyectos Docker (Estructura Limpia) # ============================================================================== # Uso: ./init_project.sh [puerto-interno] # # Genera en $SRV_DIR/projects/ la estructura base: # app/ -> código fuente, repo o Dockerfile # data/{db,storage}/ -> volúmenes persistentes # .env -> variables de entorno (chmod 600) # docker-compose.yml -> plantilla conectada a proxy_network + etiquetas Traefik # # La plantilla incluye HTTP con redirección a HTTPS y HTTPS con Let's Encrypt, # más un bloque comentado alternativo para dominios .local con certificado # auto-firmado (ver docs/http-https.md). # ============================================================================== set -euo pipefail # Directorio base de los proyectos. Configurable con SRV_DIR. BASE_DIR="${SRV_DIR:-$HOME/srv}" PROJECTS_DIR="$BASE_DIR/projects" NETWORK_NAME="proxy_network" # Colores para salida de terminal GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' # Validar argumentos if [ $# -lt 2 ]; then echo -e "${RED}Uso:${NC} $0 [puerto-interno]" echo -e "Ejemplo: $0 api-ventas api.midominio.com 80" exit 1 fi PROJECT_NAME="$1" PROJECT_DOMAIN="$2" INTERNAL_PORT="${3:-80}" TARGET_DIR="$PROJECTS_DIR/$PROJECT_NAME" echo -e "${BLUE}==>${NC} Inicializando entorno para: ${GREEN}$PROJECT_NAME${NC}" # 1. Asegurar red compartida externa if ! docker network ls --format '{{.Name}}' | grep -wq "$NETWORK_NAME"; then echo -e "${YELLOW}Creando red externa $NETWORK_NAME...${NC}" docker network create "$NETWORK_NAME" fi # 2. Comprobar que no exista el proyecto if [ -d "$TARGET_DIR" ]; then echo -e "${RED}Error:${NC} El directorio $TARGET_DIR ya existe." exit 1 fi # 3. Crear árbol de carpetas limpias # - app/: Destino para clonar repositorios o poner tu código fuente / Dockerfile # - data/: Para persistencia de volúmenes de base de datos o archivos mkdir -p "$PROJECTS_DIR" mkdir -p "$TARGET_DIR/app" mkdir -p "$TARGET_DIR/data/db" mkdir -p "$TARGET_DIR/data/storage" # Asignar permisos restrictivos al directorio raíz del proyecto chmod 700 "$TARGET_DIR" # 4. Crear archivo .env base personalizable cat < "$TARGET_DIR/.env" # ============================================================================== # Variables de entorno - $PROJECT_NAME # ============================================================================== APP_NAME=$PROJECT_NAME APP_DOMAIN=$PROJECT_DOMAIN PORT=$INTERNAL_PORT # Agrega aquí las variables y secretos de tu proyecto. # Este archivo tiene permisos 600 y NO debe subirse a Git. EOF chmod 600 "$TARGET_DIR/.env" # 5. Crear plantilla docker-compose.yml lista para tu propia imagen o build local cat < "$TARGET_DIR/docker-compose.yml" services: # Servicio principal conectado al Proxy Reverso web: # Opción A: Construir tu propio Dockerfile dentro de app/ build: context: ./app dockerfile: Dockerfile # Opción B: Usar una imagen existente de tu registro o Docker Hub # (comentá el bloque build: de arriba y descomentá la línea image:) image: ${PROJECT_NAME}:latest container_name: ${PROJECT_NAME}-web restart: unless-stopped env_file: - .env volumes: - ./app:/app - ./data/storage:/app/storage networks: - default - ${NETWORK_NAME} labels: - "traefik.enable=true" - "traefik.docker.network=${NETWORK_NAME}" # ====================================================================== # MODO A — Dominio público con Let's Encrypt # ====================================================================== # 1. Middleware de redirección HTTP -> HTTPS - "traefik.http.middlewares.${PROJECT_NAME}-redirect.redirectscheme.scheme=https" - "traefik.http.middlewares.${PROJECT_NAME}-redirect.redirectscheme.permanent=true" # 2. Router HTTP (puerto 80): redirige al HTTPS - "traefik.http.routers.${PROJECT_NAME}-http.rule=Host(\`${PROJECT_DOMAIN}\`)" - "traefik.http.routers.${PROJECT_NAME}-http.entrypoints=web" - "traefik.http.routers.${PROJECT_NAME}-http.middlewares=${PROJECT_NAME}-redirect" # 3. Router HTTPS (puerto 443): atiende el tráfico seguro - "traefik.http.routers.${PROJECT_NAME}-https.rule=Host(\`${PROJECT_DOMAIN}\`)" - "traefik.http.routers.${PROJECT_NAME}-https.entrypoints=websecure" - "traefik.http.routers.${PROJECT_NAME}-https.tls=true" - "traefik.http.routers.${PROJECT_NAME}-https.tls.certresolver=letsencrypt" - "traefik.http.routers.${PROJECT_NAME}-https.service=${PROJECT_NAME}-svc" # 4. Servicio: puerto interno del contenedor - "traefik.http.services.${PROJECT_NAME}-svc.loadbalancer.server.port=${INTERNAL_PORT}" # ====================================================================== # MODO B — Dominio .local con certificado auto-firmado # ====================================================================== # Reemplazá los routers de arriba por estos, agregá el certificado en # ~/srv/core/data/dynamic_tls.yml y quitá el certresolver (el certificado # lo aporta el provider "file"). Ver docs/http-https.md # # - "traefik.http.routers.${PROJECT_NAME}.rule=Host(\`${PROJECT_DOMAIN}\`)" # - "traefik.http.routers.${PROJECT_NAME}.entrypoints=websecure" # - "traefik.http.routers.${PROJECT_NAME}.tls=true" # - "traefik.http.services.${PROJECT_NAME}.loadbalancer.server.port=${INTERNAL_PORT}" # ============================================================================== # Servicios internos (base de datos, colas, etc.) # ============================================================================== # IMPORTANTE: conectalos solo a la red "default" para que queden aislados # del proxy inverso y no sean accesibles desde internet. # # db: # image: postgres:14 # container_name: ${PROJECT_NAME}-pg # restart: unless-stopped # networks: # - default # environment: # POSTGRES_USER: \${POSTGRES_USER} # POSTGRES_PASSWORD: \${POSTGRES_PASSWORD} # POSTGRES_DB: \${POSTGRES_DB} # volumes: # - ./data/db:/var/lib/postgresql # # Exponer solo en localhost, nunca público: # ports: # - "127.0.0.1:5432:5432" # Redes: default (aislada para servicios internos) y proxy_network (para el reverse proxy) networks: default: driver: bridge ${NETWORK_NAME}: external: true EOF echo -e "${GREEN}✓${NC} Estructura limpia creada en: ${BLUE}$TARGET_DIR${NC}" echo -e " ├── ${BLUE}app/${NC} <- Pega aquí tu código, Dockerfile o clona tu repo" echo -e " ├── ${BLUE}data/${NC} <- Directorio para volúmenes persistentes" echo -e " ├── ${YELLOW}.env${NC} <- Variables de entorno" echo -e " └── ${YELLOW}docker-compose.yml${NC}<- Orquestación enlazada al proxy" echo "" echo -e "${YELLOW}Próximos pasos:${NC}" echo -e " 1. Copia tus archivos en: ${BLUE}$TARGET_DIR/app/${NC}" echo -e " 2. Ajusta ${YELLOW}$TARGET_DIR/docker-compose.yml${NC} según tu imagen o build" echo -e " 3. Levanta el proxy si aún no está: ${GREEN}cd $HOME/srv/core && docker compose up -d${NC}" echo -e " 4. Inicia el proyecto: ${GREEN}cd $TARGET_DIR && docker compose up -d${NC}"