diff --git a/apps/public/content/docs/self-hosting/self-hosting.mdx b/apps/public/content/docs/self-hosting/self-hosting.mdx index 524aab47..eee2a785 100644 --- a/apps/public/content/docs/self-hosting/self-hosting.mdx +++ b/apps/public/content/docs/self-hosting/self-hosting.mdx @@ -16,7 +16,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ### Quickstart ```bash -git clone https://github.com/Openpanel-dev/openpanel && cd openpanel/self-hosting && ./setup +git clone -b self-hosting https://github.com/Openpanel-dev/openpanel && cd openpanel/self-hosting && ./setup # After setup is complete run `./start` to start OpenPanel ``` @@ -25,10 +25,10 @@ git clone https://github.com/Openpanel-dev/openpanel && cd openpanel/self-hostin ### Clone -Clone the repository to your VPS +Clone the repository to your VPS and checkout the self-hosting tag ```bash -git clone https://github.com/Openpanel-dev/openpanel.git +git clone -b self-hosting https://github.com/Openpanel-dev/openpanel.git ``` diff --git a/apps/worker/src/boot-cron.ts b/apps/worker/src/boot-cron.ts index e9869081..30661e06 100644 --- a/apps/worker/src/boot-cron.ts +++ b/apps/worker/src/boot-cron.ts @@ -36,10 +36,7 @@ export async function bootCron() { }, ]; - if ( - (process.env.VITE_SELF_HOSTED === 'true' || process.env.SELF_HOSTED) && - process.env.NODE_ENV === 'production' - ) { + if (process.env.SELF_HOSTED && process.env.NODE_ENV === 'production') { jobs.push({ name: 'ping', type: 'ping', diff --git a/apps/worker/src/jobs/cron.delete-projects.ts b/apps/worker/src/jobs/cron.delete-projects.ts index da82341e..abb8f684 100644 --- a/apps/worker/src/jobs/cron.delete-projects.ts +++ b/apps/worker/src/jobs/cron.delete-projects.ts @@ -47,7 +47,7 @@ export async function deleteProjects(job: Job) { for (const table of tables) { const query = - process.env.VITE_SELF_HOSTED === 'true' + process.env.SELF_HOSTED === 'true' ? `ALTER TABLE ${table} DELETE WHERE ${where};` : `ALTER TABLE ${table}_replicated ON CLUSTER '{cluster}' DELETE WHERE ${where};`; diff --git a/packages/db/code-migrations/helpers.ts b/packages/db/code-migrations/helpers.ts index 59b35307..1c095365 100644 --- a/packages/db/code-migrations/helpers.ts +++ b/packages/db/code-migrations/helpers.ts @@ -24,7 +24,7 @@ export function getIsCluster() { } export function getIsSelfHosting() { - return process.env.VITE_SELF_HOSTED === 'true' || !!process.env.SELF_HOSTED; + return process.env.SELF_HOSTED === 'true' || !!process.env.SELF_HOSTED; } export function getIsDry() { diff --git a/packages/db/src/prisma-client.ts b/packages/db/src/prisma-client.ts index e7e2d86a..6943e4ec 100644 --- a/packages/db/src/prisma-client.ts +++ b/packages/db/src/prisma-client.ts @@ -59,7 +59,7 @@ const getPrismaClient = () => { subscriptionStatus: { needs: { subscriptionStatus: true, subscriptionCanceledAt: true }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return 'active'; } @@ -69,7 +69,7 @@ const getPrismaClient = () => { hasSubscription: { needs: { subscriptionStatus: true, subscriptionEndsAt: true }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return false; } @@ -94,7 +94,7 @@ const getPrismaClient = () => { subscriptionPeriodEventsCountExceededAt: true, }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return null; } @@ -131,7 +131,7 @@ const getPrismaClient = () => { isCanceled: { needs: { subscriptionStatus: true, subscriptionCanceledAt: true }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return false; } @@ -145,7 +145,7 @@ const getPrismaClient = () => { subscriptionEndsAt: true, }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return false; } @@ -159,7 +159,7 @@ const getPrismaClient = () => { subscriptionCanceledAt: true, }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return false; } @@ -182,7 +182,7 @@ const getPrismaClient = () => { subscriptionPeriodEventsLimit: true, }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return false; } @@ -195,7 +195,7 @@ const getPrismaClient = () => { subscriptionCurrentPeriodStart: { needs: { subscriptionStartsAt: true, subscriptionInterval: true }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return null; } @@ -229,7 +229,7 @@ const getPrismaClient = () => { subscriptionInterval: true, }, compute(org) { - if (process.env.VITE_SELF_HOSTED === 'true') { + if (process.env.SELF_HOSTED === 'true') { return null; } diff --git a/packages/trpc/src/routers/onboarding.ts b/packages/trpc/src/routers/onboarding.ts index 59e14373..071b5a7e 100644 --- a/packages/trpc/src/routers/onboarding.ts +++ b/packages/trpc/src/routers/onboarding.ts @@ -33,7 +33,7 @@ async function createOrGetOrganization( }, }); - if (process.env.VITE_SELF_HOSTED !== 'true' && !process.env.SELF_HOSTED) { + if (!process.env.SELF_HOSTED) { await addTrialEndingSoonJob( organization.id, 1000 * 60 * 60 * 24 * TRIAL_DURATION_IN_DAYS * 0.9, diff --git a/self-hosting/coolify.yml b/self-hosting/coolify.yml index b40029b8..521143a4 100644 --- a/self-hosting/coolify.yml +++ b/self-hosting/coolify.yml @@ -135,7 +135,7 @@ services: environment: # Common - NODE_ENV=production - - VITE_SELF_HOSTED=true + - SELF_HOSTED=true # URLs - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public - DATABASE_URL_DIRECT=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public @@ -166,7 +166,7 @@ services: environment: # Common - NODE_ENV=production - - VITE_SELF_HOSTED=true + - SELF_HOSTED=true # URLs - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public - REDIS_URL=redis://default:${SERVICE_PASSWORD_REDIS}@opkv:6379 @@ -193,7 +193,7 @@ services: - SERVICE_FQDN_OPBULLBOARD # Common - NODE_ENV=production - - VITE_SELF_HOSTED=true + - SELF_HOSTED=true # URLs - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public - DATABASE_URL_DIRECT=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public diff --git a/self-hosting/get_latest_images b/self-hosting/get_latest_images index 765d6c36..4744965a 100755 --- a/self-hosting/get_latest_images +++ b/self-hosting/get_latest_images @@ -77,6 +77,65 @@ while [[ $# -gt 0 ]]; do esac done +# Check if jq is installed (required for JSON parsing) +if ! command -v jq &> /dev/null; then + echo -e "${YELLOW}jq is required but not installed${NC}\n" + echo -e "${CYAN}jq is a lightweight JSON processor needed to parse GitHub API responses.${NC}\n" + + # Detect OS and suggest installation + if [[ -f /etc/os-release ]]; then + . /etc/os-release + OS_ID=$ID + elif [[ "$OSTYPE" == "darwin"* ]]; then + OS_ID="macos" + else + OS_ID="unknown" + fi + + # Determine installation command + case $OS_ID in + ubuntu|debian) + INSTALL_CMD="sudo apt-get update && sudo apt-get install -y jq" + ;; + rhel|centos|fedora) + INSTALL_CMD="sudo yum install -y jq" + ;; + alpine) + INSTALL_CMD="sudo apk add --no-cache jq" + ;; + macos) + INSTALL_CMD="brew install jq" + ;; + *) + echo -e "${RED}Could not detect your OS.${NC}" + echo -e "${YELLOW}Please install jq manually:${NC}" + echo -e " ${GREEN}Ubuntu/Debian:${NC} sudo apt-get update && sudo apt-get install -y jq" + echo -e " ${GREEN}RHEL/CentOS:${NC} sudo yum install -y jq" + echo -e " ${GREEN}Alpine:${NC} sudo apk add --no-cache jq" + echo -e " ${GREEN}macOS:${NC} brew install jq" + echo "" + exit 1 + ;; + esac + + # Ask user if they want to install + read -p "$(echo -e ${GREEN}Would you like to install jq now? [Y/n]:${NC} )" -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + echo -e "${RED}jq is required to continue. Please install it manually.${NC}" + exit 1 + fi + + # Install jq + echo -e "${BLUE}Installing jq...${NC}\n" + if eval "$INSTALL_CMD"; then + echo -e "\n${GREEN}✓ jq installed successfully!${NC}\n" + else + echo -e "\n${RED}✗ Failed to install jq. Please install it manually.${NC}" + exit 1 + fi +fi + # Check if user needs to be logged in (for apply mode) if [ "$APPLY_MODE" = true ]; then # Check if Docker is available @@ -135,11 +194,7 @@ fi # List all tags if requested if [ "$LIST_ALL" = true ]; then echo -e "${GREEN}All available tags:${NC}\n" - if command -v jq &> /dev/null; then - echo "$TAGS_JSON" | jq -r '.[] | " \(.name) (\(.commit.sha[0:7]))"' - else - echo "$TAGS_JSON" | grep "\"name\":" | sed 's/.*"name": "\([^"]*\)".*/ \1/' - fi + echo "$TAGS_JSON" | jq -r '.[] | " \(.name) (\(.commit.sha[0:7]))"' echo "" exit 0 fi @@ -150,15 +205,9 @@ get_latest_tag() { local output_var_tag=$2 local output_var_sha=$3 - if command -v jq &> /dev/null; then - # Use jq for better JSON parsing - local tag=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .name" 2>/dev/null) - local sha=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .commit.sha" 2>/dev/null) - else - # Fallback to grep/sed - local tag=$(echo "$TAGS_JSON" | grep -o "\"name\": \"[^\"]*${component}[^\"]*\"" | head -1 | cut -d'"' -f4) - local sha=$(echo "$TAGS_JSON" | grep -B5 "\"name\": \"${tag}\"" | grep "\"sha\"" | head -1 | cut -d'"' -f4) - fi + # Use jq for JSON parsing + local tag=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .name" 2>/dev/null) + local sha=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .commit.sha" 2>/dev/null) if [ -z "$tag" ] || [ "$tag" == "null" ]; then echo -e "${RED}✗${NC} ${component}: No matching tag found" diff --git a/sh/docker-build b/sh/docker-build index c95e0797..45509b4c 100755 --- a/sh/docker-build +++ b/sh/docker-build @@ -46,7 +46,6 @@ build_image() { --platform linux/amd64,linux/arm64 \ -t "$full_version" \ --build-arg DATABASE_URL="postgresql://p@p:5432/p" \ - --build-arg VITE_SELF_HOSTED="true" \ -f "apps/$app/Dockerfile" \ --push \ . @@ -57,7 +56,6 @@ build_image() { -t "$full_version" \ -t "$image_name:latest" \ --build-arg DATABASE_URL="postgresql://p@p:5432/p" \ - --build-arg VITE_SELF_HOSTED="true" \ -f "apps/$app/Dockerfile" \ --push \ . diff --git a/sh/tag-self-hosting b/sh/tag-self-hosting new file mode 100755 index 00000000..299278e0 --- /dev/null +++ b/sh/tag-self-hosting @@ -0,0 +1,60 @@ +#!/bin/bash + +# Tags to manage +TAGS=("self-hosting") + +# Get commit from argument or default to HEAD +COMMIT="${1:-HEAD}" + +echo "🏷️ Managing tags: ${TAGS[@]}" +echo "📍 Target commit: $COMMIT" +echo "" + +# Verify commit exists +if ! git rev-parse --verify "$COMMIT" >/dev/null 2>&1; then + echo "❌ Error: Invalid commit reference: $COMMIT" + exit 1 +fi + +# Delete local tags +echo "🗑️ Deleting local tags..." +for tag in "${TAGS[@]}"; do + if git tag -l "$tag" | grep -q "$tag"; then + git tag -d "$tag" + echo " ✓ Deleted local tag: $tag" + else + echo " - Tag $tag doesn't exist locally" + fi +done + +echo "" + +# Delete remote tags +echo "🗑️ Deleting remote tags..." +for tag in "${TAGS[@]}"; do + if git ls-remote --tags origin | grep -q "refs/tags/$tag"; then + SKIP_HOOKS=1 git push origin ":refs/tags/$tag" 2>/dev/null + echo " ✓ Deleted remote tag: $tag" + else + echo " - Tag $tag doesn't exist on remote" + fi +done + +echo "" + +# Create new tags +echo "🏷️ Creating new tags on commit $COMMIT..." +for tag in "${TAGS[@]}"; do + git tag "$tag" "$COMMIT" + echo " ✓ Created tag: $tag" +done + +echo "" + +# Push tags +echo "🚀 Pushing tags to remote..." +SKIP_HOOKS=1 git push origin "${TAGS[@]}" + +echo "" +echo "✅ Done! Tags updated successfully." + diff --git a/sh/tag-supporter b/sh/tag-supporter new file mode 100755 index 00000000..71a1041f --- /dev/null +++ b/sh/tag-supporter @@ -0,0 +1,60 @@ +#!/bin/bash + +# Tags to manage +TAGS=("api" "worker" "dashboard") + +# Get commit from argument or default to HEAD +COMMIT="${1:-HEAD}" + +echo "🏷️ Managing tags: ${TAGS[@]}" +echo "📍 Target commit: $COMMIT" +echo "" + +# Verify commit exists +if ! git rev-parse --verify "$COMMIT" >/dev/null 2>&1; then + echo "❌ Error: Invalid commit reference: $COMMIT" + exit 1 +fi + +# Delete local tags +echo "🗑️ Deleting local tags..." +for tag in "${TAGS[@]}"; do + if git tag -l "$tag" | grep -q "$tag"; then + git tag -d "$tag" + echo " ✓ Deleted local tag: $tag" + else + echo " - Tag $tag doesn't exist locally" + fi +done + +echo "" + +# Delete remote tags +echo "🗑️ Deleting remote tags..." +for tag in "${TAGS[@]}"; do + if git ls-remote --tags origin | grep -q "refs/tags/$tag"; then + SKIP_HOOKS=1 git push origin ":refs/tags/$tag" 2>/dev/null + echo " ✓ Deleted remote tag: $tag" + else + echo " - Tag $tag doesn't exist on remote" + fi +done + +echo "" + +# Create new tags +echo "🏷️ Creating new tags on commit $COMMIT..." +for tag in "${TAGS[@]}"; do + git tag "$tag" "$COMMIT" + echo " ✓ Created tag: $tag" +done + +echo "" + +# Push tags +echo "🚀 Pushing tags to remote..." +SKIP_HOOKS=1 git push origin "${TAGS[@]}" + +echo "" +echo "✅ Done! Tags updated successfully." +