Update health check endpoints and refine TypeScript configuration
- Changed health check endpoint from `/api/health` to `/_health` in Dockerfile and docker-compose.yml for consistency. - Removed the now obsolete health check route file from the API. - Updated TypeScript configuration to exclude the `.next` directory, improving build performance and clarity. - Enhanced documentation in proxy.ts to reflect the updated health check endpoint.
This commit is contained in:
parent
2266167467
commit
3d56f2895f
@ -98,7 +98,7 @@ ENV NODE_ENV=production \
|
|||||||
|
|
||||||
# Health check for container orchestration
|
# Health check for container orchestration
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||||
CMD node -e "fetch('http://localhost:3000/api/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"
|
CMD node -e "fetch('http://localhost:3000/_health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"
|
||||||
|
|
||||||
ENTRYPOINT ["dumb-init", "--"]
|
ENTRYPOINT ["dumb-init", "--"]
|
||||||
CMD ["node", "apps/portal/server.js"]
|
CMD ["node", "apps/portal/server.js"]
|
||||||
|
|||||||
@ -84,10 +84,10 @@ export const config = {
|
|||||||
* - _next/static (static files)
|
* - _next/static (static files)
|
||||||
* - _next/image (image optimization files)
|
* - _next/image (image optimization files)
|
||||||
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
|
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
|
||||||
* - api/health (health check endpoint)
|
* - _health (health check endpoint)
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
source: "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|api/health).*)",
|
source: "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|_health).*)",
|
||||||
missing: [
|
missing: [
|
||||||
{ type: "header", key: "next-router-prefetch" },
|
{ type: "header", key: "next-router-prefetch" },
|
||||||
{ type: "header", key: "purpose", value: "prefetch" },
|
{ type: "header", key: "purpose", value: "prefetch" },
|
||||||
|
|||||||
@ -9,6 +9,6 @@
|
|||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules", ".next"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ docker images | grep portal
|
|||||||
2. Name: `customer-portal`
|
2. Name: `customer-portal`
|
||||||
3. Paste contents of `docker-compose.yml`
|
3. Paste contents of `docker-compose.yml`
|
||||||
4. Scroll down to **Environment Variables**
|
4. Scroll down to **Environment Variables**
|
||||||
5. Copy variables from `stack.env.example` and fill in your production values
|
5. Copy variables from `env.example` and fill in your production values
|
||||||
|
|
||||||
### 3. Generate Secrets
|
### 3. Generate Secrets
|
||||||
|
|
||||||
@ -65,11 +65,11 @@ This setup uses `network_mode: bridge` with Docker `links` to avoid the iptables
|
|||||||
|
|
||||||
### Service URLs (internal)
|
### Service URLs (internal)
|
||||||
|
|
||||||
| Service | Internal URL |
|
| Service | Internal URL |
|
||||||
|----------|-------------------------|
|
| -------- | -------------------------- |
|
||||||
| Backend | http://backend:4000 |
|
| Backend | http://backend:4000 |
|
||||||
| Database | postgresql://database:5432 |
|
| Database | postgresql://database:5432 |
|
||||||
| Redis | redis://cache:6379 |
|
| Redis | redis://cache:6379 |
|
||||||
|
|
||||||
### Nginx/Plesk Proxy
|
### Nginx/Plesk Proxy
|
||||||
|
|
||||||
@ -83,6 +83,7 @@ Configure your domain to proxy to:
|
|||||||
## Updating the Stack
|
## Updating the Stack
|
||||||
|
|
||||||
1. Load new images:
|
1. Load new images:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker load < portal-frontend-latest.tar
|
docker load < portal-frontend-latest.tar
|
||||||
docker load < portal-backend-latest.tar
|
docker load < portal-backend-latest.tar
|
||||||
|
|||||||
@ -25,7 +25,13 @@ services:
|
|||||||
links:
|
links:
|
||||||
- backend
|
- backend
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/api/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"]
|
test:
|
||||||
|
[
|
||||||
|
"CMD",
|
||||||
|
"node",
|
||||||
|
"-e",
|
||||||
|
"fetch('http://localhost:3000/_health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))",
|
||||||
|
]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
@ -46,36 +52,40 @@ services:
|
|||||||
- APP_BASE_URL=${APP_BASE_URL}
|
- APP_BASE_URL=${APP_BASE_URL}
|
||||||
- BFF_PORT=4000
|
- BFF_PORT=4000
|
||||||
- PORT=4000
|
- PORT=4000
|
||||||
|
|
||||||
# Database - use "database" as host (via links)
|
# Database - use "database" as host (via links)
|
||||||
- DATABASE_URL=postgresql://${POSTGRES_USER:-portal}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB:-portal_prod}?schema=public
|
- DATABASE_URL=postgresql://${POSTGRES_USER:-portal}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB:-portal_prod}?schema=public
|
||||||
|
|
||||||
# Redis - use "cache" as host (via links)
|
# Redis - use "cache" as host (via links)
|
||||||
- REDIS_URL=redis://cache:6379/0
|
- REDIS_URL=redis://cache:6379/0
|
||||||
|
|
||||||
# Security
|
# Security
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
- JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-7d}
|
- JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-7d}
|
||||||
|
- JWT_SECRET_PREVIOUS=${JWT_SECRET_PREVIOUS}
|
||||||
|
- JWT_ISSUER=${JWT_ISSUER}
|
||||||
|
- JWT_AUDIENCE=${JWT_AUDIENCE}
|
||||||
- BCRYPT_ROUNDS=${BCRYPT_ROUNDS:-12}
|
- BCRYPT_ROUNDS=${BCRYPT_ROUNDS:-12}
|
||||||
- CORS_ORIGIN=${CORS_ORIGIN}
|
- CORS_ORIGIN=${CORS_ORIGIN}
|
||||||
- TRUST_PROXY=true
|
- TRUST_PROXY=true
|
||||||
- CSRF_SECRET_KEY=${CSRF_SECRET_KEY}
|
- CSRF_SECRET_KEY=${CSRF_SECRET_KEY}
|
||||||
|
|
||||||
# Auth
|
# Auth
|
||||||
- AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=${AUTH_ALLOW_REDIS_TOKEN_FAILOPEN:-false}
|
- AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=${AUTH_ALLOW_REDIS_TOKEN_FAILOPEN:-false}
|
||||||
- AUTH_REQUIRE_REDIS_FOR_TOKENS=${AUTH_REQUIRE_REDIS_FOR_TOKENS:-false}
|
- AUTH_REQUIRE_REDIS_FOR_TOKENS=${AUTH_REQUIRE_REDIS_FOR_TOKENS:-false}
|
||||||
|
- AUTH_BLACKLIST_FAIL_CLOSED=${AUTH_BLACKLIST_FAIL_CLOSED:-false}
|
||||||
- AUTH_MAINTENANCE_MODE=${AUTH_MAINTENANCE_MODE:-false}
|
- AUTH_MAINTENANCE_MODE=${AUTH_MAINTENANCE_MODE:-false}
|
||||||
|
|
||||||
# Rate Limiting
|
# Rate Limiting
|
||||||
- RATE_LIMIT_TTL=${RATE_LIMIT_TTL:-60}
|
- RATE_LIMIT_TTL=${RATE_LIMIT_TTL:-60}
|
||||||
- RATE_LIMIT_LIMIT=${RATE_LIMIT_LIMIT:-100}
|
- RATE_LIMIT_LIMIT=${RATE_LIMIT_LIMIT:-100}
|
||||||
- EXPOSE_VALIDATION_ERRORS=false
|
- EXPOSE_VALIDATION_ERRORS=false
|
||||||
|
|
||||||
# WHMCS
|
# WHMCS
|
||||||
- WHMCS_BASE_URL=${WHMCS_BASE_URL}
|
- WHMCS_BASE_URL=${WHMCS_BASE_URL}
|
||||||
- WHMCS_API_IDENTIFIER=${WHMCS_API_IDENTIFIER}
|
- WHMCS_API_IDENTIFIER=${WHMCS_API_IDENTIFIER}
|
||||||
- WHMCS_API_SECRET=${WHMCS_API_SECRET}
|
- WHMCS_API_SECRET=${WHMCS_API_SECRET}
|
||||||
|
|
||||||
# Salesforce
|
# Salesforce
|
||||||
- SF_LOGIN_URL=${SF_LOGIN_URL}
|
- SF_LOGIN_URL=${SF_LOGIN_URL}
|
||||||
- SF_CLIENT_ID=${SF_CLIENT_ID}
|
- SF_CLIENT_ID=${SF_CLIENT_ID}
|
||||||
@ -83,25 +93,25 @@ services:
|
|||||||
- SF_EVENTS_ENABLED=${SF_EVENTS_ENABLED:-true}
|
- SF_EVENTS_ENABLED=${SF_EVENTS_ENABLED:-true}
|
||||||
- SF_PRIVATE_KEY_BASE64=${SF_PRIVATE_KEY_BASE64}
|
- SF_PRIVATE_KEY_BASE64=${SF_PRIVATE_KEY_BASE64}
|
||||||
- SF_PRIVATE_KEY_PATH=/app/secrets/sf-private.key
|
- SF_PRIVATE_KEY_PATH=/app/secrets/sf-private.key
|
||||||
|
|
||||||
# Freebit
|
# Freebit
|
||||||
- FREEBIT_BASE_URL=${FREEBIT_BASE_URL:-https://i1.mvno.net/emptool/api}
|
- FREEBIT_BASE_URL=${FREEBIT_BASE_URL:-https://i1.mvno.net/emptool/api}
|
||||||
- FREEBIT_OEM_ID=${FREEBIT_OEM_ID:-PASI}
|
- FREEBIT_OEM_ID=${FREEBIT_OEM_ID:-PASI}
|
||||||
- FREEBIT_OEM_KEY=${FREEBIT_OEM_KEY}
|
- FREEBIT_OEM_KEY=${FREEBIT_OEM_KEY}
|
||||||
|
|
||||||
# Email
|
# Email
|
||||||
- EMAIL_ENABLED=${EMAIL_ENABLED:-true}
|
- EMAIL_ENABLED=${EMAIL_ENABLED:-true}
|
||||||
- EMAIL_FROM=${EMAIL_FROM:-no-reply@asolutions.jp}
|
- EMAIL_FROM=${EMAIL_FROM:-no-reply@asolutions.jp}
|
||||||
- EMAIL_FROM_NAME=${EMAIL_FROM_NAME:-Assist Solutions}
|
- EMAIL_FROM_NAME=${EMAIL_FROM_NAME:-Assist Solutions}
|
||||||
- SENDGRID_API_KEY=${SENDGRID_API_KEY}
|
- SENDGRID_API_KEY=${SENDGRID_API_KEY}
|
||||||
|
|
||||||
# Portal
|
# Portal
|
||||||
- PORTAL_PRICEBOOK_ID=${PORTAL_PRICEBOOK_ID}
|
- PORTAL_PRICEBOOK_ID=${PORTAL_PRICEBOOK_ID}
|
||||||
- PORTAL_PRICEBOOK_NAME=${PORTAL_PRICEBOOK_NAME:-Portal}
|
- PORTAL_PRICEBOOK_NAME=${PORTAL_PRICEBOOK_NAME:-Portal}
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
- LOG_LEVEL=${LOG_LEVEL:-info}
|
- LOG_LEVEL=${LOG_LEVEL:-info}
|
||||||
|
|
||||||
# Enable automatic database migrations on startup
|
# Enable automatic database migrations on startup
|
||||||
- RUN_MIGRATIONS=true
|
- RUN_MIGRATIONS=true
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@ -117,7 +127,13 @@ services:
|
|||||||
# - Database migration when RUN_MIGRATIONS=true
|
# - Database migration when RUN_MIGRATIONS=true
|
||||||
# - Waiting for dependencies (nc checks in entrypoint)
|
# - Waiting for dependencies (nc checks in entrypoint)
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "node", "-e", "fetch('http://localhost:4000/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"]
|
test:
|
||||||
|
[
|
||||||
|
"CMD",
|
||||||
|
"node",
|
||||||
|
"-e",
|
||||||
|
"fetch('http://localhost:4000/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))",
|
||||||
|
]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
start_period: 60s
|
start_period: 60s
|
||||||
@ -151,7 +167,19 @@ services:
|
|||||||
cache:
|
cache:
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
container_name: portal-cache
|
container_name: portal-cache
|
||||||
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning", "--maxmemory", "256mb", "--maxmemory-policy", "noeviction"]
|
command:
|
||||||
|
[
|
||||||
|
"redis-server",
|
||||||
|
"--save",
|
||||||
|
"60",
|
||||||
|
"1",
|
||||||
|
"--loglevel",
|
||||||
|
"warning",
|
||||||
|
"--maxmemory",
|
||||||
|
"256mb",
|
||||||
|
"--maxmemory-policy",
|
||||||
|
"noeviction",
|
||||||
|
]
|
||||||
volumes:
|
volumes:
|
||||||
- redis_data:/data
|
- redis_data:/data
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@ -33,13 +33,17 @@ POSTGRES_PASSWORD=<GENERATE_WITH_openssl_rand_base64_24>
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Generate with: openssl rand -base64 32
|
# Generate with: openssl rand -base64 32
|
||||||
JWT_SECRET=<GENERATE_WITH_openssl_rand_base64_32>
|
JWT_SECRET=<GENERATE_WITH_openssl_rand_base64_32>
|
||||||
|
JWT_SECRET_PREVIOUS=
|
||||||
JWT_EXPIRES_IN=7d
|
JWT_EXPIRES_IN=7d
|
||||||
|
JWT_ISSUER=customer-portal
|
||||||
|
JWT_AUDIENCE=portal
|
||||||
BCRYPT_ROUNDS=12
|
BCRYPT_ROUNDS=12
|
||||||
CSRF_SECRET_KEY=<GENERATE_WITH_openssl_rand_base64_32>
|
CSRF_SECRET_KEY=<GENERATE_WITH_openssl_rand_base64_32>
|
||||||
|
|
||||||
# Auth Settings
|
# Auth Settings
|
||||||
AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=false
|
AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=false
|
||||||
AUTH_REQUIRE_REDIS_FOR_TOKENS=false
|
AUTH_REQUIRE_REDIS_FOR_TOKENS=false
|
||||||
|
AUTH_BLACKLIST_FAIL_CLOSED=false
|
||||||
AUTH_MAINTENANCE_MODE=false
|
AUTH_MAINTENANCE_MODE=false
|
||||||
|
|
||||||
# Rate Limiting
|
# Rate Limiting
|
||||||
|
|||||||
@ -34,6 +34,8 @@ echo ""
|
|||||||
# Look for image files
|
# Look for image files
|
||||||
FRONTEND_TAR="${IMAGES_DIR}/portal-frontend-${TAG}.tar"
|
FRONTEND_TAR="${IMAGES_DIR}/portal-frontend-${TAG}.tar"
|
||||||
BACKEND_TAR="${IMAGES_DIR}/portal-backend-${TAG}.tar"
|
BACKEND_TAR="${IMAGES_DIR}/portal-backend-${TAG}.tar"
|
||||||
|
FRONTEND_TARGZ="${IMAGES_DIR}/portal-frontend-${TAG}.tar.gz"
|
||||||
|
BACKEND_TARGZ="${IMAGES_DIR}/portal-backend-${TAG}.tar.gz"
|
||||||
|
|
||||||
# Also check alternative naming
|
# Also check alternative naming
|
||||||
if [[ ! -f "$FRONTEND_TAR" ]]; then
|
if [[ ! -f "$FRONTEND_TAR" ]]; then
|
||||||
@ -43,20 +45,33 @@ if [[ ! -f "$BACKEND_TAR" ]]; then
|
|||||||
BACKEND_TAR="${IMAGES_DIR}/portal-backend.${TAG}.tar"
|
BACKEND_TAR="${IMAGES_DIR}/portal-backend.${TAG}.tar"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$FRONTEND_TARGZ" ]]; then
|
||||||
|
FRONTEND_TARGZ="${IMAGES_DIR}/portal-frontend.${TAG}.tar.gz"
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$BACKEND_TARGZ" ]]; then
|
||||||
|
BACKEND_TARGZ="${IMAGES_DIR}/portal-backend.${TAG}.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
# Load frontend
|
# Load frontend
|
||||||
if [[ -f "$FRONTEND_TAR" ]]; then
|
if [[ -f "$FRONTEND_TARGZ" ]]; then
|
||||||
|
log "Loading frontend image from: $FRONTEND_TARGZ"
|
||||||
|
gunzip -c "$FRONTEND_TARGZ" | docker load
|
||||||
|
elif [[ -f "$FRONTEND_TAR" ]]; then
|
||||||
log "Loading frontend image from: $FRONTEND_TAR"
|
log "Loading frontend image from: $FRONTEND_TAR"
|
||||||
docker load -i "$FRONTEND_TAR"
|
docker load -i "$FRONTEND_TAR"
|
||||||
else
|
else
|
||||||
warn "Frontend tarball not found: $FRONTEND_TAR"
|
warn "Frontend tarball not found: $FRONTEND_TAR or $FRONTEND_TARGZ"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Load backend
|
# Load backend
|
||||||
if [[ -f "$BACKEND_TAR" ]]; then
|
if [[ -f "$BACKEND_TARGZ" ]]; then
|
||||||
|
log "Loading backend image from: $BACKEND_TARGZ"
|
||||||
|
gunzip -c "$BACKEND_TARGZ" | docker load
|
||||||
|
elif [[ -f "$BACKEND_TAR" ]]; then
|
||||||
log "Loading backend image from: $BACKEND_TAR"
|
log "Loading backend image from: $BACKEND_TAR"
|
||||||
docker load -i "$BACKEND_TAR"
|
docker load -i "$BACKEND_TAR"
|
||||||
else
|
else
|
||||||
warn "Backend tarball not found: $BACKEND_TAR"
|
warn "Backend tarball not found: $BACKEND_TAR or $BACKEND_TARGZ"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@ -16,7 +16,7 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|||||||
|
|
||||||
# Default paths (override via env vars)
|
# Default paths (override via env vars)
|
||||||
REPO_PATH="${REPO_PATH:-/var/www/vhosts/yourdomain.com/git/customer-portal}"
|
REPO_PATH="${REPO_PATH:-/var/www/vhosts/yourdomain.com/git/customer-portal}"
|
||||||
COMPOSE_FILE="${COMPOSE_FILE:-$PROJECT_ROOT/docker/portainer/docker-compose.yml}"
|
COMPOSE_FILE="${COMPOSE_FILE:-$PROJECT_ROOT/docker/Prod - Portainer/docker-compose.yml}"
|
||||||
ENV_FILE="${ENV_FILE:-$PROJECT_ROOT/.env}"
|
ENV_FILE="${ENV_FILE:-$PROJECT_ROOT/.env}"
|
||||||
|
|
||||||
# Image settings
|
# Image settings
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user