mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 15:20:43 +00:00
Merge branch 'v29'
This commit is contained in:
@@ -21,6 +21,7 @@ on:
|
||||
options:
|
||||
- masters
|
||||
- staging
|
||||
- falk2
|
||||
- falk1
|
||||
target_subdomain:
|
||||
description: "Deployment Subdomain"
|
||||
@@ -94,6 +95,7 @@ jobs:
|
||||
env:
|
||||
SERVER_HOST_MASTERS: ${{ secrets.SERVER_HOST_MASTERS }}
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SERVER_HOST_STAGING: ${{ secrets.SERVER_HOST_STAGING }}
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
@@ -102,6 +104,7 @@ jobs:
|
||||
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
|
||||
test -n "$SERVER_HOST_MASTERS" && ssh-keyscan -H "$SERVER_HOST_MASTERS" >> ~/.ssh/known_hosts
|
||||
test -n "$SERVER_HOST_FALK1" && ssh-keyscan -H "$SERVER_HOST_FALK1" >> ~/.ssh/known_hosts
|
||||
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
|
||||
test -n "$SERVER_HOST_STAGING" && ssh-keyscan -H "$SERVER_HOST_STAGING" >> ~/.ssh/known_hosts
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
- name: 🚢 Deploy
|
||||
@@ -118,6 +121,7 @@ jobs:
|
||||
API_KEY: ${{ secrets.API_KEY }}
|
||||
SERVER_HOST_MASTERS: ${{ secrets.SERVER_HOST_MASTERS }}
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SERVER_HOST_STAGING: ${{ secrets.SERVER_HOST_STAGING }}
|
||||
SSH_KEY: ~/.ssh/id_rsa
|
||||
VERSION_TAG: latest
|
||||
|
||||
@@ -105,13 +105,13 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: 🔑 Create SSH private key
|
||||
env:
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
|
||||
test -n "$SERVER_HOST_FALK1" && ssh-keyscan -H "$SERVER_HOST_FALK1" >> ~/.ssh/known_hosts
|
||||
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
- name: 🚀 Deploy image
|
||||
env:
|
||||
@@ -125,11 +125,11 @@ jobs:
|
||||
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
|
||||
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
|
||||
API_KEY: ${{ secrets.API_KEY }}
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SSH_KEY: ~/.ssh/id_rsa
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
./deploy.sh prod falk1 "${IMAGE_ID}" beta
|
||||
./deploy.sh prod falk2 "${IMAGE_ID}" beta
|
||||
- name: ⏳ Wait for deployment to start
|
||||
env:
|
||||
FQDN: beta.${{ vars.DOMAIN }}
|
||||
@@ -156,13 +156,13 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: 🔑 Create SSH private key
|
||||
env:
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
|
||||
test -n "$SERVER_HOST_FALK1" && ssh-keyscan -H "$SERVER_HOST_FALK1" >> ~/.ssh/known_hosts
|
||||
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
- name: 🚀 Deploy image
|
||||
env:
|
||||
@@ -176,11 +176,11 @@ jobs:
|
||||
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
|
||||
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
|
||||
API_KEY: ${{ secrets.API_KEY }}
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SSH_KEY: ~/.ssh/id_rsa
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
./deploy.sh prod falk1 "${IMAGE_ID}" blue
|
||||
./deploy.sh prod falk2 "${IMAGE_ID}" blue
|
||||
- name: ⏳ Wait for deployment to start
|
||||
env:
|
||||
FQDN: blue.${{ vars.DOMAIN }}
|
||||
@@ -207,13 +207,13 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: 🔑 Create SSH private key
|
||||
env:
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
mkdir -p ~/.ssh
|
||||
echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
|
||||
test -n "$SERVER_HOST_FALK1" && ssh-keyscan -H "$SERVER_HOST_FALK1" >> ~/.ssh/known_hosts
|
||||
test -n "$SERVER_HOST_FALK2" && ssh-keyscan -H "$SERVER_HOST_FALK2" >> ~/.ssh/known_hosts
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
- name: 🚀 Deploy image
|
||||
env:
|
||||
@@ -227,11 +227,11 @@ jobs:
|
||||
OTEL_AUTH_HEADER: ${{ secrets.OTEL_AUTH_HEADER }}
|
||||
TURNSTILE_SECRET_KEY: ${{ secrets.TURNSTILE_SECRET_KEY }}
|
||||
API_KEY: ${{ secrets.API_KEY }}
|
||||
SERVER_HOST_FALK1: ${{ secrets.SERVER_HOST_FALK1 }}
|
||||
SERVER_HOST_FALK2: ${{ secrets.SERVER_HOST_FALK2 }}
|
||||
SSH_KEY: ~/.ssh/id_rsa
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
./deploy.sh prod falk1 "${IMAGE_ID}" green
|
||||
./deploy.sh prod falk2 "${IMAGE_ID}" green
|
||||
- name: ⏳ Wait for deployment to start
|
||||
env:
|
||||
FQDN: green.${{ vars.DOMAIN }}
|
||||
|
||||
+6
-6
@@ -15,34 +15,34 @@ print_header "BUILD AND DEPLOY WRAPPER"
|
||||
echo "This script will run build.sh and deploy.sh in sequence."
|
||||
echo "You can also run them separately:"
|
||||
echo " ./build.sh [prod|staging] [version_tag]"
|
||||
echo " ./deploy.sh [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain]"
|
||||
echo " ./deploy.sh [prod|staging] [falk1|falk2|nbg1|staging|masters] [version_tag] [subdomain]"
|
||||
echo ""
|
||||
|
||||
# Check command line arguments
|
||||
if [ $# -lt 3 ] || [ $# -gt 5 ]; then
|
||||
echo "Error: Please specify environment, host, and subdomain"
|
||||
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
|
||||
echo "Usage: $0 [prod|staging] [falk1|falk2|nbg1|staging|masters] [subdomain]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate first argument (environment)
|
||||
if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then
|
||||
echo "Error: First argument must be either 'prod' or 'staging'"
|
||||
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
|
||||
echo "Usage: $0 [prod|staging] [falk1|falk2|nbg1|staging|masters] [subdomain]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate second argument (host)
|
||||
if [ "$2" != "falk1" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then
|
||||
if [ "$2" != "falk1" ] && [ "$2" != "falk2" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then
|
||||
echo "Error: Second argument must be either 'falk1', 'nbg1', 'staging', or 'masters'"
|
||||
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
|
||||
echo "Usage: $0 [prod|staging] [falk1|falk2|nbg1|staging|masters] [subdomain]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate third argument (subdomain)
|
||||
if [ -z "$3" ]; then
|
||||
echo "Error: Subdomain is required"
|
||||
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [subdomain]"
|
||||
echo "Usage: $0 [prod|staging] [falk1|falk2|nbg1|staging|masters] [subdomain]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ if [ "$1" != "prod" ] && [ "$1" != "staging" ]; then
|
||||
fi
|
||||
|
||||
# Validate second argument (host)
|
||||
if [ "$2" != "falk1" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then
|
||||
echo "Error: Second argument must be either 'falk1', 'nbg1', 'staging', or 'masters'"
|
||||
echo "Usage: $0 [prod|staging] [falk1|nbg1|staging|masters] [version_tag] [subdomain]"
|
||||
if [ "$2" != "falk1" ] && [ "$2" != "falk2" ] && [ "$2" != "nbg1" ] && [ "$2" != "staging" ] && [ "$2" != "masters" ]; then
|
||||
echo "Error: Second argument must be either 'falk1', 'falk2', 'nbg1', 'staging', or 'masters'"
|
||||
echo "Usage: $0 [prod|staging] [falk1|falk2|nbg1|staging|masters] [version_tag] [subdomain]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -75,6 +75,9 @@ elif [ "$HOST" == "nbg1" ]; then
|
||||
elif [ "$HOST" == "masters" ]; then
|
||||
print_header "DEPLOYING TO MASTERS HOST"
|
||||
SERVER_HOST=$SERVER_HOST_MASTERS
|
||||
elif [ "$HOST" == "falk2" ]; then
|
||||
print_header "DEPLOYING TO FALK2 HOST"
|
||||
SERVER_HOST=$SERVER_HOST_FALK2
|
||||
else
|
||||
print_header "DEPLOYING TO FALK1 HOST"
|
||||
SERVER_HOST=$SERVER_HOST_FALK1
|
||||
|
||||
@@ -7,10 +7,32 @@ echo "====================================================="
|
||||
echo "🚀 STARTING SERVER SETUP"
|
||||
echo "====================================================="
|
||||
|
||||
# Load environment variables from .env.setup if present
|
||||
ENV_FILE="$(dirname "$0")/.env.setup"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "📂 Loading environment from $ENV_FILE"
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
else
|
||||
echo "ℹ️ No .env.setup file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify required environment variables
|
||||
if [ -z "$OTEL_EXPORTER_OTLP_ENDPOINT" ] || [ -z "$OTEL_AUTH_HEADER" ]; then
|
||||
echo "❌ ERROR: Required environment variables are not set!"
|
||||
echo "Please set OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_AUTH_HEADER"
|
||||
echo "Please set OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_AUTH_HEADER in .env.setup"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# CF_ORIGIN_CERT and CF_ORIGIN_KEY: Cloudflare Origin Certificate and private key.
|
||||
# Generate at: Cloudflare dashboard → SSL/TLS → Origin Server → Create Certificate
|
||||
if [ -z "$CF_ORIGIN_CERT" ] || [ -z "$CF_ORIGIN_KEY" ]; then
|
||||
echo "❌ ERROR: CF_ORIGIN_CERT and CF_ORIGIN_KEY are not set!"
|
||||
echo "Generate an origin certificate at: Cloudflare → SSL/TLS → Origin Server → Create Certificate"
|
||||
echo "Then add CF_ORIGIN_CERT and CF_ORIGIN_KEY to .env.setup"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -82,6 +104,96 @@ fi
|
||||
chown -R openfront:openfront /home/openfront
|
||||
echo "Set proper ownership for openfront's home directory"
|
||||
|
||||
# Set up Traefik reverse proxy
|
||||
echo "🔀 Setting up Traefik..."
|
||||
|
||||
# Create the shared Docker network used by Traefik and app containers
|
||||
if docker network ls --format '{{.Name}}' | grep -q '^web$'; then
|
||||
echo "Docker network 'web' already exists"
|
||||
else
|
||||
docker network create web
|
||||
echo "Created Docker network 'web'"
|
||||
fi
|
||||
|
||||
TRAEFIK_CONFIG_DIR="/home/openfront/traefik"
|
||||
TRAEFIK_CERTS_DIR="$TRAEFIK_CONFIG_DIR/certs"
|
||||
mkdir -p "$TRAEFIK_CERTS_DIR"
|
||||
|
||||
# Write Cloudflare origin certificate and key (passed as env vars)
|
||||
echo "$CF_ORIGIN_CERT" > "$TRAEFIK_CERTS_DIR/origin.crt"
|
||||
echo "$CF_ORIGIN_KEY" > "$TRAEFIK_CERTS_DIR/origin.key"
|
||||
chmod 600 "$TRAEFIK_CERTS_DIR/origin.crt" "$TRAEFIK_CERTS_DIR/origin.key"
|
||||
|
||||
# No [api] block — dashboard is disabled for production.
|
||||
# To access it for debugging, SSH tunnel: ssh -L 8080:localhost:8080 user@server
|
||||
cat > "$TRAEFIK_CONFIG_DIR/traefik.toml" << 'EOF'
|
||||
[log]
|
||||
level = "INFO"
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.websecure]
|
||||
address = ":443"
|
||||
|
||||
[providers]
|
||||
[providers.docker]
|
||||
endpoint = "unix:///var/run/docker.sock"
|
||||
exposedByDefault = false # Only route containers with traefik.enable=true
|
||||
network = "web"
|
||||
watch = true
|
||||
[providers.file]
|
||||
filename = "/etc/traefik/tls.toml"
|
||||
watch = true
|
||||
EOF
|
||||
|
||||
# Static TLS configuration referencing the Cloudflare origin cert
|
||||
cat > "$TRAEFIK_CONFIG_DIR/tls.toml" << 'EOF'
|
||||
[[tls.certificates]]
|
||||
certFile = "/certs/origin.crt"
|
||||
keyFile = "/certs/origin.key"
|
||||
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
minVersion = "VersionTLS12"
|
||||
EOF
|
||||
|
||||
cat > "$TRAEFIK_CONFIG_DIR/compose.yaml" << 'EOF'
|
||||
networks:
|
||||
web:
|
||||
# External so blue/green containers can join independently.
|
||||
external: true
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.6
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- /home/openfront/traefik/traefik.toml:/etc/traefik/traefik.toml:ro
|
||||
- /home/openfront/traefik/tls.toml:/etc/traefik/tls.toml:ro
|
||||
- /home/openfront/traefik/certs:/certs:ro
|
||||
networks:
|
||||
- web
|
||||
EOF
|
||||
|
||||
# Give openfront ownership of config files but keep certs owned by root.
|
||||
# Traefik runs as root inside its container so it can read them, but the
|
||||
# openfront app user cannot access the TLS private key.
|
||||
chown -R openfront:openfront "$TRAEFIK_CONFIG_DIR"
|
||||
chown root:root "$TRAEFIK_CERTS_DIR" "$TRAEFIK_CERTS_DIR/origin.crt" "$TRAEFIK_CERTS_DIR/origin.key"
|
||||
|
||||
docker compose -f "$TRAEFIK_CONFIG_DIR/compose.yaml" pull
|
||||
docker compose -f "$TRAEFIK_CONFIG_DIR/compose.yaml" up -d
|
||||
|
||||
if docker ps | grep -q traefik; then
|
||||
echo "✅ Traefik started successfully!"
|
||||
else
|
||||
echo "❌ Failed to start Traefik. Check logs with: docker logs traefik"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create directory for OpenTelemetry configuration
|
||||
echo "📊 Setting up Node Exporter and OpenTelemetry Collector..."
|
||||
OTEL_CONFIG_DIR="/home/openfront/otel"
|
||||
@@ -176,6 +288,7 @@ echo "🎉 SETUP COMPLETE!"
|
||||
echo "====================================================="
|
||||
echo "The openfront user has been set up and has Docker permissions."
|
||||
echo "UDP buffer sizes have been configured for optimal QUIC/WebSocket performance."
|
||||
echo "Traefik reverse proxy is running (HTTP :80, HTTPS :443 with Cloudflare origin cert)."
|
||||
echo "Node Exporter is collecting system metrics."
|
||||
echo "OpenTelemetry Collector is forwarding metrics to your endpoint."
|
||||
echo ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { base64urlToUuid } from "./Base64";
|
||||
import { BigIntStringSchema, PlayerStatsSchema } from "./StatsSchemas";
|
||||
import { Difficulty, GameMode, GameType, RankedType } from "./game/Game";
|
||||
import { Difficulty, GameMode, GameType } from "./game/Game";
|
||||
|
||||
export const RefreshResponseSchema = z.object({
|
||||
token: z.string(),
|
||||
|
||||
@@ -73,7 +73,8 @@ docker run -d \
|
||||
--network web \
|
||||
--label "traefik.enable=true" \
|
||||
--label "traefik.http.routers.${CONTAINER_NAME}.rule=Host(\`${SUBDOMAIN}.${DOMAIN}\`)" \
|
||||
--label "traefik.http.routers.${CONTAINER_NAME}.entrypoints=web" \
|
||||
--label "traefik.http.routers.${CONTAINER_NAME}.entrypoints=websecure" \
|
||||
--label "traefik.http.routers.${CONTAINER_NAME}.tls=true" \
|
||||
--label "traefik.http.services.${CONTAINER_NAME}.loadbalancer.server.port=80" \
|
||||
"${GHCR_IMAGE}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user