Dynamic tunnels (#579)

## Description:

Update deployment:

1. automatically create and configure CF tunnels and point it to
subdomain.domain

2. Send loki logs to remote endpoint

3. create metric-exporter.sh to push prom metrics to remote endpoint

4. update and refactor deployment & env variables

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

## Please put your Discord username so you can be contacted if a bug or
regression is found:

<DISCORD USERNAME>

---------

Co-authored-by: Evan Pellegrini <evan@Evans-Air.attlocal.net>
Co-authored-by: evan <openfrontio@gmail.com>
This commit is contained in:
evanpelle
2025-04-20 19:34:17 -07:00
committed by GitHub
parent a4329d42ee
commit 03f7bade7f
11 changed files with 365 additions and 123 deletions
+1 -1
View File
@@ -5,5 +5,5 @@ static/
TODO.txt
resources/images/.DS_Store
resources/.DS_Store
.env
.env*
.DS_Store
+2 -5
View File
@@ -1,11 +1,8 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run tests first
npm run test || {
echo "Tests failed - commit aborted"
exit 1
}
# Add PATH setup to ensure npx is found
export PATH="/usr/local/bin:$HOME/.npm-global/bin:$HOME/.nvm/versions/node/$(node -v)/bin:$PATH"
# Then run lint-staged if tests pass
npx lint-staged
+25 -8
View File
@@ -1,12 +1,28 @@
# Use an official Node runtime as the base image
FROM node:18
ARG GIT_COMMIT=unknown
ENV GIT_COMMIT=$GIT_COMMIT
# Install Nginx, Supervisor and Git (for Husky)
RUN apt-get update && apt-get install -y nginx supervisor git && \
rm -rf /var/lib/apt/lists/*
# Install Nginx, Supervisor, Git, jq, curl, and Node Exporter dependencies
RUN apt-get update && apt-get install -y \
nginx \
supervisor \
git \
curl \
jq \
wget \
&& rm -rf /var/lib/apt/lists/*
# Install Node Exporter
RUN mkdir -p /opt/node_exporter && \
wget -qO- https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz | \
tar xvz --strip-components=1 -C /opt/node_exporter && \
ln -s /opt/node_exporter/node_exporter /usr/local/bin/
# Install cloudflared
RUN curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb > cloudflared.deb \
&& dpkg -i cloudflared.deb \
&& rm cloudflared.deb
# Set the working directory in the container
WORKDIR /usr/src/app
@@ -33,8 +49,9 @@ RUN rm -f /etc/nginx/sites-enabled/default
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Expose only the Nginx port
EXPOSE 80 443
# Copy and make executable the startup script
COPY startup.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/startup.sh
# Start Supervisor to manage both Node.js and Nginx
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
# Use the startup script as the entrypoint
ENTRYPOINT ["/usr/local/bin/startup.sh"]
+76 -46
View File
@@ -7,6 +7,27 @@
set -e # Exit immediately if a command exits with a non-zero status
# Check command line arguments
if [ $# -lt 2 ] || [ $# -gt 3 ]; then
echo "Error: Please specify environment and host, with optional subdomain"
echo "Usage: $0 [prod|staging] [eu|us|staging] [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] [eu|us|staging] [subdomain]"
exit 1
fi
# Validate second argument (host)
if [ "$2" != "eu" ] && [ "$2" != "us" ] && [ "$2" != "staging" ]; then
echo "Error: Second argument must be either 'eu', 'us', or 'staging'"
echo "Usage: $0 [prod|staging] [eu|us|staging] [subdomain]"
exit 1
fi
# Function to print section headers
print_header() {
echo "======================================================"
@@ -14,59 +35,59 @@ print_header() {
echo "======================================================"
}
# Load environment variables
ENV=$1
HOST=$2
SUBDOMAIN=$3 # Optional third argument for custom subdomain
# Set subdomain - use the custom subdomain if provided, otherwise use REGION
if [ -n "$SUBDOMAIN" ]; then
echo "Using custom subdomain: $SUBDOMAIN"
else
SUBDOMAIN=$HOST
echo "Using host as subdomain: $SUBDOMAIN"
fi
# Load common environment variables first
if [ -f .env ]; then
echo "Loading configuration from .env file..."
echo "Loading common configuration from .env file..."
export $(grep -v '^#' .env | xargs)
fi
# Check command line argument
if [ $# -ne 1 ] || ([ "$1" != "staging" ] && [ "$1" != "eu" ] && [ "$1" != "us" ]); then
echo "Error: Please specify environment (staging, eu, or us)"
echo "Usage: $0 [staging|eu|us]"
# Load environment-specific variables
if [ -f .env.$ENV ]; then
echo "Loading $ENV-specific configuration from .env.$ENV file..."
export $(grep -v '^#' .env.$ENV | xargs)
else
echo "Error: Environment file .env.$ENV not found"
exit 1
fi
REGION=$1
VERSION_TAG="latest"
DOCKER_REPO=""
ENV=""
SSH_KEY=""
# Set environment-specific variables
if [ "$REGION" == "staging" ]; then
print_header "DEPLOYING TO STAGING ENVIRONMENT"
if [ "$HOST" == "staging" ]; then
print_header "DEPLOYING TO STAGING HOST"
SERVER_HOST=$SERVER_HOST_STAGING
DOCKER_REPO=$DOCKER_REPO_STAGING
ENV="staging"
SSH_KEY=$SSH_KEY_STAGING
elif [ "$REGION" == "us" ]; then
print_header "DEPLOYING TO US ENVIRONMENT"
elif [ "$HOST" == "us" ]; then
print_header "DEPLOYING TO US HOST"
SERVER_HOST=$SERVER_HOST_US
DOCKER_REPO=$DOCKER_REPO_PROD # Uses prod Docker repo for alt environment
SSH_KEY=$SSH_KEY_PROD
ENV="prod"
else
print_header "DEPLOYING TO EU ENVIRONMENT"
print_header "DEPLOYING TO EU HOST"
SERVER_HOST=$SERVER_HOST_EU
DOCKER_REPO=$DOCKER_REPO_PROD
SSH_KEY=$SSH_KEY_PROD
ENV="prod"
fi
# Check required environment variables
if [ -z "$SERVER_HOST" ]; then
echo "Error: SERVER_HOST_${REGION^^} not defined in .env file or environment"
echo "Error: ${HOST} not defined in .env file or environment"
exit 1
fi
# Configuration
DOCKER_USERNAME=${DOCKER_USERNAME} # Docker Hub username
UPDATE_SCRIPT="./update.sh" # Path to your update script
REMOTE_USER="openfront"
REMOTE_UPDATE_PATH="/home/$REMOTE_USER"
REMOTE_UPDATE_SCRIPT="$REMOTE_UPDATE_PATH/update-openfront.sh" # Where to place the script on server
IMAGE_NAME="${DOCKER_USERNAME}/${DOCKER_REPO}"
DOCKER_IMAGE="${IMAGE_NAME}:${VERSION_TAG}"
# Check if update script exists
if [ ! -f "$UPDATE_SCRIPT" ]; then
echo "Error: Update script $UPDATE_SCRIPT not found!"
@@ -75,7 +96,9 @@ fi
# Step 1: Build and upload Docker image to Docker Hub
print_header "STEP 1: Building and uploading Docker image to Docker Hub"
echo "Region: ${REGION}"
echo "Environment: ${ENV}"
echo "Host: ${HOST}"
echo "Subdomain: ${SUBDOMAIN}"
echo "Using version tag: $VERSION_TAG"
echo "Docker repository: $DOCKER_REPO"
@@ -107,25 +130,32 @@ chmod +x $UPDATE_SCRIPT
# Copy the update script to the server
scp -i $SSH_KEY $UPDATE_SCRIPT $REMOTE_USER@$SERVER_HOST:$REMOTE_UPDATE_SCRIPT
# Copy environment variables if needed
if [ -f .env ]; then
scp -i $SSH_KEY .env $REMOTE_USER@$SERVER_HOST:$REMOTE_UPDATE_PATH/.env
# Secure the .env file
ssh -i $SSH_KEY $REMOTE_USER@$SERVER_HOST "chmod 600 $REMOTE_UPDATE_PATH/.env"
fi
if [ $? -ne 0 ]; then
echo "❌ Failed to copy update script to server. Stopping deployment."
exit 1
fi
echo "✅ Update script successfully copied to server."
# Step 3: Execute the update script on the server
print_header "STEP 3: Executing update script on server"
# Make the script executable on the remote server and execute it with the environment parameter
ssh -i $SSH_KEY $REMOTE_USER@$SERVER_HOST "chmod +x $REMOTE_UPDATE_SCRIPT && $REMOTE_UPDATE_SCRIPT $REGION $DOCKER_USERNAME $DOCKER_REPO"
ssh -i $SSH_KEY $REMOTE_USER@$SERVER_HOST "chmod +x $REMOTE_UPDATE_SCRIPT && \
cat > $REMOTE_UPDATE_PATH/.env << 'EOL'
GAME_ENV=$ENV
ENV=$ENV
HOST=$HOST
SUBDOMAIN=$SUBDOMAIN
DOCKER_IMAGE=$DOCKER_IMAGE
DOCKER_TOKEN=$DOCKER_TOKEN
ADMIN_TOKEN=$ADMIN_TOKEN
CF_ACCOUNT_ID=$CF_ACCOUNT_ID
R2_ACCESS_KEY=$R2_ACCESS_KEY
R2_SECRET_KEY=$R2_SECRET_KEY
R2_BUCKET=$R2_BUCKET
CF_API_TOKEN=$CF_API_TOKEN
DOMAIN=$DOMAIN
SUBDOMAIN=$SUBDOMAIN
MON_USERNAME=$MON_USERNAME
MON_PASSWORD=$MON_PASSWORD
EOL
chmod 600 $REMOTE_UPDATE_PATH/.env && \
$REMOTE_UPDATE_SCRIPT"
if [ $? -ne 0 ]; then
echo "❌ Failed to execute update script on server."
@@ -133,6 +163,6 @@ if [ $? -ne 0 ]; then
fi
print_header "DEPLOYMENT COMPLETED SUCCESSFULLY"
echo "✅ New version deployed to ${REGION} environment!"
echo "🌐 Check your ${REGION} server to verify the deployment."
echo "✅ New version deployed to ${ENV} environment in ${HOST} with subdomain ${SUBDOMAIN}!"
echo "🌐 Check your server to verify the deployment."
echo "======================================================="
+25 -13
View File
@@ -1,20 +1,32 @@
# Server Configuration
SERVER_HOST_STAGING=xxx.xxx.xx.xxx
SERVER_HOST_EU=xxx.xxx.xxx.xxx
SERVER_HOST_US=x.xxx.xxx.xxx
SSH_KEY_STAGING=~/.ssh/your-staging-key
SSH_KEY_PROD=~/.ssh/your-prod-key
# SSH Configuration
SSH_KEY=~/.ssh/your-ssh-key
# Docker Configuration
DOCKER_USERNAME=username
DOCKER_REPO_PROD=your-prod-repo
DOCKER_REPO_STAGING=your-staging-repo
DOCKER_TOKEN=your_docker_token
DOCKER_REPO=your-repo-name
DOCKER_TOKEN=your_docker_token_here
# Admin credentials
ADMIN_TOKEN=your_admin_token
ADMIN_TOKEN=your_admin_token_here
# Cloudflare Configuration
CF_ACCOUNT_ID=your_cloudflare_account_id
CF_API_TOKEN=your_cloudflare_api_token
DOMAIN=your-domain.com
# R2 Configuration
R2_ACCESS_KEY=your_r2_access_key
R2_SECRET_KEY=your_r2_secret_key
R2_ACCOUNT_ID=your_r2_account_id
R2_PROD_BUCKET=your-prod-bucket
R2_STAGING_BUCKET=your-staging-bucket
R2_BUCKET=your-bucket-name
# Server Hosts
SERVER_HOST_STAGING=123.456.78.90
SERVER_HOST_EU=123.456.78.91
SERVER_HOST_US=123.456.78.92
# Monitoring Credentials
MON_USERNAME=monitor_username
MON_PASSWORD=monitor_password
# Version
VERSION_TAG="latest"
+103
View File
@@ -0,0 +1,103 @@
#!/bin/bash
# Metric Collector for Prometheus Pushgateway
# This script collects metrics from Node Exporter and application sources
# and pushes them to a Prometheus Pushgateway with custom labels.
# Configuration
NODE_EXPORTER_URL="http://localhost:9100/metrics"
APP_METRICS_URL="http://localhost:9090/metrics"
PUSHGATEWAY_BASE_URL="https://mon.openfront.io/pushgateway/metrics"
AUTH=$MON_USERNAME:$MON_PASSWORD
INTERVAL=15 # seconds
# Function to fetch metrics from Node Exporter
fetch_node_exporter_metrics() {
curl -s --connect-timeout 5 --max-time 10 "$NODE_EXPORTER_URL" ||
echo "# Error fetching Node Exporter metrics"
}
# Function to fetch metrics from your application
fetch_app_metrics() {
curl -s --connect-timeout 5 --max-time 10 "$APP_METRICS_URL" ||
echo "# Error fetching application metrics"
}
# Function to push metrics to Pushgateway
push_metrics() {
local metrics=$1
local job_name=$2
echo "Pushing $job_name metrics to Pushgateway..."
# Create a temporary file for the metrics
TEMP_FILE=$(mktemp)
echo "$metrics" > "$TEMP_FILE"
# Push to Pushgateway with instance label
curl -s -u "$AUTH" --data-binary @"$TEMP_FILE" \
"$PUSHGATEWAY_BASE_URL/job/$job_name/instance/$HOST"
# Check if push was successful
if [ $? -eq 0 ]; then
echo "$job_name metrics pushed successfully"
else
echo "Error pushing $job_name metrics"
fi
# Remove temporary file
rm "$TEMP_FILE"
}
# Function to add labels to metrics
add_labels() {
local metrics=$1
# First, handle metrics with existing labels
metrics=$(echo "$metrics" | sed -E 's/(\{[^}]*)\}/\1,env="'$ENV'",host="'$HOST'",subdomain="'$SUBDOMAIN'"}/g')
# Then, handle metrics with no existing labels
metrics=$(echo "$metrics" | sed -E 's/^([a-zA-Z0-9_:]+)[ \t]+([0-9.e+-]+)$/\1{env="'$ENV'",host="'$HOST'",subdomain="'$SUBDOMAIN'"} \2/g')
echo "$metrics"
}
# Main function to collect and push metrics
collect_and_push_metrics() {
echo "Starting metrics collection cycle at $(date)"
# Get metrics from both sources
NODE_METRICS=$(fetch_node_exporter_metrics)
APP_METRICS=$(fetch_app_metrics)
# Clean up metrics (remove headers etc.)
NODE_METRICS=$(echo "$NODE_METRICS" | grep -v "^Fetching")
APP_METRICS=$(echo "$APP_METRICS" | grep -v "^Fetching")
# Add labels to metrics
NODE_METRICS=$(add_labels "$NODE_METRICS")
APP_METRICS=$(add_labels "$APP_METRICS")
# Push to Pushgateway separately
push_metrics "$NODE_METRICS" "node_exporter"
push_metrics "$APP_METRICS" "app_metrics"
echo "Metrics collection cycle completed at $(date)"
}
# Main execution
echo "===== Starting metrics collector ====="
echo "Environment: $ENV, HOST: $HOST, Subdomain: $SUBDOMAIN"
echo "Collecting and pushing metrics every $INTERVAL seconds"
echo "Node Exporter URL: $NODE_EXPORTER_URL"
echo "App Metrics URL: $APP_METRICS_URL"
echo "Pushgateway URL: $PUSHGATEWAY_BASE_URL"
# Wait for app to be ready.
sleep 30
# Then set up interval loop
while true; do
sleep $INTERVAL
collect_and_push_metrics
done
+1 -1
View File
@@ -34,7 +34,7 @@ export abstract class DefaultServerConfig implements ServerConfig {
return process.env.GIT_COMMIT;
}
r2Endpoint(): string {
return `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`;
return `https://${process.env.CF_ACCOUNT_ID}.r2.cloudflarestorage.com`;
}
r2AccessKey(): string {
return process.env.R2_ACCESS_KEY;
+3 -10
View File
@@ -1,10 +1,6 @@
import promClient from "prom-client";
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
import { GameManager } from "./GameManager";
const config = getServerConfigFromServer();
const region = config.region();
// Initialize the Prometheus registry
const register = new promClient.Registry();
@@ -15,21 +11,18 @@ promClient.collectDefaultMetrics({ register });
const activeGamesGauge = new promClient.Gauge({
name: "openfront_active_games_count",
help: "Number of active games on this worker",
labelNames: ["region"],
registers: [register],
});
const connectedClientsGauge = new promClient.Gauge({
name: "openfront_connected_clients_count",
help: "Number of connected clients on this worker",
labelNames: ["region"],
registers: [register],
});
const memoryUsageGauge = new promClient.Gauge({
name: "openfront_memory_usage_bytes",
help: "Current memory usage of the worker process in bytes",
labelNames: ["region"],
registers: [register],
});
@@ -42,11 +35,11 @@ export const metrics = {
// Function to update game-related metrics
updateGameMetrics: (gameManager: GameManager) => {
activeGamesGauge.set({ region: region }, gameManager.activeGames());
connectedClientsGauge.set({ region: region }, gameManager.activeClients());
activeGamesGauge.set(gameManager.activeGames());
connectedClientsGauge.set(gameManager.activeClients());
// Update memory usage metrics
const memoryUsage = process.memoryUsage();
memoryUsageGauge.set({ region: region }, memoryUsage.heapUsed);
memoryUsageGauge.set(memoryUsage.heapUsed);
},
};
+90
View File
@@ -0,0 +1,90 @@
#!/bin/bash
set -e
# Check if required environment variables are set
if [ -z "$CF_API_TOKEN" ] || [ -z "$CF_ACCOUNT_ID" ] || [ -z "$SUBDOMAIN" ] || [ -z "$DOMAIN" ]; then
echo "Error: Required environment variables not set"
echo "Please set CF_API_TOKEN, CF_ACCOUNT_ID, SUBDOMAIN, and DOMAIN"
exit 1
fi
# Generate a unique tunnel name using timestamp
TIMESTAMP=$(date +%Y%m%d%H%M%S)
TUNNEL_NAME="${SUBDOMAIN}-tunnel-${TIMESTAMP}"
echo "Using unique tunnel name: ${TUNNEL_NAME}"
# Create a new tunnel
echo "Creating Cloudflare tunnel for subdomain ${SUBDOMAIN}..."
TUNNEL_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/cfd_tunnel" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{\"name\":\"${TUNNEL_NAME}\"}")
# Extract tunnel ID and token
TUNNEL_ID=$(echo $TUNNEL_RESPONSE | jq -r '.result.id')
TUNNEL_TOKEN=$(echo $TUNNEL_RESPONSE | jq -r '.result.token')
if [ -z "$TUNNEL_ID" ] || [ "$TUNNEL_ID" == "null" ]; then
echo "Failed to create tunnel"
echo $TUNNEL_RESPONSE
exit 1
fi
echo "Tunnel created with ID: ${TUNNEL_ID}"
# Configure the tunnel with hostname
echo "Configuring tunnel to point to ${SUBDOMAIN}.${DOMAIN}..."
curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/cfd_tunnel/${TUNNEL_ID}/configurations" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{\"config\":{\"ingress\":[{\"hostname\":\"${SUBDOMAIN}.${DOMAIN}\",\"service\":\"http://localhost:80\"},{\"service\":\"http_status:404\"}]}}"
# Update DNS record to point to the new tunnel
echo "Updating DNS record to point to the new tunnel..."
# First check if DNS record exists
DNS_RECORDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${DOMAIN}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json")
ZONE_ID=$(echo $DNS_RECORDS | jq -r '.result[0].id')
if [ -z "$ZONE_ID" ] || [ "$ZONE_ID" == "null" ]; then
echo "Could not find zone ID for domain ${DOMAIN}"
exit 1
fi
# Check for existing record
EXISTING_RECORDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${SUBDOMAIN}.${DOMAIN}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json")
RECORD_ID=$(echo $EXISTING_RECORDS | jq -r '.result[0].id')
# Create or update the DNS record
if [ -z "$RECORD_ID" ] || [ "$RECORD_ID" == "null" ]; then
# Create new record
echo "Creating new DNS record..."
DNS_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{\"type\":\"CNAME\",\"name\":\"${SUBDOMAIN}\",\"content\":\"${TUNNEL_ID}.cfargotunnel.com\",\"ttl\":1,\"proxied\":true}")
else
# Update existing record
echo "Updating existing DNS record..."
DNS_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{\"type\":\"CNAME\",\"name\":\"${SUBDOMAIN}\",\"content\":\"${TUNNEL_ID}.cfargotunnel.com\",\"ttl\":1,\"proxied\":true}")
fi
# Log the tunnel information
echo "Tunnel is set up! Site will be available at: https://${SUBDOMAIN}.${DOMAIN}"
# Export the tunnel token for supervisord
export CLOUDFLARE_TUNNEL_TOKEN=${TUNNEL_TOKEN}
# Start supervisord
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
+23 -1
View File
@@ -22,4 +22,26 @@ user=node
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stderr_logfile_maxbytes=0
[program:cloudflared]
command=cloudflared tunnel run --token %(ENV_CLOUDFLARE_TUNNEL_TOKEN)s
autostart=true
autorestart=true
stdout_logfile=/var/log/cloudflared.log
stderr_logfile=/var/log/cloudflared-err.log
[program:node_exporter]
command=/usr/local/bin/node_exporter
autostart=true
autorestart=true
stdout_logfile=/var/log/node_exporter.log
stderr_logfile=/var/log/node_exporter-err.log
[program:metrics_exporter]
command=/usr/src/app/metric-exporter.sh
autostart=true
autorestart=true
stdout_logfile=/var/log/metrics-exporter.log
stderr_logfile=/var/log/metrics-exporter-err.log
+16 -38
View File
@@ -2,35 +2,20 @@
# update.sh - Script to update Docker container on Hetzner server
# Called by deploy.sh after uploading Docker image to Docker Hub
# Check if environment parameter is provided
if [ $# -lt 3 ]; then
echo "Error: Required parameters missing"
echo "Usage: $0 <REGION> <docker_username> <docker_repo>"
exit 1
fi
# Set parameters
REGION=$1
DOCKER_USERNAME=$2
DOCKER_REPO=$3
# Container and image configuration
CONTAINER_NAME="openfront-${REGION}"
IMAGE_NAME="${DOCKER_USERNAME}/${DOCKER_REPO}"
FULL_IMAGE_NAME="${IMAGE_NAME}:latest"
echo "======================================================"
echo "🔄 UPDATING SERVER: ${REGION} ENVIRONMENT"
echo "======================================================"
echo "Container name: ${CONTAINER_NAME}"
echo "Docker image: ${FULL_IMAGE_NAME}"
# Load environment variables if .env exists
if [ -f /home/openfront/.env ]; then
echo "Loading environment variables from .env file..."
export $(grep -v '^#' /home/openfront/.env | xargs)
fi
echo "======================================================"
echo "🔄 UPDATING SERVER: ${HOST} ENVIRONMENT"
echo "======================================================"
# Container and image configuration
CONTAINER_NAME="openfront-${ENV}-${SUBDOMAIN}"
docker login -u $DOCKER_USERNAME -p $DOCKER_TOKEN
# Install Loki Docker plugin if not already installed
@@ -46,8 +31,8 @@ else
echo "Loki Docker plugin already installed."
fi
echo "Pulling latest image from Docker Hub..."
docker pull $FULL_IMAGE_NAME
echo "Pulling ${DOCKER_IMAGE} from Docker Hub..."
docker pull $DOCKER_IMAGE
echo "Checking for existing container..."
# Check for running container
@@ -86,27 +71,20 @@ if [ -n "$PORT_CHECK" ]; then
echo "Attempting to proceed anyway..."
fi
ENV="prod"
if [ "$REGION" == "staging" ]; then
ENV="staging"
fi
echo "Starting new container for ${REGION} environment..."
docker run -d -p 80:80 -p 127.0.0.1:9090:9090 \
echo "Starting new container for ${HOST} environment..."
docker run -d \
--restart=always \
$VOLUME_MOUNTS \
--log-driver=loki \
--log-opt loki-url="http://localhost:3100/loki/api/v1/push" \
--log-opt loki-url="https://${MON_USERNAME}:${MON_PASSWORD}@mon.openfront.io/loki/loki/api/v1/push" \
--log-opt loki-batch-size="400" \
--log-opt loki-external-labels="job=docker,environment=${ENV},host=${REGION},region=${REGION}" \
--env GAME_ENV=${ENV} \
--env REGION=${REGION} \
--log-opt loki-external-labels="job=docker,environment=${ENV},host=${HOST},subdomain=${SUBDOMAIN}" \
--env-file /home/openfront/.env \
--name ${CONTAINER_NAME} \
$FULL_IMAGE_NAME
$DOCKER_IMAGE
if [ $? -eq 0 ]; then
echo "Update complete! New ${REGION} container is running."
echo "Update complete! New ${CONTAINER_NAME} container is running."
# Final cleanup after successful deployment
echo "Performing final cleanup of unused Docker resources..."