-
- Using a root user is required to ensure everything works as
- expected.
+
+ You can connect as root or as a non-root user with passwordless
+ sudo access. If using a non-root user, ensure passwordless sudo is
+ configured.
diff --git a/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx b/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx
index f36c1b54e..39d5de09f 100644
--- a/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx
+++ b/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx
@@ -163,6 +163,29 @@ export const ValidateServer = ({ serverId }: Props) => {
: "Not Created"
}
/>
+
+
diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts
index 7fabe242d..bfad8836a 100644
--- a/apps/dokploy/server/api/routers/server.ts
+++ b/apps/dokploy/server/api/routers/server.ts
@@ -252,6 +252,8 @@ export const serverRouter = createTRPCRouter({
isDokployNetworkInstalled: boolean;
isSwarmInstalled: boolean;
isMainDirectoryInstalled: boolean;
+ privilegeMode: string;
+ dockerGroupMember: boolean;
};
} catch (error) {
throw new TRPCError({
diff --git a/packages/server/src/setup/server-setup.ts b/packages/server/src/setup/server-setup.ts
index c15856dc3..f66c65e82 100644
--- a/packages/server/src/setup/server-setup.ts
+++ b/packages/server/src/setup/server-setup.ts
@@ -115,9 +115,20 @@ SYS_ARCH=$(uname -m)
CURRENT_USER=$USER
echo "Installing requirements for: OS: $OS_TYPE"
-if [ $EUID != 0 ]; then
- echo "Please run this script as root or with sudo ❌"
- exit
+
+# Auto-detect sudo requirement
+if [ "$EUID" -eq 0 ]; then
+ SUDO_CMD=""
+ echo "Running as root"
+else
+ if sudo -n true 2>/dev/null; then
+ SUDO_CMD="sudo"
+ echo "Running as $CURRENT_USER with sudo privileges"
+ else
+ echo "Error: Non-root user requires passwordless sudo access. ❌"
+ echo "Configure with: echo '$CURRENT_USER ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/$CURRENT_USER"
+ exit 1
+ fi
fi
# Check if the OS is manjaro, if so, change it to arch
@@ -152,7 +163,7 @@ else
fi
if [ "$OS_TYPE" = 'amzn' ]; then
- dnf install -y findutils >/dev/null
+ $SUDO_CMD dnf install -y findutils >/dev/null
fi
case "$OS_TYPE" in
@@ -218,6 +229,9 @@ ${installBuildpacks()}
echo -e "13. Installing Railpack"
${installRailpack()}
+
+echo -e "14. Configuring permissions"
+${setupPermissions()}
`
: `
echo -e "2. Installing Docker. "
@@ -235,6 +249,9 @@ ${installBuildpacks()}
echo -e "6. Installing Railpack"
${installRailpack()}
+
+echo -e "7. Configuring permissions"
+${setupPermissions()}
`
}
`;
@@ -352,16 +369,18 @@ const setupMainDirectory = () => `
echo "/etc/dokploy already exists ✅"
else
# Create the /etc/dokploy directory
- mkdir -p /etc/dokploy
- chmod 777 /etc/dokploy
-
+ $SUDO_CMD mkdir -p /etc/dokploy
echo "Directory /etc/dokploy created ✅"
fi
+ # Ensure the current user owns the directory
+ if [ -n "$SUDO_CMD" ]; then
+ $SUDO_CMD chown -R $CURRENT_USER:$CURRENT_USER /etc/dokploy
+ fi
`;
export const setupSwarm = () => `
# Check if the node is already part of a Docker Swarm
- if docker info | grep -q 'Swarm: active'; then
+ if $SUDO_CMD docker info | grep -q 'Swarm: active'; then
echo "Already part of a Docker Swarm ✅"
else
# Get IP address
@@ -411,18 +430,18 @@ export const setupSwarm = () => `
echo "Advertise address: \$advertise_addr"
# Initialize Docker Swarm
- docker swarm init --advertise-addr \$advertise_addr
+ $SUDO_CMD docker swarm init --advertise-addr \$advertise_addr
echo "Swarm initialized ✅"
fi
`;
const setupNetwork = () => `
# Check if the dokploy-network already exists
- if docker network ls | grep -q 'dokploy-network'; then
+ if $SUDO_CMD docker network ls | grep -q 'dokploy-network'; then
echo "Network dokploy-network already exists ✅"
else
# Create the dokploy-network if it doesn't exist
- if docker network create --driver overlay --attachable dokploy-network; then
+ if $SUDO_CMD docker network create --driver overlay --attachable dokploy-network; then
echo "Network created ✅"
else
echo "Failed to create dokploy-network ❌" >&2
@@ -447,33 +466,34 @@ const installUtilities = () => `
case "$OS_TYPE" in
arch)
- pacman -Sy --noconfirm --needed curl wget git git-lfs jq openssl >/dev/null || true
+ $SUDO_CMD pacman -Sy --noconfirm --needed curl wget git git-lfs jq openssl >/dev/null || true
;;
alpine)
- sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
- apk update >/dev/null
- apk add curl wget git git-lfs jq openssl sudo unzip tar >/dev/null
+ $SUDO_CMD sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
+ $SUDO_CMD apk update >/dev/null
+ $SUDO_CMD apk add curl wget git git-lfs jq openssl sudo unzip tar >/dev/null
;;
ubuntu | debian | raspbian)
- DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null
- DEBIAN_FRONTEND=noninteractive apt-get install -y unzip curl wget git git-lfs jq openssl >/dev/null
+ export DEBIAN_FRONTEND=noninteractive
+ $SUDO_CMD apt-get update -y >/dev/null
+ $SUDO_CMD apt-get install -y unzip curl wget git git-lfs jq openssl >/dev/null
;;
centos | fedora | rhel | ol | rocky | almalinux | opencloudos | amzn)
if [ "$OS_TYPE" = "amzn" ]; then
- dnf install -y wget git git-lfs jq openssl >/dev/null
+ $SUDO_CMD dnf install -y wget git git-lfs jq openssl >/dev/null
else
if ! command -v dnf >/dev/null; then
- yum install -y dnf >/dev/null
+ $SUDO_CMD yum install -y dnf >/dev/null
fi
if ! command -v curl >/dev/null; then
- dnf install -y curl >/dev/null
+ $SUDO_CMD dnf install -y curl >/dev/null
fi
- dnf install -y wget git git-lfs jq openssl unzip >/dev/null
+ $SUDO_CMD dnf install -y wget git git-lfs jq openssl unzip >/dev/null
fi
;;
sles | opensuse-leap | opensuse-tumbleweed)
- zypper refresh >/dev/null
- zypper install -y curl wget git git-lfs jq openssl >/dev/null
+ $SUDO_CMD zypper refresh >/dev/null
+ $SUDO_CMD zypper install -y curl wget git git-lfs jq openssl >/dev/null
;;
*)
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
@@ -500,41 +520,41 @@ if ! [ -x "$(command -v docker)" ]; then
echo " - Docker is not installed. Installing Docker. It may take a while."
case "$OS_TYPE" in
"almalinux")
- dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1
- dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
+ $SUDO_CMD dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1
+ $SUDO_CMD dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
exit 1
fi
- systemctl start docker >/dev/null 2>&1
- systemctl enable docker >/dev/null 2>&1
+ $SUDO_CMD systemctl start docker >/dev/null 2>&1
+ $SUDO_CMD systemctl enable docker >/dev/null 2>&1
;;
"opencloudos")
# Special handling for OpenCloud OS
echo " - Installing Docker for OpenCloud OS..."
- dnf install -y docker >/dev/null 2>&1
+ $SUDO_CMD dnf install -y docker >/dev/null 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
exit 1
fi
-
+
# Remove --live-restore parameter from Docker configuration if it exists
if [ -f "/etc/sysconfig/docker" ]; then
echo " - Removing --live-restore parameter from Docker configuration..."
- sed -i 's/--live-restore[^[:space:]]*//' /etc/sysconfig/docker >/dev/null 2>&1
- sed -i 's/--live-restore//' /etc/sysconfig/docker >/dev/null 2>&1
+ $SUDO_CMD sed -i 's/--live-restore[^[:space:]]*//' /etc/sysconfig/docker >/dev/null 2>&1
+ $SUDO_CMD sed -i 's/--live-restore//' /etc/sysconfig/docker >/dev/null 2>&1
# Clean up any double spaces that might be left
- sed -i 's/ */ /g' /etc/sysconfig/docker >/dev/null 2>&1
+ $SUDO_CMD sed -i 's/ */ /g' /etc/sysconfig/docker >/dev/null 2>&1
fi
-
- systemctl enable docker >/dev/null 2>&1
- systemctl start docker >/dev/null 2>&1
+
+ $SUDO_CMD systemctl enable docker >/dev/null 2>&1
+ $SUDO_CMD systemctl start docker >/dev/null 2>&1
echo " - Docker configured for OpenCloud OS"
;;
"alpine")
- apk add docker docker-cli-compose >/dev/null 2>&1
- rc-update add docker default >/dev/null 2>&1
- service docker start >/dev/null 2>&1
+ $SUDO_CMD apk add docker docker-cli-compose >/dev/null 2>&1
+ $SUDO_CMD rc-update add docker default >/dev/null 2>&1
+ $SUDO_CMD service docker start >/dev/null 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Failed to install Docker with apk. Try to install it manually."
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
@@ -542,8 +562,8 @@ if ! [ -x "$(command -v docker)" ]; then
fi
;;
"arch")
- pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
- systemctl enable docker.service >/dev/null 2>&1
+ $SUDO_CMD pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
+ $SUDO_CMD systemctl enable docker.service >/dev/null 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Failed to install Docker with pacman. Try to install it manually."
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
@@ -551,13 +571,13 @@ if ! [ -x "$(command -v docker)" ]; then
fi
;;
"amzn")
- dnf install docker -y >/dev/null 2>&1
+ $SUDO_CMD dnf install docker -y >/dev/null 2>&1
DOCKER_CONFIG=/usr/local/lib/docker
- mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
- curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
- chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
- systemctl start docker >/dev/null 2>&1
- systemctl enable docker >/dev/null 2>&1
+ $SUDO_CMD mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
+ $SUDO_CMD curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
+ $SUDO_CMD chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
+ $SUDO_CMD systemctl start docker >/dev/null 2>&1
+ $SUDO_CMD systemctl enable docker >/dev/null 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Failed to install Docker with dnf. Try to install it manually."
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
@@ -567,18 +587,18 @@ if ! [ -x "$(command -v docker)" ]; then
"fedora")
if [ -x "$(command -v dnf5)" ]; then
# dnf5 is available
- dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
+ $SUDO_CMD dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
else
# dnf5 is not available, use dnf
- dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
+ $SUDO_CMD dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
fi
- dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
+ $SUDO_CMD dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
exit 1
fi
- systemctl start docker >/dev/null 2>&1
- systemctl enable docker >/dev/null 2>&1
+ $SUDO_CMD systemctl start docker >/dev/null 2>&1
+ $SUDO_CMD systemctl enable docker >/dev/null 2>&1
;;
*)
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
@@ -586,9 +606,9 @@ if ! [ -x "$(command -v docker)" ]; then
echo "Please install Docker manually."
exit 1
fi
-
+
if ! [ -x "$(command -v docker)" ]; then
- curl -s https://get.docker.com | sh -s -- --version $DOCKER_VERSION 2>&1
+ curl -s https://get.docker.com | $SUDO_CMD sh -s -- --version $DOCKER_VERSION 2>&1
if ! [ -x "$(command -v docker)" ]; then
echo " - Docker installation failed."
echo " Maybe your OS is not supported?"
@@ -597,13 +617,13 @@ if ! [ -x "$(command -v docker)" ]; then
fi
fi
if [ "$OS_TYPE" = "rocky" ]; then
- systemctl start docker >/dev/null 2>&1
- systemctl enable docker >/dev/null 2>&1
+ $SUDO_CMD systemctl start docker >/dev/null 2>&1
+ $SUDO_CMD systemctl enable docker >/dev/null 2>&1
fi
if [ "$OS_TYPE" = "centos" ]; then
- systemctl start docker >/dev/null 2>&1
- systemctl enable docker >/dev/null 2>&1
+ $SUDO_CMD systemctl start docker >/dev/null 2>&1
+ $SUDO_CMD systemctl enable docker >/dev/null 2>&1
fi
@@ -647,7 +667,7 @@ export const installRClone = () => `
if command_exists rclone; then
echo "RClone already installed ✅"
else
- curl https://rclone.org/install.sh | sudo bash
+ curl https://rclone.org/install.sh | $SUDO_CMD bash
RCLONE_VERSION=$(rclone --version | head -n 1 | awk '{print $2}' | sed 's/^v//')
echo "RClone version $RCLONE_VERSION installed ✅"
fi
@@ -656,19 +676,19 @@ export const installRClone = () => `
export const createTraefikInstance = () => {
const command = `
# Check if dokpyloy-traefik exists
- if docker service inspect dokploy-traefik > /dev/null 2>&1; then
+ if $SUDO_CMD docker service inspect dokploy-traefik > /dev/null 2>&1; then
echo "Migrating Traefik to Standalone..."
- docker service rm dokploy-traefik
+ $SUDO_CMD docker service rm dokploy-traefik
sleep 8
echo "Traefik migrated to Standalone ✅"
fi
- if docker inspect dokploy-traefik > /dev/null 2>&1; then
+ if $SUDO_CMD docker inspect dokploy-traefik > /dev/null 2>&1; then
echo "Traefik already exists ✅"
else
# Create the dokploy-traefik container
TRAEFIK_VERSION=${TRAEFIK_VERSION}
- docker run -d \
+ $SUDO_CMD docker run -d \
--name dokploy-traefik \
--restart always \
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
@@ -679,7 +699,7 @@ export const createTraefikInstance = () => {
-p ${TRAEFIK_HTTP3_PORT}:${TRAEFIK_HTTP3_PORT}/udp \
traefik:v$TRAEFIK_VERSION
- docker network connect dokploy-network dokploy-traefik;
+ $SUDO_CMD docker network connect dokploy-network dokploy-traefik;
echo "Traefik version $TRAEFIK_VERSION installed ✅"
fi
`;
@@ -692,7 +712,7 @@ const installNixpacks = () => `
echo "Nixpacks already installed ✅"
else
export NIXPACKS_VERSION=1.41.0
- bash -c "$(curl -fsSL https://nixpacks.com/install.sh)"
+ $SUDO_CMD bash -c "$(curl -fsSL https://nixpacks.com/install.sh)"
echo "Nixpacks version $NIXPACKS_VERSION installed ✅"
fi
`;
@@ -702,11 +722,28 @@ const installRailpack = () => `
echo "Railpack already installed ✅"
else
export RAILPACK_VERSION=0.15.4
- bash -c "$(curl -fsSL https://railpack.com/install.sh)"
+ $SUDO_CMD bash -c "$(curl -fsSL https://railpack.com/install.sh)"
echo "Railpack version $RAILPACK_VERSION installed ✅"
fi
`;
+const setupPermissions = () => `
+ # Add user to docker group if not root
+ if [ -n "$SUDO_CMD" ]; then
+ if ! groups $CURRENT_USER | grep -qw docker; then
+ $SUDO_CMD usermod -aG docker $CURRENT_USER
+ echo "User $CURRENT_USER added to docker group ✅"
+ else
+ echo "User $CURRENT_USER already in docker group ✅"
+ fi
+ # Ensure the user owns the dokploy directory
+ $SUDO_CMD chown -R $CURRENT_USER:$CURRENT_USER /etc/dokploy
+ echo "Permissions configured for $CURRENT_USER ✅"
+ else
+ echo "Running as root, no extra permissions needed ✅"
+ fi
+`;
+
const installBuildpacks = () => `
SUFFIX=""
if [ "$SYS_ARCH" = "aarch64" ] || [ "$SYS_ARCH" = "arm64" ]; then
@@ -716,7 +753,7 @@ const installBuildpacks = () => `
echo "Buildpacks already installed ✅"
else
BUILDPACKS_VERSION=0.39.1
- curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.39.1/pack-v$BUILDPACKS_VERSION-linux$SUFFIX.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack
+ curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.39.1/pack-v$BUILDPACKS_VERSION-linux$SUFFIX.tgz" | $SUDO_CMD tar -C /usr/local/bin/ --no-same-owner -xzv pack
echo "Buildpacks version $BUILDPACKS_VERSION installed ✅"
fi
`;
diff --git a/packages/server/src/setup/server-validate.ts b/packages/server/src/setup/server-validate.ts
index b190fde28..f55bbe616 100644
--- a/packages/server/src/setup/server-validate.ts
+++ b/packages/server/src/setup/server-validate.ts
@@ -79,6 +79,24 @@ export const validateDokployNetwork = () => `
fi
`;
+export const validateSudoAccess = () => `
+ if [ "$(id -u)" -eq 0 ]; then
+ echo "root true"
+ elif sudo -n true 2>/dev/null; then
+ echo "sudo true"
+ else
+ echo "none false"
+ fi
+`;
+
+export const validateDockerGroup = () => `
+ if groups | grep -qw docker; then
+ echo true
+ else
+ echo false
+ fi
+`;
+
export const serverValidate = async (serverId: string) => {
const client = new Client();
const server = await findServerById(serverId);
@@ -118,7 +136,11 @@ export const serverValidate = async (serverId: string) => {
isSwarmInstalled=$(${validateSwarm()})
isMainDirectoryInstalled=$(${validateMainDirectory()})
- echo "{\\"docker\\": {\\"version\\": \\"$dockerVersion\\", \\"enabled\\": $dockerEnabled}, \\"rclone\\": {\\"version\\": \\"$rcloneVersion\\", \\"enabled\\": $rcloneEnabled}, \\"nixpacks\\": {\\"version\\": \\"$nixpacksVersion\\", \\"enabled\\": $nixpacksEnabled}, \\"buildpacks\\": {\\"version\\": \\"$buildpacksVersion\\", \\"enabled\\": $buildpacksEnabled}, \\"railpack\\": {\\"version\\": \\"$railpackVersion\\", \\"enabled\\": $railpackEnabled}, \\"isDokployNetworkInstalled\\": $isDokployNetworkInstalled, \\"isSwarmInstalled\\": $isSwarmInstalled, \\"isMainDirectoryInstalled\\": $isMainDirectoryInstalled}"
+ sudoAccessResult=$(${validateSudoAccess()})
+ privilegeMode=$(echo $sudoAccessResult | awk '{print $1}')
+ isDockerGroupMember=$(${validateDockerGroup()})
+
+ echo "{\\"docker\\": {\\"version\\": \\"$dockerVersion\\", \\"enabled\\": $dockerEnabled}, \\"rclone\\": {\\"version\\": \\"$rcloneVersion\\", \\"enabled\\": $rcloneEnabled}, \\"nixpacks\\": {\\"version\\": \\"$nixpacksVersion\\", \\"enabled\\": $nixpacksEnabled}, \\"buildpacks\\": {\\"version\\": \\"$buildpacksVersion\\", \\"enabled\\": $buildpacksEnabled}, \\"railpack\\": {\\"version\\": \\"$railpackVersion\\", \\"enabled\\": $railpackEnabled}, \\"isDokployNetworkInstalled\\": $isDokployNetworkInstalled, \\"isSwarmInstalled\\": $isSwarmInstalled, \\"isMainDirectoryInstalled\\": $isMainDirectoryInstalled, \\"privilegeMode\\": \\"$privilegeMode\\", \\"dockerGroupMember\\": $isDockerGroupMember}"
`;
client.exec(bashCommand, (err, stream) => {
if (err) {