Bläddra i källkod

MinIO S3 API через path-based routing (api.photoplaces.ru/s3/)

- Caddyfile: HTTP only (порт 80), убран HSTS (на Synology), добавлен маршрут /s3/* -> minio:9000
- docker-compose.prod.yml: Caddy только порт 80, MinIO без внешних портов
- env.prod.example: S3_PUBLIC_ENDPOINT=https://api.photoplaces.ru/s3
- deploy.sh: health check через HTTP, убран minio.photoplaces.ru
- MinIO Console (9001) — только внутри Docker сети
neyrogovnarik 1 månad sedan
förälder
incheckning
16345a295e

+ 17 - 20
deploy/Caddyfile

@@ -1,12 +1,23 @@
 {
-	# Global options
+	# Global options - HTTP only (SSL терминируется на Synology)
 	admin off
 	http_port 80
-	https_port 443
 }
 
-# API subdomain
+# API subdomain - проксирует на backend + MinIO S3 API
 api.{$DOMAIN} {
+	# MinIO S3 API: /s3/* -> minio:9000
+	@s3 {
+		path /s3/*
+	}
+	reverse_proxy @s3 minio:9000 {
+		header_up Host {host}
+		header_up X-Real-IP {remote}
+		header_up X-Forwarded-For {remote}
+		header_up X-Forwarded-Proto {scheme}
+	}
+
+	# Backend API: всё остальное -> backend:8080
 	reverse_proxy backend:8080 {
 		header_up Host {host}
 		header_up X-Real-IP {remote}
@@ -14,9 +25,8 @@ api.{$DOMAIN} {
 		header_up X-Forwarded-Proto {scheme}
 	}
 
-	# Security headers
+	# Security headers (HSTS на Synology, здесь — остальное)
 	header {
-		Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
 		X-Content-Type-Options "nosniff"
 		X-Frame-Options "DENY"
 		Referrer-Policy "strict-origin-when-cross-origin"
@@ -45,7 +55,6 @@ api.{$DOMAIN} {
 
 	# Security headers
 	header {
-		Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
 		X-Content-Type-Options "nosniff"
 		X-Frame-Options "DENY"
 		Referrer-Policy "strict-origin-when-cross-origin"
@@ -66,17 +75,5 @@ api.{$DOMAIN} {
 	encode zstd gzip
 }
 
-# MinIO console (optional, restricted)
-minio.{$DOMAIN} {
-	reverse_proxy minio:9001 {
-		header_up Host {host}
-		header_up X-Real-IP {remote}
-		header_up X-Forwarded-For {remote}
-		header_up X-Forwarded-Proto {scheme}
-	}
-
-	# Basic auth for MinIO console (add credentials to env)
-	basicauth {
-		{$MINIO_CONSOLE_USER} {$MINIO_CONSOLE_PASSWORD}
-	}
-}
+# MinIO Console (9001) — ТОЛЬКО внутри Docker сети, доступ через SSH туннель
+# Никакого внешнего доступа, никакого minio.{$DOMAIN}

+ 5 - 3
deploy/deploy.sh

@@ -106,12 +106,13 @@ echo ">>> Собираю и запускаю контейнеры..."
 docker compose -f deploy/docker-compose.prod.yml up -d --build
 
 # 6. Health check (Caddy -> backend -> migrations)
+# SSL на Synology, Caddy работает на HTTP (порт 80)
 echo ">>> Проверяю здоровье (ждём Caddy + миграции + старт)..."
 for i in $(seq 1 60); do
     # Check Caddy health (port 2019 metrics endpoint)
     if docker compose -f deploy/docker-compose.prod.yml exec -T caddy wget -q --spider http://localhost:2019/metrics 2>/dev/null; then
-        # Caddy is up, check backend through Caddy
-        HEALTH=$(curl -sf "https://${DOMAIN}/api/v1/health" 2>/dev/null || curl -sf http://localhost:8080/api/v1/health 2>/dev/null || echo '{"status":"fail"}')
+        # Caddy is up, check backend through Caddy (HTTP, SSL на Synology)
+        HEALTH=$(curl -sf "http://localhost/api/v1/health" 2>/dev/null || curl -sf http://localhost:8080/api/v1/health 2>/dev/null || echo '{"status":"fail"}')
         if echo "$HEALTH" | grep -q '"ok"'; then
             break
         fi
@@ -127,4 +128,5 @@ done
 echo "✓ Деплой успешен!"
 echo "Фронтенд:    https://${DOMAIN}"
 echo "API:         https://api.${DOMAIN}/api/v1"
-echo "MinIO консоль: https://minio.${DOMAIN} (basic auth)"
+echo "S3 API:      https://api.${DOMAIN}/s3 (presigned URLs)"
+echo "MinIO консоль: только внутри Docker сети (SSH туннель при необходимости)"

+ 2 - 4
deploy/docker-compose.prod.yml

@@ -24,15 +24,12 @@ services:
     image: caddy:2.8-alpine
     ports:
       - "80:80"
-      - "443:443"
     volumes:
       - ./Caddyfile:/etc/caddy/Caddyfile
       - caddy_data:/data
       - caddy_config:/config
     environment:
       DOMAIN: ${DOMAIN}
-      MINIO_CONSOLE_USER: ${MINIO_CONSOLE_USER:-admin}
-      MINIO_CONSOLE_PASSWORD: ${MINIO_CONSOLE_PASSWORD}
     depends_on:
       backend:
         condition: service_healthy
@@ -77,7 +74,7 @@ services:
   minio:
     <<: *common
     image: minio/minio:latest
-    command: server /data
+    command: server /data --console-address ":9001"
     volumes:
       - miniodata:/data
     environment:
@@ -89,6 +86,7 @@ services:
       retries: 5
     secrets:
       - s3_secret_key
+    # Порты 9000/9001 ТОЛЬКО внутри Docker сети (нет внешнего доступа)
 
   backend:
     <<: *common

+ 6 - 5
deploy/env.prod.example

@@ -4,7 +4,7 @@
 # Copy to env.prod and fill in values
 # NEVER commit env.prod to git!
 
-# ----- Domain (REQUIRED for Caddy/HTTPS) -----
+# ----- Domain (REQUIRED for Caddy) -----
 DOMAIN=photoplaces.ru
 
 # ----- PostgreSQL -----
@@ -19,7 +19,8 @@ JWT_REFRESH_SECRET=
 
 # ----- S3 / MinIO -----
 S3_ENDPOINT=http://minio:9000
-S3_PUBLIC_ENDPOINT=https://s3.photoplaces.ru
+# S3_PUBLIC_ENDPOINT для presigned URLs (путь через Caddy: /s3/* -> minio:9000)
+S3_PUBLIC_ENDPOINT=https://api.photoplaces.ru/s3
 S3_ACCESS_KEY=photoplaces
 S3_SECRET_KEY=
 
@@ -35,6 +36,6 @@ YANDEX_MAPS_API_KEY=
 # ----- CORS (comma-separated domains) -----
 ALLOWED_ORIGINS=https://photoplaces.ru,https://www.photoplaces.ru
 
-# ----- MinIO Console (optional, for Caddy basic auth) -----
-MINIO_CONSOLE_USER=admin
-MINIO_CONSOLE_PASSWORD=
+# ----- MinIO Console (только внутри Docker сети, доступ через SSH туннель) -----
+# MINIO_CONSOLE_USER=admin
+# MINIO_CONSOLE_PASSWORD=

+ 3 - 3
obsidian_data/Photoplaces_data/.obsidian/graph.json

@@ -5,14 +5,14 @@
   "showAttachments": false,
   "hideUnresolved": false,
   "showOrphans": true,
-  "collapse-color-groups": true,
+  "collapse-color-groups": false,
   "colorGroups": [],
-  "collapse-display": true,
+  "collapse-display": false,
   "showArrow": false,
   "textFadeMultiplier": 0,
   "nodeSizeMultiplier": 1,
   "lineSizeMultiplier": 1,
-  "collapse-forces": true,
+  "collapse-forces": false,
   "centerStrength": 0.518713248970312,
   "repelStrength": 10,
   "linkStrength": 1,

+ 7 - 28
obsidian_data/Photoplaces_data/.obsidian/workspace.json

@@ -4,39 +4,17 @@
     "type": "split",
     "children": [
       {
-        "id": "d0afdd5792743e22",
+        "id": "f68fb580a8c78df7",
         "type": "tabs",
-        "dimension": 34.51776649746193,
         "children": [
           {
-            "id": "a3137b3e9166eebd",
+            "id": "3d01ec58e39ece45",
             "type": "leaf",
             "state": {
-              "type": "empty",
+              "type": "graph",
               "state": {},
-              "icon": "lucide-file",
-              "title": "Новая вкладка"
-            }
-          }
-        ]
-      },
-      {
-        "id": "0f487117e0e12eef",
-        "type": "tabs",
-        "dimension": 65.48223350253807,
-        "children": [
-          {
-            "id": "8bd96bec443738ab",
-            "type": "leaf",
-            "state": {
-              "type": "markdown",
-              "state": {
-                "file": "architecture-overview.md",
-                "mode": "source",
-                "source": false
-              },
-              "icon": "lucide-file",
-              "title": "architecture-overview"
+              "icon": "lucide-git-fork",
+              "title": "Граф"
             }
           }
         ]
@@ -201,8 +179,9 @@
       "bases:Создать новую базу": false
     }
   },
-  "active": "8bd96bec443738ab",
+  "active": "3d01ec58e39ece45",
   "lastOpenFiles": [
+    "architecture-overview.md",
     "Добро пожаловать.md"
   ]
 }