feat: Docker + Caddy production deployment setup
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
*.log
|
||||||
+12
-3
@@ -1,5 +1,14 @@
|
|||||||
# Скопируйте этот файл в .env и укажите ваши данные от Telegram бота
|
# Supabase
|
||||||
VITE_TG_BOT_TOKEN="ваш_токен_бота_от_botfather"
|
|
||||||
VITE_TG_CHAT_ID="ваш_chat_id_куда_отправлять_сообщения"
|
|
||||||
VITE_SUPABASE_URL=https://your-project.supabase.co
|
VITE_SUPABASE_URL=https://your-project.supabase.co
|
||||||
VITE_SUPABASE_ANON_KEY=your-anon-key
|
VITE_SUPABASE_ANON_KEY=your-anon-key
|
||||||
|
|
||||||
|
# Telegram bot (lead form on landing page)
|
||||||
|
VITE_TG_BOT_TOKEN=your-bot-token
|
||||||
|
VITE_TG_CHAT_ID=your-chat-id
|
||||||
|
|
||||||
|
# Web Push / VAPID (generate with the node command in .env)
|
||||||
|
VITE_VAPID_PUBLIC_KEY=your-vapid-public-key
|
||||||
|
|
||||||
|
# Deployment domain for Caddy (automatic HTTPS)
|
||||||
|
# Use "localhost" for local dev, set to real domain in production
|
||||||
|
DOMAIN=localhost
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{$DOMAIN:localhost} {
|
||||||
|
root * /srv
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
# SPA fallback — all routes serve index.html
|
||||||
|
try_files {path} /index.html
|
||||||
|
|
||||||
|
# Cache static assets aggressively
|
||||||
|
@static {
|
||||||
|
path *.js *.css *.png *.jpg *.svg *.ico *.woff2 *.woff
|
||||||
|
}
|
||||||
|
header @static Cache-Control "public, max-age=31536000, immutable"
|
||||||
|
|
||||||
|
# Service worker must not be cached
|
||||||
|
@sw {
|
||||||
|
path /sw.js
|
||||||
|
}
|
||||||
|
header @sw Cache-Control "no-cache, no-store, must-revalidate"
|
||||||
|
|
||||||
|
file_server
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
# Stage 1: build
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci --prefer-offline
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ARG VITE_SUPABASE_URL
|
||||||
|
ARG VITE_SUPABASE_ANON_KEY
|
||||||
|
ARG VITE_TG_BOT_TOKEN
|
||||||
|
ARG VITE_TG_CHAT_ID
|
||||||
|
ARG VITE_VAPID_PUBLIC_KEY
|
||||||
|
|
||||||
|
ENV VITE_SUPABASE_URL=$VITE_SUPABASE_URL
|
||||||
|
ENV VITE_SUPABASE_ANON_KEY=$VITE_SUPABASE_ANON_KEY
|
||||||
|
ENV VITE_TG_BOT_TOKEN=$VITE_TG_BOT_TOKEN
|
||||||
|
ENV VITE_TG_CHAT_ID=$VITE_TG_CHAT_ID
|
||||||
|
ENV VITE_VAPID_PUBLIC_KEY=$VITE_VAPID_PUBLIC_KEY
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 2: serve with Caddy
|
||||||
|
FROM caddy:2-alpine
|
||||||
|
COPY --from=builder /app/dist /srv
|
||||||
|
COPY Caddyfile /etc/caddy/Caddyfile
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
services:
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
VITE_SUPABASE_URL: ${VITE_SUPABASE_URL}
|
||||||
|
VITE_SUPABASE_ANON_KEY: ${VITE_SUPABASE_ANON_KEY}
|
||||||
|
VITE_TG_BOT_TOKEN: ${VITE_TG_BOT_TOKEN}
|
||||||
|
VITE_TG_CHAT_ID: ${VITE_TG_CHAT_ID}
|
||||||
|
VITE_VAPID_PUBLIC_KEY: ${VITE_VAPID_PUBLIC_KEY}
|
||||||
|
environment:
|
||||||
|
DOMAIN: ${DOMAIN:-localhost}
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp" # HTTP/3
|
||||||
|
volumes:
|
||||||
|
- caddy_data:/data # TLS certificates (persisted across restarts)
|
||||||
|
- caddy_config:/config # Caddy config cache
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://localhost:80"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
Reference in New Issue
Block a user