Struxa
Struxa is a self-hosted, open-source server management panel — a modern, fully typed replacement for Pterodactyl.
Configuration
version: "3.8"
services:
mysql:
image: mysql:8.4
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- struxa-mysql:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 5s
timeout: 5s
retries: 30
start_period: 60s
minio:
image: minio/minio:RELEASE.2025-04-22T22-12-26Z
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
- MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
- MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
volumes:
- struxa-minio:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 10
migrate:
image: ghcr.io/struxadotcloud/migrate:${IMAGE_TAG}
restart: on-failure:5
environment:
- DATABASE_URL=${DATABASE_URL}
depends_on:
mysql:
condition: service_healthy
struxa:
image: ghcr.io/struxadotcloud/dashboard:${IMAGE_TAG}
restart: unless-stopped
entrypoint:
- /bin/sh
- -c
- |
eval "$$(node -e '
const {generateKeyPairSync}=require("crypto");
const {publicKey,privateKey}=generateKeyPairSync("rsa",{modulusLength:2048,
publicKeyEncoding:{type:"spki",format:"pem"},
privateKeyEncoding:{type:"pkcs8",format:"pem"}});
console.log("export JWT_PRIVATE_KEY="+JSON.stringify(privateKey.replace(/\n/g,"\\n")));
console.log("export JWT_PUBLIC_KEY="+JSON.stringify(publicKey.replace(/\n/g,"\\n")));
')"
exec node apps/web/server.js
environment:
- DATABASE_URL=${DATABASE_URL}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- BETTER_AUTH_URL=${BETTER_AUTH_URL}
- CORS_ORIGIN=${CORS_ORIGIN}
- APP_URL=${APP_URL}
- DATABASE_ENCRYPTION_KEY=${DATABASE_ENCRYPTION_KEY}
- MINIO_ENDPOINT=${MINIO_ENDPOINT}
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
- MINIO_BUCKET=${MINIO_BUCKET}
- NODE_ENV=production
depends_on:
migrate:
condition: service_completed_successfully
minio:
condition: service_healthy
watchkeeper:
image: ghcr.io/struxadotcloud/watchkeeper:${IMAGE_TAG}
restart: unless-stopped
environment:
- DATABASE_URL=${DATABASE_URL}
- DATABASE_ENCRYPTION_KEY=${DATABASE_ENCRYPTION_KEY}
depends_on:
migrate:
condition: service_completed_successfully
volumes:
struxa-mysql:
struxa-minio:[variables]
main_domain = "${domain}"
image_tag = "latest"
mysql_root_password = "${password:32}"
mysql_password = "${password:32}"
better_auth_secret = "${base64:32}"
db_encryption_key = "${hash:64}"
minio_access_key = "${username}"
minio_secret_key = "${password:32}"
[config]
env = [
"IMAGE_TAG=${image_tag}",
"MYSQL_ROOT_PASSWORD=${mysql_root_password}",
"MYSQL_DATABASE=struxa",
"MYSQL_USER=struxa",
"MYSQL_PASSWORD=${mysql_password}",
"DATABASE_URL=mysql://struxa:${mysql_password}@mysql:3306/struxa",
"BETTER_AUTH_SECRET=${better_auth_secret}",
"BETTER_AUTH_URL=http://${main_domain}",
"APP_URL=http://${main_domain}",
"CORS_ORIGIN=http://${main_domain}",
"DATABASE_ENCRYPTION_KEY=${db_encryption_key}",
"MINIO_ENDPOINT=http://minio:9000",
"MINIO_ACCESS_KEY=${minio_access_key}",
"MINIO_SECRET_KEY=${minio_secret_key}",
"MINIO_BUCKET=struxa",
]
mounts = []
[[config.domains]]
serviceName = "struxa"
port = 3001
host = "${main_domain}"Base64
To import this template in Dokploy: create a Compose service → Advanced → Base64 import and paste the content below:
ewogICJjb21wb3NlIjogInZlcnNpb246IFwiMy44XCJcbnNlcnZpY2VzOlxuICBteXNxbDpcbiAgICBpbWFnZTogbXlzcWw6OC40XG4gICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWRcbiAgICBlbnZpcm9ubWVudDpcbiAgICAgIC0gTVlTUUxfUk9PVF9QQVNTV09SRD0ke01ZU1FMX1JPT1RfUEFTU1dPUkR9XG4gICAgICAtIE1ZU1FMX0RBVEFCQVNFPSR7TVlTUUxfREFUQUJBU0V9XG4gICAgICAtIE1ZU1FMX1VTRVI9JHtNWVNRTF9VU0VSfVxuICAgICAgLSBNWVNRTF9QQVNTV09SRD0ke01ZU1FMX1BBU1NXT1JEfVxuICAgIHZvbHVtZXM6XG4gICAgICAtIHN0cnV4YS1teXNxbDovdmFyL2xpYi9teXNxbFxuICAgIGhlYWx0aGNoZWNrOlxuICAgICAgdGVzdDogW1wiQ01EXCIsIFwibXlzcWxhZG1pblwiLCBcInBpbmdcIiwgXCItaFwiLCBcImxvY2FsaG9zdFwiLCBcIi11XCIsIFwicm9vdFwiLCBcIi1wJHtNWVNRTF9ST09UX1BBU1NXT1JEfVwiXVxuICAgICAgaW50ZXJ2YWw6IDVzXG4gICAgICB0aW1lb3V0OiA1c1xuICAgICAgcmV0cmllczogMzBcbiAgICAgIHN0YXJ0X3BlcmlvZDogNjBzXG5cbiAgbWluaW86XG4gICAgaW1hZ2U6IG1pbmlvL21pbmlvOlJFTEVBU0UuMjAyNS0wNC0yMlQyMi0xMi0yNlpcbiAgICByZXN0YXJ0OiB1bmxlc3Mtc3RvcHBlZFxuICAgIGNvbW1hbmQ6IHNlcnZlciAvZGF0YSAtLWNvbnNvbGUtYWRkcmVzcyBcIjo5MDAxXCJcbiAgICBlbnZpcm9ubWVudDpcbiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7TUlOSU9fQUNDRVNTX0tFWX1cbiAgICAgIC0gTUlOSU9fUk9PVF9QQVNTV09SRD0ke01JTklPX1NFQ1JFVF9LRVl9XG4gICAgdm9sdW1lczpcbiAgICAgIC0gc3RydXhhLW1pbmlvOi9kYXRhXG4gICAgaGVhbHRoY2hlY2s6XG4gICAgICB0ZXN0OiBbXCJDTURcIiwgXCJjdXJsXCIsIFwiLWZcIiwgXCJodHRwOi8vbG9jYWxob3N0OjkwMDAvbWluaW8vaGVhbHRoL2xpdmVcIl1cbiAgICAgIGludGVydmFsOiAxMHNcbiAgICAgIHRpbWVvdXQ6IDVzXG4gICAgICByZXRyaWVzOiAxMFxuXG4gIG1pZ3JhdGU6XG4gICAgaW1hZ2U6IGdoY3IuaW8vc3RydXhhZG90Y2xvdWQvbWlncmF0ZToke0lNQUdFX1RBR31cbiAgICByZXN0YXJ0OiBvbi1mYWlsdXJlOjVcbiAgICBlbnZpcm9ubWVudDpcbiAgICAgIC0gREFUQUJBU0VfVVJMPSR7REFUQUJBU0VfVVJMfVxuICAgIGRlcGVuZHNfb246XG4gICAgICBteXNxbDpcbiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHlcblxuICBzdHJ1eGE6XG4gICAgaW1hZ2U6IGdoY3IuaW8vc3RydXhhZG90Y2xvdWQvZGFzaGJvYXJkOiR7SU1BR0VfVEFHfVxuICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkXG4gICAgZW50cnlwb2ludDpcbiAgICAgIC0gL2Jpbi9zaFxuICAgICAgLSAtY1xuICAgICAgLSB8XG4gICAgICAgIGV2YWwgXCIkJChub2RlIC1lICdcbiAgICAgICAgICBjb25zdCB7Z2VuZXJhdGVLZXlQYWlyU3luY309cmVxdWlyZShcImNyeXB0b1wiKTtcbiAgICAgICAgICBjb25zdCB7cHVibGljS2V5LHByaXZhdGVLZXl9PWdlbmVyYXRlS2V5UGFpclN5bmMoXCJyc2FcIix7bW9kdWx1c0xlbmd0aDoyMDQ4LFxuICAgICAgICAgICAgcHVibGljS2V5RW5jb2Rpbmc6e3R5cGU6XCJzcGtpXCIsZm9ybWF0OlwicGVtXCJ9LFxuICAgICAgICAgICAgcHJpdmF0ZUtleUVuY29kaW5nOnt0eXBlOlwicGtjczhcIixmb3JtYXQ6XCJwZW1cIn19KTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhcImV4cG9ydCBKV1RfUFJJVkFURV9LRVk9XCIrSlNPTi5zdHJpbmdpZnkocHJpdmF0ZUtleS5yZXBsYWNlKC9cXG4vZyxcIlxcXFxuXCIpKSk7XG4gICAgICAgICAgY29uc29sZS5sb2coXCJleHBvcnQgSldUX1BVQkxJQ19LRVk9XCIrSlNPTi5zdHJpbmdpZnkocHVibGljS2V5LnJlcGxhY2UoL1xcbi9nLFwiXFxcXG5cIikpKTtcbiAgICAgICAgJylcIlxuICAgICAgICBleGVjIG5vZGUgYXBwcy93ZWIvc2VydmVyLmpzXG4gICAgZW52aXJvbm1lbnQ6XG4gICAgICAtIERBVEFCQVNFX1VSTD0ke0RBVEFCQVNFX1VSTH1cbiAgICAgIC0gQkVUVEVSX0FVVEhfU0VDUkVUPSR7QkVUVEVSX0FVVEhfU0VDUkVUfVxuICAgICAgLSBCRVRURVJfQVVUSF9VUkw9JHtCRVRURVJfQVVUSF9VUkx9XG4gICAgICAtIENPUlNfT1JJR0lOPSR7Q09SU19PUklHSU59XG4gICAgICAtIEFQUF9VUkw9JHtBUFBfVVJMfVxuICAgICAgLSBEQVRBQkFTRV9FTkNSWVBUSU9OX0tFWT0ke0RBVEFCQVNFX0VOQ1JZUFRJT05fS0VZfVxuICAgICAgLSBNSU5JT19FTkRQT0lOVD0ke01JTklPX0VORFBPSU5UfVxuICAgICAgLSBNSU5JT19BQ0NFU1NfS0VZPSR7TUlOSU9fQUNDRVNTX0tFWX1cbiAgICAgIC0gTUlOSU9fU0VDUkVUX0tFWT0ke01JTklPX1NFQ1JFVF9LRVl9XG4gICAgICAtIE1JTklPX0JVQ0tFVD0ke01JTklPX0JVQ0tFVH1cbiAgICAgIC0gTk9ERV9FTlY9cHJvZHVjdGlvblxuICAgIGRlcGVuZHNfb246XG4gICAgICBtaWdyYXRlOlxuICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfY29tcGxldGVkX3N1Y2Nlc3NmdWxseVxuICAgICAgbWluaW86XG4gICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5XG5cbiAgd2F0Y2hrZWVwZXI6XG4gICAgaW1hZ2U6IGdoY3IuaW8vc3RydXhhZG90Y2xvdWQvd2F0Y2hrZWVwZXI6JHtJTUFHRV9UQUd9XG4gICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWRcbiAgICBlbnZpcm9ubWVudDpcbiAgICAgIC0gREFUQUJBU0VfVVJMPSR7REFUQUJBU0VfVVJMfVxuICAgICAgLSBEQVRBQkFTRV9FTkNSWVBUSU9OX0tFWT0ke0RBVEFCQVNFX0VOQ1JZUFRJT05fS0VZfVxuICAgIGRlcGVuZHNfb246XG4gICAgICBtaWdyYXRlOlxuICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfY29tcGxldGVkX3N1Y2Nlc3NmdWxseVxuXG52b2x1bWVzOlxuICBzdHJ1eGEtbXlzcWw6XG4gIHN0cnV4YS1taW5pbzpcbiIsCiAgImNvbmZpZyI6ICJbdmFyaWFibGVzXVxubWFpbl9kb21haW4gPSBcIiR7ZG9tYWlufVwiXG5pbWFnZV90YWcgPSBcImxhdGVzdFwiXG5teXNxbF9yb290X3Bhc3N3b3JkID0gXCIke3Bhc3N3b3JkOjMyfVwiXG5teXNxbF9wYXNzd29yZCA9IFwiJHtwYXNzd29yZDozMn1cIlxuYmV0dGVyX2F1dGhfc2VjcmV0ID0gXCIke2Jhc2U2NDozMn1cIlxuZGJfZW5jcnlwdGlvbl9rZXkgPSBcIiR7aGFzaDo2NH1cIlxubWluaW9fYWNjZXNzX2tleSA9IFwiJHt1c2VybmFtZX1cIlxubWluaW9fc2VjcmV0X2tleSA9IFwiJHtwYXNzd29yZDozMn1cIlxuXG5bY29uZmlnXVxuZW52ID0gW1xuICBcIklNQUdFX1RBRz0ke2ltYWdlX3RhZ31cIixcbiAgXCJNWVNRTF9ST09UX1BBU1NXT1JEPSR7bXlzcWxfcm9vdF9wYXNzd29yZH1cIixcbiAgXCJNWVNRTF9EQVRBQkFTRT1zdHJ1eGFcIixcbiAgXCJNWVNRTF9VU0VSPXN0cnV4YVwiLFxuICBcIk1ZU1FMX1BBU1NXT1JEPSR7bXlzcWxfcGFzc3dvcmR9XCIsXG4gIFwiREFUQUJBU0VfVVJMPW15c3FsOi8vc3RydXhhOiR7bXlzcWxfcGFzc3dvcmR9QG15c3FsOjMzMDYvc3RydXhhXCIsXG4gIFwiQkVUVEVSX0FVVEhfU0VDUkVUPSR7YmV0dGVyX2F1dGhfc2VjcmV0fVwiLFxuICBcIkJFVFRFUl9BVVRIX1VSTD1odHRwOi8vJHttYWluX2RvbWFpbn1cIixcbiAgXCJBUFBfVVJMPWh0dHA6Ly8ke21haW5fZG9tYWlufVwiLFxuICBcIkNPUlNfT1JJR0lOPWh0dHA6Ly8ke21haW5fZG9tYWlufVwiLFxuICBcIkRBVEFCQVNFX0VOQ1JZUFRJT05fS0VZPSR7ZGJfZW5jcnlwdGlvbl9rZXl9XCIsXG4gIFwiTUlOSU9fRU5EUE9JTlQ9aHR0cDovL21pbmlvOjkwMDBcIixcbiAgXCJNSU5JT19BQ0NFU1NfS0VZPSR7bWluaW9fYWNjZXNzX2tleX1cIixcbiAgXCJNSU5JT19TRUNSRVRfS0VZPSR7bWluaW9fc2VjcmV0X2tleX1cIixcbiAgXCJNSU5JT19CVUNLRVQ9c3RydXhhXCIsXG5dXG5tb3VudHMgPSBbXVxuXG5bW2NvbmZpZy5kb21haW5zXV1cbnNlcnZpY2VOYW1lID0gXCJzdHJ1eGFcIlxucG9ydCA9IDMwMDFcbmhvc3QgPSBcIiR7bWFpbl9kb21haW59XCJcbiIKfQ==Links
Tags
hosting, game-server, panel, self-hosted
Version: latest
StreamFlow
StreamFlow is a multi-platform live streaming web application that enables simultaneous RTMP streaming to YouTube, Facebook, and other platforms with video gallery, scheduled streaming, and real-time monitoring.
SupaBase
The open source Firebase alternative. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications. This require at least version 0.22.5 of dokploy.