Files
xenia-pos-local/install.sh
T
bonaminandClaude Opus 5.5 0f9946e6ca fix(proxy): forward WebSocket upgrades and disable buffering in proxy configs
The nginx config written by install.sh proxied waiter.*, manager.* and the
IP default_server without proxy_http_version 1.1 or Upgrade/Connection
headers, so /api/ws/connect never upgraded and live events (new orders,
KDS status, chat, phone calls) never reached waiters or the manager. The
repo's nginx-proxy/nginx.conf had the same gap on the manager block.

Both configs now use a $connection_upgrade map, 1h read/send timeouts and
proxy_buffering off (SSE) on every proxied location. Verified with nginx -t
and a header-echo upstream: old config strips Upgrade, new one forwards it.

Existing sites: copy the new install.sh, re-run it, restart the proxy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:28:27 +03:00

213 lines
8.1 KiB
Bash

#!/bin/bash
# Xenia POS — first-time install script
# Run this on the client machine before starting the stack.
# Usage: bash install.sh
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== Xenia POS Install ==="
echo ""
# ── 1. Create required directories ───────────────────────────────────────────
echo "[ 1/5 ] Creating directories..."
mkdir -p "$SCRIPT_DIR/data"
mkdir -p "$SCRIPT_DIR/certs"
mkdir -p "$SCRIPT_DIR/nginx-proxy"
mkdir -p /opt/xenia/data
touch /opt/xenia/logo.png 2>/dev/null || true
# ── 2. Create .env from .env.example if missing ───────────────────────────────
echo "[ 2/5 ] Configuring environment..."
if [ ! -f "$SCRIPT_DIR/.env" ]; then
cp "$SCRIPT_DIR/.env.example" "$SCRIPT_DIR/.env"
echo ""
echo " A .env file has been created from .env.example."
echo " You must fill in SITE_ID, SITE_KEY, and SECRET_KEY before starting."
echo ""
echo " Get SITE_ID and SITE_KEY from: https://xenia-admin.bonamin.gr"
echo " Generate SECRET_KEY with: openssl rand -hex 32"
echo ""
read -rp " Enter SITE_ID: " INPUT_SITE_ID
read -rp " Enter SITE_KEY: " INPUT_SITE_KEY
read -rp " Enter SECRET_KEY (leave blank to auto-generate): " INPUT_SECRET_KEY
if [ -z "$INPUT_SECRET_KEY" ]; then
INPUT_SECRET_KEY=$(openssl rand -hex 32)
echo " Generated SECRET_KEY: $INPUT_SECRET_KEY"
fi
sed -i "s/^SITE_ID=.*/SITE_ID=${INPUT_SITE_ID}/" "$SCRIPT_DIR/.env"
sed -i "s/^SITE_KEY=.*/SITE_KEY=${INPUT_SITE_KEY}/" "$SCRIPT_DIR/.env"
sed -i "s/^SECRET_KEY=.*/SECRET_KEY=${INPUT_SECRET_KEY}/" "$SCRIPT_DIR/.env"
echo ""
echo " .env written. Review it at: $SCRIPT_DIR/.env"
echo ""
else
echo " .env already exists — skipping."
fi
# ── 3. Write nginx-proxy/nginx.conf ──────────────────────────────────────────
echo "[ 3/5 ] Writing nginx proxy config..."
cat > "$SCRIPT_DIR/nginx-proxy/nginx.conf" << 'EOF'
# Generated by install.sh — keep in sync with nginx-proxy/nginx.conf in the repo.
# Every proxied location must forward WebSocket upgrades (/api/ws/connect) and
# must not buffer (SSE), otherwise live events never reach waiters / KDS.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name waiter.*;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://waiter_pwa:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
}
server {
listen 443 ssl;
server_name manager.*;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://manager_dashboard:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
}
server {
listen 443 ssl default_server;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location /api/ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
location / {
proxy_pass http://waiter_pwa:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
}
EOF
# ── 4. SSL certificates ───────────────────────────────────────────────────────
echo "[ 4/5 ] Checking SSL certificates..."
if [ -f "$SCRIPT_DIR/certs/cert.pem" ] && [ -f "$SCRIPT_DIR/certs/key.pem" ]; then
echo " Certificates already exist — skipping."
else
echo ""
echo " No certificates found in certs/"
echo ""
echo " DNS requirement:"
echo " Two subdomains must point to this machine's IP:"
echo " waiter.YOURDOMAIN → this machine's IP"
echo " manager.YOURDOMAIN → this machine's IP"
echo " The waiter domain should also be registered in the sysadmin"
echo " panel as the 'Waiter Domain' so phones get the QR code."
echo ""
echo " Option A — Let's Encrypt (recommended):"
echo " sudo apt install certbot"
echo " sudo certbot certonly --manual --preferred-challenges dns \\"
echo " -d waiter.YOURDOMAIN -d manager.YOURDOMAIN"
echo " sudo cp /etc/letsencrypt/live/waiter.YOURDOMAIN/fullchain.pem certs/cert.pem"
echo " sudo cp /etc/letsencrypt/live/waiter.YOURDOMAIN/privkey.pem certs/key.pem"
echo ""
echo " Option B — Self-signed / mkcert (local testing only):"
echo " sudo apt install mkcert libnss3-tools"
echo " mkcert -install"
echo " mkcert -cert-file certs/cert.pem -key-file certs/key.pem \\"
echo " waiter.YOURDOMAIN manager.YOURDOMAIN"
echo ""
echo " Add certs then run: docker compose up -d"
echo ""
fi
# ── 5. Logo ───────────────────────────────────────────────────────────────────
echo "[ 5/5 ] Checking logo..."
if [ ! -s "$SCRIPT_DIR/logo.png" ]; then
echo " WARNING: logo.png not found or is empty."
echo " Place your restaurant logo at: $SCRIPT_DIR/logo.png"
touch "$SCRIPT_DIR/logo.png"
fi
# ── Done ─────────────────────────────────────────────────────────────────────
echo ""
echo "=== Setup complete ==="
echo ""
if [ -f "$SCRIPT_DIR/certs/cert.pem" ] && [ -f "$SCRIPT_DIR/certs/key.pem" ]; then
echo "Starting stack..."
docker compose -f "$SCRIPT_DIR/docker-compose.yml" up -d
echo ""
echo "Done! Services running."
echo " Waiter app: https://waiter.YOURDOMAIN"
echo " Manager app: https://manager.YOURDOMAIN"
else
echo "Add SSL certificates to certs/ then run:"
echo " docker compose up -d"
fi