Compare commits
No commits in common. "0c9f5b58e031c48a7e3fd09b4b6ba8657427db12" and "20d0993b06bbdc276cf80d4b0b80b381674ba52e" have entirely different histories.
0c9f5b58e0
...
20d0993b06
@ -39,18 +39,12 @@ jobs:
|
|||||||
- name: Login to Container Registry
|
- name: Login to Container Registry
|
||||||
run: echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" -u "$REGISTRY_USER" --password-stdin
|
run: echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" -u "$REGISTRY_USER" --password-stdin
|
||||||
|
|
||||||
- name: Build and Push API image
|
- name: Build and Push Docker image
|
||||||
run: |
|
run: |
|
||||||
docker build -f Dockerfile.api -t "$REGISTRY_URL/sortifal/pfee:$IMAGE_TAG" -t "$REGISTRY_URL/sortifal/pfee:latest" .
|
docker build -t "$REGISTRY_URL/sortifal/pfee:$IMAGE_TAG" -t "$REGISTRY_URL/sortifal/pfee:latest" .
|
||||||
docker push "$REGISTRY_URL/sortifal/pfee:$IMAGE_TAG"
|
docker push "$REGISTRY_URL/sortifal/pfee:$IMAGE_TAG"
|
||||||
docker push "$REGISTRY_URL/sortifal/pfee:latest"
|
docker push "$REGISTRY_URL/sortifal/pfee:latest"
|
||||||
|
|
||||||
- name: Build and Push Frontend image
|
|
||||||
run: |
|
|
||||||
docker build -f Dockerfile.frontend -t "$REGISTRY_URL/sortifal/pfee-frontend:$IMAGE_TAG" -t "$REGISTRY_URL/sortifal/pfee-frontend:latest" .
|
|
||||||
docker push "$REGISTRY_URL/sortifal/pfee-frontend:$IMAGE_TAG"
|
|
||||||
docker push "$REGISTRY_URL/sortifal/pfee-frontend:latest"
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: Deploy to Kubernetes
|
name: Deploy to Kubernetes
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -81,20 +75,12 @@ jobs:
|
|||||||
-n sqdc-dashboard \
|
-n sqdc-dashboard \
|
||||||
--dry-run=client -o yaml | kubectl apply -f -
|
--dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
- name: Install Kustomize
|
- name: Deploy to Kubernetes
|
||||||
run: |
|
run: |
|
||||||
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
|
kubectl apply -f k8s/namespace.yaml k8s/deployment.yaml k8s/service.yaml k8s/ingress.yaml
|
||||||
sudo mv kustomize /usr/local/bin/
|
|
||||||
|
|
||||||
- name: Deploy with Kustomize
|
- name: Update deployment and verify
|
||||||
run: |
|
run: |
|
||||||
cd k8s
|
kubectl set image deployment/sqdc-dashboard dashboard="$REGISTRY_URL/sortifal/pfee:$IMAGE_TAG" -n sqdc-dashboard
|
||||||
kustomize edit set image gitea.vidoks.fr/sortifal/pfee="$REGISTRY_URL/sortifal/pfee:$IMAGE_TAG"
|
kubectl rollout status deployment/sqdc-dashboard -n sqdc-dashboard --timeout=5m
|
||||||
kustomize edit set image gitea.vidoks.fr/sortifal/pfee-frontend="$REGISTRY_URL/sortifal/pfee-frontend:$IMAGE_TAG"
|
|
||||||
kubectl apply -k .
|
|
||||||
|
|
||||||
- name: Verify deployment
|
|
||||||
run: |
|
|
||||||
kubectl rollout status deployment/sqdc-api -n sqdc-dashboard --timeout=5m
|
|
||||||
kubectl rollout status deployment/sqdc-frontend -n sqdc-dashboard --timeout=5m
|
|
||||||
kubectl get pods,svc,ingress -n sqdc-dashboard
|
kubectl get pods,svc,ingress -n sqdc-dashboard
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
|
build
|
||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
*.md
|
*.md
|
||||||
|
|||||||
@ -8,8 +8,8 @@ WORKDIR /app
|
|||||||
# Copy package files
|
# Copy package files
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# Install all dependencies (including dev) needed for build
|
# Install dependencies
|
||||||
RUN npm ci
|
RUN npm ci --only=production
|
||||||
|
|
||||||
# Copy source code
|
# Copy source code
|
||||||
COPY . .
|
COPY . .
|
||||||
@ -17,9 +17,6 @@ COPY . .
|
|||||||
# Build the application
|
# Build the application
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Install only production dependencies for runtime
|
|
||||||
RUN npm ci --only=production
|
|
||||||
|
|
||||||
# Stage 2: Production image with Nginx
|
# Stage 2: Production image with Nginx
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
@ -46,4 +43,4 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|||||||
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
|
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
|
||||||
|
|
||||||
# Start both nginx and the API server
|
# Start both nginx and the API server
|
||||||
CMD ["sh", "-c", "node /app/server.js & nginx -g 'daemon off;'"]
|
CMD sh -c "node /app/server.js & nginx -g 'daemon off;'"
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
# API Server Dockerfile
|
|
||||||
FROM node:18-alpine
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Install only production dependencies
|
|
||||||
RUN npm ci --only=production
|
|
||||||
|
|
||||||
# Copy database and server files
|
|
||||||
COPY database ./database
|
|
||||||
COPY server.js .
|
|
||||||
|
|
||||||
# Expose API port
|
|
||||||
EXPOSE 3001
|
|
||||||
|
|
||||||
# Health check
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
||||||
CMD node -e "require('http').get('http://localhost:3001/api/categories', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"
|
|
||||||
|
|
||||||
# Start the API server
|
|
||||||
CMD ["node", "server.js"]
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
# Multi-stage build for React frontend with Nginx
|
|
||||||
FROM node:18-alpine AS builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Install all dependencies (including dev) needed for build
|
|
||||||
RUN npm ci
|
|
||||||
|
|
||||||
# Copy source code
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build the application
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Stage 2: Production image with Nginx
|
|
||||||
FROM nginx:alpine
|
|
||||||
|
|
||||||
# Copy custom nginx configuration
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
|
|
||||||
# Copy built application from builder stage
|
|
||||||
COPY --from=builder /app/build /usr/share/nginx/html
|
|
||||||
|
|
||||||
# Expose port
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
# Health check
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
||||||
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
|
|
||||||
|
|
||||||
# Start nginx
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: sqdc-api
|
|
||||||
namespace: sqdc-dashboard
|
|
||||||
labels:
|
|
||||||
app: sqdc-api
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
ports:
|
|
||||||
- port: 3001
|
|
||||||
targetPort: 3001
|
|
||||||
protocol: TCP
|
|
||||||
name: api
|
|
||||||
selector:
|
|
||||||
app: sqdc-api
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
apiVersion: batch/v1
|
|
||||||
kind: Job
|
|
||||||
metadata:
|
|
||||||
name: sqdc-db-init
|
|
||||||
namespace: sqdc-dashboard
|
|
||||||
labels:
|
|
||||||
app: sqdc-api
|
|
||||||
spec:
|
|
||||||
backoffLimit: 3
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: sqdc-api-init
|
|
||||||
spec:
|
|
||||||
serviceAccountName: sqdc-db-init
|
|
||||||
restartPolicy: Never
|
|
||||||
containers:
|
|
||||||
- name: db-init
|
|
||||||
image: gitea.vidoks.fr/sortifal/pfee:latest
|
|
||||||
imagePullPolicy: Always
|
|
||||||
command:
|
|
||||||
- sh
|
|
||||||
- -c
|
|
||||||
- |
|
|
||||||
echo "Starting database initialization..."
|
|
||||||
|
|
||||||
if [ ! -f /app/database/sqdc.db ]; then
|
|
||||||
echo "Creating new database from schema..."
|
|
||||||
sqlite3 /app/database/sqdc.db < /app/database/schema.sql
|
|
||||||
|
|
||||||
echo "Populating database with sample data..."
|
|
||||||
python3 /app/database/populate_db.py
|
|
||||||
|
|
||||||
echo "✅ Database initialized successfully"
|
|
||||||
else
|
|
||||||
echo "✅ Database already exists, skipping initialization"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Verifying database integrity..."
|
|
||||||
sqlite3 /app/database/sqdc.db "SELECT COUNT(*) as table_count FROM sqlite_master WHERE type='table';"
|
|
||||||
|
|
||||||
echo "Database initialization complete"
|
|
||||||
volumeMounts:
|
|
||||||
- name: database
|
|
||||||
mountPath: /app/database
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "128Mi"
|
|
||||||
cpu: "100m"
|
|
||||||
limits:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "200m"
|
|
||||||
volumes:
|
|
||||||
- name: database
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: sqdc-database-pvc
|
|
||||||
imagePullSecrets:
|
|
||||||
- name: registry-credentials
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: sqdc-db-init
|
|
||||||
namespace: sqdc-dashboard
|
|
||||||
labels:
|
|
||||||
app: sqdc-api
|
|
||||||
@ -1,25 +1,30 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: sqdc-api
|
name: sqdc-dashboard
|
||||||
namespace: sqdc-dashboard
|
namespace: sqdc-dashboard
|
||||||
labels:
|
labels:
|
||||||
app: sqdc-api
|
app: sqdc-dashboard
|
||||||
spec:
|
spec:
|
||||||
replicas: 2
|
replicas: 2
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: sqdc-api
|
app: sqdc-dashboard
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: sqdc-api
|
app: sqdc-dashboard
|
||||||
spec:
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: registry-credentials
|
||||||
containers:
|
containers:
|
||||||
- name: api
|
- name: dashboard
|
||||||
image: gitea.vidoks.fr/sortifal/pfee:latest
|
image: gitea.vidoks.fr/sortifal/pfee:latest
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
- containerPort: 3001
|
- containerPort: 3001
|
||||||
name: api
|
name: api
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
@ -28,23 +33,23 @@ spec:
|
|||||||
value: "production"
|
value: "production"
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "128Mi"
|
|
||||||
cpu: "100m"
|
|
||||||
limits:
|
|
||||||
memory: "256Mi"
|
memory: "256Mi"
|
||||||
cpu: "250m"
|
cpu: "250m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /api/categories
|
path: /
|
||||||
port: 3001
|
port: 80
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /api/categories
|
path: /
|
||||||
port: 3001
|
port: 80
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
timeoutSeconds: 3
|
timeoutSeconds: 3
|
||||||
@ -55,6 +60,17 @@ spec:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: database
|
- name: database
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: sqdc-database-pvc
|
claimName: sqdc-dashboard-pvc
|
||||||
imagePullSecrets:
|
---
|
||||||
- name: registry-credentials
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: sqdc-dashboard-pvc
|
||||||
|
namespace: sqdc-dashboard
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
storageClassName: standard
|
||||||
@ -1,50 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: sqdc-frontend
|
|
||||||
namespace: sqdc-dashboard
|
|
||||||
labels:
|
|
||||||
app: sqdc-frontend
|
|
||||||
spec:
|
|
||||||
replicas: 2
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: sqdc-frontend
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: sqdc-frontend
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: frontend
|
|
||||||
image: gitea.vidoks.fr/sortifal/pfee-frontend:latest
|
|
||||||
imagePullPolicy: Always
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
name: http
|
|
||||||
protocol: TCP
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "64Mi"
|
|
||||||
cpu: "50m"
|
|
||||||
limits:
|
|
||||||
memory: "128Mi"
|
|
||||||
cpu: "100m"
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /
|
|
||||||
port: 80
|
|
||||||
initialDelaySeconds: 30
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 3
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /
|
|
||||||
port: 80
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
periodSeconds: 5
|
|
||||||
timeoutSeconds: 3
|
|
||||||
failureThreshold: 2
|
|
||||||
imagePullSecrets:
|
|
||||||
- name: registry-credentials
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: sqdc-frontend
|
|
||||||
namespace: sqdc-dashboard
|
|
||||||
labels:
|
|
||||||
app: sqdc-frontend
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 80
|
|
||||||
protocol: TCP
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
app: sqdc-frontend
|
|
||||||
@ -4,26 +4,18 @@ metadata:
|
|||||||
name: sqdc-dashboard-ingress
|
name: sqdc-dashboard-ingress
|
||||||
namespace: sqdc-dashboard
|
namespace: sqdc-dashboard
|
||||||
annotations:
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
||||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
|
||||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
rules:
|
rules:
|
||||||
- host: diwii.sortifal.dev
|
- host: diwii.sortifal.dev
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- path: /api(/|$)(.*)
|
|
||||||
pathType: ImplementationSpecific
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: sqdc-api
|
|
||||||
port:
|
|
||||||
number: 3001
|
|
||||||
- path: /
|
- path: /
|
||||||
pathType: Prefix
|
pathType: Prefix
|
||||||
backend:
|
backend:
|
||||||
service:
|
service:
|
||||||
name: sqdc-frontend
|
name: sqdc-dashboard-service
|
||||||
port:
|
port:
|
||||||
number: 80
|
number: 80
|
||||||
|
|||||||
@ -5,24 +5,15 @@ namespace: sqdc-dashboard
|
|||||||
|
|
||||||
resources:
|
resources:
|
||||||
- namespace.yaml
|
- namespace.yaml
|
||||||
- pvc.yaml
|
- deployment.yaml
|
||||||
- db-init-sa.yaml
|
- service.yaml
|
||||||
- db-init-job.yaml
|
|
||||||
- api-deployment.yaml
|
|
||||||
- api-service.yaml
|
|
||||||
- frontend-deployment.yaml
|
|
||||||
- frontend-service.yaml
|
|
||||||
- ingress.yaml
|
- ingress.yaml
|
||||||
- configmap.yaml
|
- configmap.yaml
|
||||||
|
|
||||||
commonLabels:
|
commonLabels:
|
||||||
|
app: sqdc-dashboard
|
||||||
managed-by: kustomize
|
managed-by: kustomize
|
||||||
|
|
||||||
# Image tags will be set via kustomize edit during deployment
|
|
||||||
images:
|
images:
|
||||||
- name: gitea.vidoks.fr/sortifal/pfee
|
- name: gitea.vidoks.fr/sortifal/pfee
|
||||||
newTag: latest
|
newTag: latest
|
||||||
newName: gitea.vidoks.fr/sortifal/pfee
|
|
||||||
- name: gitea.vidoks.fr/sortifal/pfee-frontend
|
|
||||||
newTag: latest
|
|
||||||
newName: gitea.vidoks.fr/sortifal/pfee-frontend
|
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: sqdc-database-pvc
|
|
||||||
namespace: sqdc-dashboard
|
|
||||||
labels:
|
|
||||||
app: sqdc-api
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 1Gi
|
|
||||||
20
dashboard-sqdc/k8s/service.yaml
Normal file
20
dashboard-sqdc/k8s/service.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: sqdc-dashboard-service
|
||||||
|
namespace: sqdc-dashboard
|
||||||
|
labels:
|
||||||
|
app: sqdc-dashboard
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: sqdc-dashboard
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
- name: api
|
||||||
|
port: 3001
|
||||||
|
targetPort: 3001
|
||||||
|
protocol: TCP
|
||||||
@ -1,8 +1,8 @@
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name _;
|
server_name localhost;
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html;
|
||||||
|
|
||||||
# Gzip compression
|
# Gzip compression
|
||||||
gzip on;
|
gzip on;
|
||||||
@ -10,13 +10,20 @@ server {
|
|||||||
gzip_min_length 1024;
|
gzip_min_length 1024;
|
||||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
|
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
|
||||||
|
|
||||||
# Static assets with caching
|
# API proxy
|
||||||
location /static/ {
|
location /api/ {
|
||||||
expires 1y;
|
proxy_pass http://localhost:3001/;
|
||||||
add_header Cache-Control "public, immutable";
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
# React app - handle client-side routing (must be last)
|
# React app - handle client-side routing
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
@ -24,6 +31,12 @@ server {
|
|||||||
add_header Expires "0";
|
add_header Expires "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Static assets with caching
|
||||||
|
location /static/ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
# Security headers
|
# Security headers
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user