From 8c735dd42c434b38f8eede24705772fdc3b93fc0 Mon Sep 17 00:00:00 2001 From: Manuele Sarfatti Date: Tue, 16 Sep 2025 20:46:24 +0200 Subject: [PATCH] feat: allow Dokploy to be installed as sudo user --- .../content/docs/core/manual-installation.mdx | 61 +++++---- apps/website/public/canary.sh | 118 ++++++++++-------- apps/website/public/feature.sh | 116 +++++++++-------- apps/website/public/install.sh | 73 ++++++----- 4 files changed, 208 insertions(+), 160 deletions(-) diff --git a/apps/docs/content/docs/core/manual-installation.mdx b/apps/docs/content/docs/core/manual-installation.mdx index 9fa3088f..cc1d61bd 100644 --- a/apps/docs/content/docs/core/manual-installation.mdx +++ b/apps/docs/content/docs/core/manual-installation.mdx @@ -1,6 +1,6 @@ --- -title: 'Manual Installation' -description: 'Learn how to manually install Dokploy on your server.' +title: "Manual Installation" +description: "Learn how to manually install Dokploy on your server." --- If you wish to customize the Dokploy installation on your server, you can modify several enviroment variables: @@ -15,14 +15,13 @@ If you wish to customize the Dokploy installation on your server, you can modify ## Installation Script -Here is a Bash script for installing Dokploy on a Linux server. Make sure you run this as root on a Linux environment that is not a container, and ensure ports 80 and 443 are free. - +Here is a Bash script for installing Dokploy on a Linux server. Make sure you run this as root ( or as a user with NOPASSWD sudo access) on a Linux environment that is not a container, and ensure ports 80 and 443 are free. ```bash #!/bin/bash install_dokploy() { - if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 + if [ "$(id -u)" != "0" ] && ! sudo -n true 2>/dev/null; then + echo "This script must be run as root or as a user with NOPASSWD sudo access" >&2 exit 1 fi @@ -51,29 +50,44 @@ install_dokploy() { fi command_exists() { - command -v "$@" > /dev/null 2>&1 + command -v "$@" > /dev/null 2>&1 } if command_exists docker; then - echo "Docker already installed" + echo "Docker already installed" else - curl -sSL https://get.docker.com | sh + curl -sSL https://get.docker.com | sudo sh + fi + + # Add ourselves to docker group to run docker commands without sudo + if ! getent group docker >/dev/null; then + sudo groupadd docker + fi + + if ! groups | grep -q docker; then + sudo usermod -aG docker "$USER" + newgrp docker fi + # Make sure docker config directory permissions are correct + mkdir -p "$HOME"/.docker + sudo chown "$USER":"$USER" "$HOME"/.docker -R + sudo chmod g+rwx "$HOME"/.docker -R + docker swarm leave --force 2>/dev/null get_ip() { local ip="" - + # Try IPv4 first # First attempt: ifconfig.io ip=$(curl -4s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Second attempt: icanhazip.com if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Third attempt: ipecho.net if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -83,12 +97,12 @@ install_dokploy() { if [ -z "$ip" ]; then # Try IPv6 with ifconfig.io ip=$(curl -6s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Try IPv6 with icanhazip.com if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Try IPv6 with ipecho.net if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -109,7 +123,7 @@ install_dokploy() { echo "Using advertise address: $advertise_addr" docker swarm init --advertise-addr $advertise_addr - + if [ $? -ne 0 ]; then echo "Error: Failed to initialize Docker Swarm" >&2 exit 1 @@ -122,9 +136,7 @@ install_dokploy() { echo "Network created" - mkdir -p /etc/dokploy - - chmod 777 /etc/dokploy + sudo install -d -o "$(id -u)" -g "$(id -g)" -m 775 /etc/dokploy docker service create \ --name dokploy-postgres \ @@ -164,6 +176,7 @@ install_dokploy() { docker run -d \ --name dokploy-traefik \ + --user "$(id -u)":"$(id -g)" \ --restart always \ -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \ -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \ @@ -214,7 +227,7 @@ install_dokploy() { update_dokploy() { echo "Updating Dokploy..." - + # Pull the latest image docker pull dokploy/dokploy:latest @@ -237,7 +250,8 @@ This script includes checks for common pitfalls, installs Docker if it’s not a This structured format clearly lays out the prerequisites, steps, and post-installation information, making it user-friendly and accessible for those performing manual installations. -## Customize install +## Customize install + #### Customize swarm advertise address The --advertise-addr parameter in the docker swarm init command specifies the IP address or interface that the Docker Swarm manager node should advertise to other nodes in the Swarm. This address is used by other nodes to communicate with the manager. @@ -249,18 +263,14 @@ To customize the --advertise-addr parameter, replace the line: `advertise_addr=$ :warning: This IP address should be accessible to all nodes that will join the Swarm. - ## Existing Docker swarm If you already have a Docker swarm running on your server and you want to use dokploy, you can use the following command to join it: - ```bash docker network create --driver overlay --attachable dokploy-network -mkdir -p /etc/dokploy - -chmod -R 777 /etc/dokploy +sudo install -d -o "$(id -u)" -g "$(id -g)" -m 775 /etc/dokploy docker pull dokploy/dokploy:latest @@ -284,4 +294,3 @@ To upgrade Dokploy manually, you can use the following command: ```bash curl -sSL https://dokploy.com/install.sh | sh -s update ``` - diff --git a/apps/website/public/canary.sh b/apps/website/public/canary.sh index eaf04f2d..fc15b4ac 100644 --- a/apps/website/public/canary.sh +++ b/apps/website/public/canary.sh @@ -1,7 +1,7 @@ #!/bin/bash install_dokploy() { - if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 + if [ "$(id -u)" != "0" ] && ! sudo -n true 2>/dev/null; then + echo "This script must be run as root or as a user with NOPASSWD sudo access" >&2 exit 1 fi @@ -30,29 +30,44 @@ install_dokploy() { fi command_exists() { - command -v "$@" > /dev/null 2>&1 + command -v "$@" > /dev/null 2>&1 } if command_exists docker; then - echo "Docker already installed" + echo "Docker already installed" else - curl -sSL https://get.docker.com | sh + curl -sSL https://get.docker.com | sudo sh fi + # Add ourselves to docker group to run docker commands without sudo + if ! getent group docker >/dev/null; then + sudo groupadd docker + fi + + if ! groups | grep -q docker; then + sudo usermod -aG docker "$USER" + newgrp docker + fi + + # Make sure docker config directory permissions are correct + mkdir -p "$HOME"/.docker + sudo chown "$USER":"$USER" "$HOME"/.docker -R + sudo chmod g+rwx "$HOME"/.docker -R + docker swarm leave --force 2>/dev/null get_ip() { local ip="" - + # Try IPv4 first # First attempt: ifconfig.io ip=$(curl -4s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Second attempt: icanhazip.com if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Third attempt: ipecho.net if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -62,12 +77,12 @@ install_dokploy() { if [ -z "$ip" ]; then # Try IPv6 with ifconfig.io ip=$(curl -6s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Try IPv6 with icanhazip.com if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Try IPv6 with ipecho.net if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -99,8 +114,8 @@ install_dokploy() { echo "Using advertise address: $advertise_addr" docker swarm init --advertise-addr $advertise_addr - - if [ $? -ne 0 ]; then + + if [ $? -ne 0 ]; then echo "Error: Failed to initialize Docker Swarm" >&2 exit 1 fi @@ -112,55 +127,54 @@ install_dokploy() { echo "Network created" - mkdir -p /etc/dokploy - - chmod 777 /etc/dokploy + sudo install -d -o "$(id -u)" -g "$(id -g)" -m 775 /etc/dokploy docker service create \ - --name dokploy-postgres \ - --constraint 'node.role==manager' \ - --network dokploy-network \ - --env POSTGRES_USER=dokploy \ - --env POSTGRES_DB=dokploy \ - --env POSTGRES_PASSWORD=amukds4wi9001583845717ad2 \ - --mount type=volume,source=dokploy-postgres-database,target=/var/lib/postgresql/data \ - postgres:16 + --name dokploy-postgres \ + --constraint 'node.role==manager' \ + --network dokploy-network \ + --env POSTGRES_USER=dokploy \ + --env POSTGRES_DB=dokploy \ + --env POSTGRES_PASSWORD=amukds4wi9001583845717ad2 \ + --mount type=volume,source=dokploy-postgres-database,target=/var/lib/postgresql/data \ + postgres:16 docker service create \ - --name dokploy-redis \ - --constraint 'node.role==manager' \ - --network dokploy-network \ - --mount type=volume,source=redis-data-volume,target=/data \ - redis:7 + --name dokploy-redis \ + --constraint 'node.role==manager' \ + --network dokploy-network \ + --mount type=volume,source=redis-data-volume,target=/data \ + redis:7 # Installation docker service create \ - --name dokploy \ - --replicas 1 \ - --network dokploy-network \ - --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ - --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ - --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ - --publish published=3000,target=3000,mode=host \ - --update-parallelism 1 \ - --update-order stop-first \ - --constraint 'node.role == manager' \ - -e RELEASE_TAG=canary \ - -e ADVERTISE_ADDR=$advertise_addr \ - dokploy/dokploy:canary + --name dokploy \ + --replicas 1 \ + --network dokploy-network \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ + --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ + --publish published=3000,target=3000,mode=host \ + --update-parallelism 1 \ + --update-order stop-first \ + --constraint 'node.role == manager' \ + -e RELEASE_TAG=canary \ + -e ADVERTISE_ADDR=$advertise_addr \ + dokploy/dokploy:canary sleep 4 docker run -d \ - --name dokploy-traefik \ - --restart always \ - -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \ - -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -p 80:80/tcp \ - -p 443:443/tcp \ - -p 443:443/udp \ - traefik:v3.5.0 + --name dokploy-traefik \ + --user "$(id -u)":"$(id -g)" \ + --restart always \ + -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \ + -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -p 80:80/tcp \ + -p 443:443/tcp \ + -p 443:443/udp \ + traefik:v3.5.0 docker network connect dokploy-network dokploy-traefik @@ -203,7 +217,7 @@ install_dokploy() { update_dokploy() { echo "Updating Dokploy..." - + # Pull the latest canary image docker pull dokploy/dokploy:canary @@ -218,4 +232,4 @@ if [ "$1" = "update" ]; then update_dokploy else install_dokploy -fi \ No newline at end of file +fi diff --git a/apps/website/public/feature.sh b/apps/website/public/feature.sh index 16f57222..b90bd390 100644 --- a/apps/website/public/feature.sh +++ b/apps/website/public/feature.sh @@ -1,7 +1,7 @@ #!/bin/bash install_dokploy() { - if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 + if [ "$(id -u)" != "0" ] && ! sudo -n true 2>/dev/null; then + echo "This script must be run as root or as a user with NOPASSWD sudo access" >&2 exit 1 fi @@ -30,29 +30,44 @@ install_dokploy() { fi command_exists() { - command -v "$@" > /dev/null 2>&1 + command -v "$@" > /dev/null 2>&1 } if command_exists docker; then - echo "Docker already installed" + echo "Docker already installed" else - curl -sSL https://get.docker.com | sh + curl -sSL https://get.docker.com | sudo sh fi + # Add ourselves to docker group to run docker commands without sudo + if ! getent group docker >/dev/null; then + sudo groupadd docker + fi + + if ! groups | grep -q docker; then + sudo usermod -aG docker "$USER" + newgrp docker + fi + + # Make sure docker config directory permissions are correct + mkdir -p "$HOME"/.docker + sudo chown "$USER":"$USER" "$HOME"/.docker -R + sudo chmod g+rwx "$HOME"/.docker -R + docker swarm leave --force 2>/dev/null get_ip() { local ip="" - + # Try IPv4 first # First attempt: ifconfig.io ip=$(curl -4s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Second attempt: icanhazip.com if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Third attempt: ipecho.net if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -62,12 +77,12 @@ install_dokploy() { if [ -z "$ip" ]; then # Try IPv6 with ifconfig.io ip=$(curl -6s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Try IPv6 with icanhazip.com if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Try IPv6 with ipecho.net if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -112,57 +127,54 @@ install_dokploy() { echo "Network created" - mkdir -p /etc/dokploy - - chmod 777 /etc/dokploy + sudo install -d -o "$(id -u)" -g "$(id -g)" -m 775 /etc/dokploy docker service create \ - --name dokploy-postgres \ - --constraint 'node.role==manager' \ - --network dokploy-network \ - --env POSTGRES_USER=dokploy \ - --env POSTGRES_DB=dokploy \ - --env POSTGRES_PASSWORD=amukds4wi9001583845717ad2 \ - --mount type=volume,source=dokploy-postgres-database,target=/var/lib/postgresql/data \ - postgres:16 - + --name dokploy-postgres \ + --constraint 'node.role==manager' \ + --network dokploy-network \ + --env POSTGRES_USER=dokploy \ + --env POSTGRES_DB=dokploy \ + --env POSTGRES_PASSWORD=amukds4wi9001583845717ad2 \ + --mount type=volume,source=dokploy-postgres-database,target=/var/lib/postgresql/data \ + postgres:16 docker service create \ - --name dokploy-redis \ - --constraint 'node.role==manager' \ - --network dokploy-network \ - --mount type=volume,source=redis-data-volume,target=/data \ - redis:7 - + --name dokploy-redis \ + --constraint 'node.role==manager' \ + --network dokploy-network \ + --mount type=volume,source=redis-data-volume,target=/data \ + redis:7 # Installation docker service create \ - --name dokploy \ - --replicas 1 \ - --network dokploy-network \ - --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ - --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ - --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ - --publish published=3000,target=3000,mode=host \ - --update-parallelism 1 \ - --update-order stop-first \ - --constraint 'node.role == manager' \ - -e RELEASE_TAG=feature \ - -e ADVERTISE_ADDR=$advertise_addr \ - dokploy/dokploy:feature + --name dokploy \ + --replicas 1 \ + --network dokploy-network \ + --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ + --mount type=bind,source=/etc/dokploy,target=/etc/dokploy \ + --mount type=volume,source=dokploy-docker-config,target=/root/.docker \ + --publish published=3000,target=3000,mode=host \ + --update-parallelism 1 \ + --update-order stop-first \ + --constraint 'node.role == manager' \ + -e RELEASE_TAG=feature \ + -e ADVERTISE_ADDR=$advertise_addr \ + dokploy/dokploy:feature sleep 4 docker run -d \ - --name dokploy-traefik \ - --restart always \ - -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \ - -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -p 80:80/tcp \ - -p 443:443/tcp \ - -p 443:443/udp \ - traefik:v3.5.0 + --name dokploy-traefik \ + --user "$(id -u)":"$(id -g)" \ + --restart always \ + -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \ + -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -p 80:80/tcp \ + -p 443:443/tcp \ + -p 443:443/udp \ + traefik:v3.5.0 docker network connect dokploy-network dokploy-traefik @@ -206,7 +218,7 @@ install_dokploy() { update_dokploy() { echo "Updating Dokploy..." - + # Pull the latest feature image docker pull dokploy/dokploy:feature @@ -221,4 +233,4 @@ if [ "$1" = "update" ]; then update_dokploy else install_dokploy -fi \ No newline at end of file +fi diff --git a/apps/website/public/install.sh b/apps/website/public/install.sh index 1cc6d81f..d7bdfa37 100644 --- a/apps/website/public/install.sh +++ b/apps/website/public/install.sh @@ -16,8 +16,8 @@ is_proxmox_lxc() { } install_dokploy() { - if [ "$(id -u)" != "0" ]; then - echo "This script must be run as root" >&2 + if [ "$(id -u)" != "0" ] && ! sudo -n true 2>/dev/null; then + echo "This script must be run as root or as a user with NOPASSWD sudo access" >&2 exit 1 fi @@ -46,13 +46,13 @@ install_dokploy() { fi command_exists() { - command -v "$@" > /dev/null 2>&1 + command -v "$@" > /dev/null 2>&1 } if command_exists docker; then - echo "Docker already installed" + echo "Docker already installed" else - curl -sSL https://get.docker.com | sh + curl -sSL https://get.docker.com | sudo sh fi # Check if running in Proxmox LXC container and set endpoint mode @@ -68,20 +68,35 @@ install_dokploy() { fi + # Add ourselves to docker group to run docker commands without sudo + if ! getent group docker >/dev/null; then + sudo groupadd docker + fi + + if ! groups | grep -q docker; then + sudo usermod -aG docker "$USER" + newgrp docker + fi + + # Make sure docker config directory permissions are correct + mkdir -p "$HOME"/.docker + sudo chown "$USER":"$USER" "$HOME"/.docker -R + sudo chmod g+rwx "$HOME"/.docker -R + docker swarm leave --force 2>/dev/null get_ip() { local ip="" - + # Try IPv4 first # First attempt: ifconfig.io ip=$(curl -4s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Second attempt: icanhazip.com if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Third attempt: ipecho.net if [ -z "$ip" ]; then ip=$(curl -4s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -91,12 +106,12 @@ install_dokploy() { if [ -z "$ip" ]; then # Try IPv6 with ifconfig.io ip=$(curl -6s --connect-timeout 5 https://ifconfig.io 2>/dev/null) - + # Try IPv6 with icanhazip.com if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://icanhazip.com 2>/dev/null) fi - + # Try IPv6 with ipecho.net if [ -z "$ip" ]; then ip=$(curl -6s --connect-timeout 5 https://ipecho.net/plain 2>/dev/null) @@ -128,8 +143,8 @@ install_dokploy() { echo "Using advertise address: $advertise_addr" docker swarm init --advertise-addr $advertise_addr - - if [ $? -ne 0 ]; then + + if [ $? -ne 0 ]; then echo "Error: Failed to initialize Docker Swarm" >&2 exit 1 fi @@ -141,26 +156,24 @@ install_dokploy() { echo "Network created" - mkdir -p /etc/dokploy - - chmod 777 /etc/dokploy + sudo install -d -o "$(id -u)" -g "$(id -g)" -m 775 /etc/dokploy docker service create \ - --name dokploy-postgres \ - --constraint 'node.role==manager' \ - --network dokploy-network \ - --env POSTGRES_USER=dokploy \ - --env POSTGRES_DB=dokploy \ - --env POSTGRES_PASSWORD=amukds4wi9001583845717ad2 \ - --mount type=volume,source=dokploy-postgres-database,target=/var/lib/postgresql/data \ - postgres:16 + --name dokploy-postgres \ + --constraint 'node.role==manager' \ + --network dokploy-network \ + --env POSTGRES_USER=dokploy \ + --env POSTGRES_DB=dokploy \ + --env POSTGRES_PASSWORD=amukds4wi9001583845717ad2 \ + --mount type=volume,source=dokploy-postgres-database,target=/var/lib/postgresql/data \ + postgres:16 docker service create \ - --name dokploy-redis \ - --constraint 'node.role==manager' \ - --network dokploy-network \ - --mount type=volume,source=redis-data-volume,target=/data \ - redis:7 + --name dokploy-redis \ + --constraint 'node.role==manager' \ + --network dokploy-network \ + --mount type=volume,source=redis-data-volume,target=/data \ + redis:7 # Installation docker service create \ @@ -182,6 +195,7 @@ install_dokploy() { docker run -d \ --name dokploy-traefik \ + --user "$(id -u)":"$(id -g)" \ --restart always \ -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \ -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \ @@ -193,7 +207,6 @@ install_dokploy() { docker network connect dokploy-network dokploy-traefik - # Optional: Use docker service create instead of docker run # docker service create \ # --name dokploy-traefik \ @@ -233,7 +246,7 @@ install_dokploy() { update_dokploy() { echo "Updating Dokploy..." - + # Pull the latest image docker pull dokploy/dokploy:latest