Try to connect up nginx in prod server
Some checks failed
Podman Rootless Demo / test-backend (push) Has been skipped
Podman Rootless Demo / test-frontend (push) Has been skipped
Podman Rootless Demo / build-backend (push) Has been skipped
Podman Rootless Demo / build-frontend (push) Has been skipped
Podman Rootless Demo / deploy-prod (push) Failing after 20s
Some checks failed
Podman Rootless Demo / test-backend (push) Has been skipped
Podman Rootless Demo / test-frontend (push) Has been skipped
Podman Rootless Demo / build-backend (push) Has been skipped
Podman Rootless Demo / build-frontend (push) Has been skipped
Podman Rootless Demo / deploy-prod (push) Failing after 20s
This commit is contained in:
parent
9a927bcb8b
commit
80f8f75208
3 changed files with 58 additions and 140 deletions
|
|
@ -245,6 +245,21 @@ jobs:
|
||||||
podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-backend-api-postgres:$IMAGE_TAG"
|
podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-backend-api-postgres:$IMAGE_TAG"
|
||||||
podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-frontend:$IMAGE_TAG"
|
podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-frontend:$IMAGE_TAG"
|
||||||
|
|
||||||
|
- name: Prepare in-pod nginx config on host
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# create dir on host (via user namespace)
|
||||||
|
podman --remote unshare mkdir -p /opt/sharenet/nginx /opt/sharenet/volumes/nginx-cache
|
||||||
|
# render temp config (inside the job container)
|
||||||
|
apk add --no-cache gettext >/dev/null
|
||||||
|
envsubst < nginx/nginx.conf > /tmp/nginx.conf
|
||||||
|
# write it onto the host
|
||||||
|
podman --remote unshare sh -c 'cat > /opt/sharenet/nginx/nginx.conf' < /tmp/nginx.conf
|
||||||
|
# reasonable perms for rootless mount
|
||||||
|
podman --remote unshare chown -R 1001:1001 /opt/sharenet
|
||||||
|
podman --remote unshare chmod 0755 /opt/sharenet /opt/sharenet/nginx /opt/sharenet/volumes /opt/sharenet/volumes/nginx-cache
|
||||||
|
podman --remote unshare chmod 0644 /opt/sharenet/nginx/nginx.conf || true
|
||||||
|
|
||||||
- name: Install envsubst (Alpine)
|
- name: Install envsubst (Alpine)
|
||||||
run: apk add --no-cache gettext
|
run: apk add --no-cache gettext
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,27 +150,19 @@ spec:
|
||||||
capabilities:
|
capabilities:
|
||||||
drop: ["ALL"]
|
drop: ["ALL"]
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 8080 # inside pod
|
||||||
hostPort: 8080
|
hostIP: 127.0.0.1 # only loopback on host
|
||||||
protocol: TCP
|
hostPort: 18080 # high port exposed to host
|
||||||
- containerPort: 443
|
- containerPort: 8090 # health inside pod (not exposed)
|
||||||
hostPort: 8443
|
|
||||||
protocol: TCP
|
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- { name: nginx-run, mountPath: /var/run, readOnly: false }
|
- { name: nginx-run, mountPath: /var/run, readOnly: false }
|
||||||
- { name: nginx-conf, mountPath: /etc/nginx/nginx.conf, readOnly: true, subPath: nginx.conf }
|
- { name: nginx-cache, mountPath: /var/cache/nginx, readOnly: false }
|
||||||
- { name: nginx-cache, mountPath: /var/cache/nginx, readOnly: false }
|
- { name: nginx-conf, mountPath: /etc/nginx/nginx.conf, readOnly: true, subPath: nginx.conf }
|
||||||
- { name: letsencrypt, mountPath: /etc/letsencrypt, readOnly: true }
|
|
||||||
# Health check
|
# Health check
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet: { path: /healthz, port: 8090, scheme: HTTP }
|
||||||
path: /healthz
|
|
||||||
port: 8090
|
|
||||||
scheme: HTTP
|
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 30
|
periodSeconds: 30
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 3
|
|
||||||
# Resource limits
|
# Resource limits
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|
@ -193,15 +185,7 @@ spec:
|
||||||
emptyDir: { medium: Memory }
|
emptyDir: { medium: Memory }
|
||||||
- name: nginx-run
|
- name: nginx-run
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
- name: nginx-conf
|
|
||||||
hostPath:
|
|
||||||
path: /opt/sharenet/nginx
|
|
||||||
type: Directory
|
|
||||||
- name: nginx-cache
|
- name: nginx-cache
|
||||||
hostPath:
|
hostPath: { path: /opt/sharenet/volumes/nginx-cache, type: DirectoryOrCreate }
|
||||||
path: /opt/sharenet/volumes/nginx-cache
|
- name: nginx-conf
|
||||||
type: DirectoryOrCreate
|
hostPath: { path: /opt/sharenet/nginx, type: Directory }
|
||||||
- name: letsencrypt
|
|
||||||
hostPath:
|
|
||||||
path: /etc/letsencrypt
|
|
||||||
type: Directory
|
|
||||||
145
nginx/nginx.conf
145
nginx/nginx.conf
|
|
@ -1,118 +1,37 @@
|
||||||
events {
|
user nginx;
|
||||||
worker_connections 1024;
|
worker_processes auto;
|
||||||
}
|
pid /var/run/nginx.pid;
|
||||||
|
events { worker_connections 1024; }
|
||||||
|
|
||||||
http {
|
http {
|
||||||
upstream frontend {
|
sendfile on;
|
||||||
server frontend:3000;
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
|
||||||
|
# health
|
||||||
|
server {
|
||||||
|
listen 8090;
|
||||||
|
location = /healthz { return 200 "ok\n"; add_header Content-Type text/plain; }
|
||||||
|
}
|
||||||
|
|
||||||
|
# public HTTP entrypoint (host will terminate TLS and proxy here)
|
||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
|
||||||
|
# frontend default
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:${PROD_FRONTEND_PORT};
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream backend {
|
# backend API
|
||||||
server backend:3001;
|
location /api/ {
|
||||||
|
proxy_pass http://127.0.0.1:${PROD_BACKEND_PORT}/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
# Rate limiting
|
}
|
||||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
|
||||||
limit_req_zone $binary_remote_addr zone=frontend:10m rate=30r/s;
|
|
||||||
|
|
||||||
# Gzip compression
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_min_length 1024;
|
|
||||||
gzip_proxied any;
|
|
||||||
gzip_comp_level 6;
|
|
||||||
gzip_types
|
|
||||||
text/plain
|
|
||||||
text/css
|
|
||||||
text/xml
|
|
||||||
text/javascript
|
|
||||||
application/json
|
|
||||||
application/javascript
|
|
||||||
application/xml+rss
|
|
||||||
application/atom+xml
|
|
||||||
image/svg+xml;
|
|
||||||
|
|
||||||
# Security headers
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
|
||||||
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
# Redirect HTTP to HTTPS
|
|
||||||
return 301 https://$host$request_uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 443 ssl http2;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
# SSL configuration
|
|
||||||
# These paths match Let's Encrypt certificate files copied in the CI/CD setup guide
|
|
||||||
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
|
||||||
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
|
||||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
|
|
||||||
ssl_prefer_server_ciphers off;
|
|
||||||
ssl_session_cache shared:SSL:10m;
|
|
||||||
ssl_session_timeout 10m;
|
|
||||||
|
|
||||||
# Frontend routes
|
|
||||||
location / {
|
|
||||||
limit_req zone=frontend burst=20 nodelay;
|
|
||||||
|
|
||||||
proxy_pass http://frontend;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection 'upgrade';
|
|
||||||
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;
|
|
||||||
proxy_cache_bypass $http_upgrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
# API routes
|
|
||||||
location /api/ {
|
|
||||||
limit_req zone=api burst=10 nodelay;
|
|
||||||
|
|
||||||
proxy_pass http://backend/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
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;
|
|
||||||
|
|
||||||
# CORS headers
|
|
||||||
add_header Access-Control-Allow-Origin * always;
|
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always;
|
|
||||||
|
|
||||||
if ($request_method = 'OPTIONS') {
|
|
||||||
add_header Access-Control-Allow-Origin *;
|
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
|
|
||||||
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
|
|
||||||
add_header Access-Control-Max-Age 1728000;
|
|
||||||
add_header Content-Type 'text/plain; charset=utf-8';
|
|
||||||
add_header Content-Length 0;
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Health check endpoint
|
|
||||||
location /health {
|
|
||||||
access_log off;
|
|
||||||
proxy_pass http://backend/health;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
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;
|
|
||||||
add_header Content-Type application/json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue