Deploy an app from GitHub with Dokploy on a VPS

Install Dokploy on a VPS, connect GitHub, deploy an app with Nixpacks or a Dockerfile, add a domain with Let's Encrypt, then close port 3000 and firewall it.

Contents14 sections
By Toni LukeUpdated 8 min read

To deploy from GitHub with Dokploy, install it on a VPS with one script, create a GitHub App from the Dokploy panel, and point a new Application at your repo and branch. Dokploy builds it (Nixpacks by default), runs it, and routes a domain to it through Traefik with a Let's Encrypt certificate. Once the GitHub App is connected, every push to that branch redeploys automatically.

The steps below follow Dokploy's documentation as of 29 September 2026. The latest release then was v0.30.7, published 18 September 2026.

Prerequisites

  • A VPS with at least 2GB of RAM and 30GB of disk. The installation page says that's what handles Docker's build-time resource use "and prevents system freezes."
  • A tested distro. The docs list Ubuntu 24.04, 23.10, 22.04, 20.04 and 18.04, Debian 12, 11 and 10, Fedora 40, and CentOS 9 and 8. The hardening guide adds that Dokploy's automated security check only targets Ubuntu and Debian LTS, so those are the easiest choice.
  • Ports 80, 443 and 3000 free. Traefik takes 80 and 443, and the panel uses 3000. The docs say the install fails if any of them is already in use.
  • A domain name, if you want HTTPS. Dokploy can hand out free traefik.me hostnames, but the Domains page says those are HTTP only.
  • A GitHub repository for the app.

Docker doesn't need to be installed first. The script installs it if it's missing.

Step 1: install Dokploy

SSH into the server and run the installer from the docs:

bash
curl -sSL https://dokploy.com/install.sh | sh

The script installs the latest stable release. It sets up Docker and Docker Swarm, then starts Traefik and the Dokploy services.

Situations the installation page covers:

  • Running it with sudo. sudo resets your environment, so a variable you export never reaches the script. Pass it inline, as the docs show: curl -sSL https://dokploy.com/install.sh | sudo ADVERTISE_ADDR=192.168.1.100 sh.
  • The script picks the wrong IP, or you want Swarm on a VPN interface. Set ADVERTISE_ADDR as above.
  • The Swarm network clashes with your cloud VPC. Set DOCKER_SWARM_INIT_ARGS="--default-addr-pool 172.20.0.0/16 --default-addr-pool-mask-length 24" before running the script.
  • You need a specific version. Use the install.sh attached to that GitHub release. The docs warn against setting DOKPLOY_VERSION to an old version, because the main script always targets the latest setup.

Step 2: create the admin account

Open http://your-server-ip:3000.

What you should see: the initial setup page. The first account you create there becomes the Dokploy admin. If the page doesn't load, the docs point at the firewall: make sure it allows port 3000.

Step 3: connect GitHub

From the Dokploy GitHub docs:

  1. In Dokploy, open the Git section and choose GitHub. Pick a personal account (the default) or an organisation.
  2. Click Create Github App, and give it a unique name such as Dokploy-Github-App.
  3. After you're redirected back, click Install. Choose all repositories or only the ones Dokploy should see.
  4. Click Install & Authorize.

What you should see: you're returned to Dokploy's Git section, and your repositories are now available to Applications and Docker Compose services.

Step 4: create a project and an application

According to the interface overview, projects group your services, and each can hold applications, databases and Compose services, split by environment (production, staging and so on). Create a project, then add an Application inside it.

In the application's General tab, set:

  • Provider: GitHub, then choose the repository and the branch.
  • Build path: / for a repo whose app sits at the root.

Step 5: choose a build type

Dokploy's Build Type page lists these options:

Build typeWhen to use it (per the docs)
Nixpacks (default)Detects your stack and builds it. Tune it with NIXPACKS_* variables or a nixpacks.toml. Has a Publish Directory field for static output such as Astro's dist.
Railpack (new)Described as Nixpacks' successor. Supports Node.js, Python, Go, PHP, static files and shell scripts, and has a pinnable version field.
DockerfileYour repo has a Dockerfile. Set Dockerfile Path (required), and optionally Docker Context Path and Docker Build Stage.
BuildpacksHeroku buildpacks (version 24 by default) or Paketo.
StaticServes the repo through an optimised nginx image. The docs say to use port 80 for its domain.

The docs recommend Nixpacks for prototyping. For production, their advice is to follow the "Going Production" guide (see step 9).

With the Dockerfile build type, the Environment tab also gains Build Time Arguments and Build-time Secrets. The docs say build arguments and environment variables persist in the final image, so pass API tokens and passwords as build-time secrets.

Step 6: add environment variables and deploy

Put runtime settings in the Environment tab. For a multiline value such as a private key, the docs say to wrap it in double quotes.

Click Deploy.

What you should see: a new record in the Deployments tab that streams the build log live. Dokploy keeps the last 10 deployments. You can cancel a queued deployment, but the docs say one that's already running can't be cancelled. Once it's up, Logs shows the running container's output and Monitoring shows CPU, memory, disk and network graphs. The graphs only refresh while you're on that page.

Step 7: add a domain with HTTPS

Do this in order. The troubleshooting page is explicit: point the domain at your server's IP before adding it in Dokploy. If you add the domain first, the certificate won't be generated, and you may have to recreate the domain or restart Traefik.

  1. At your DNS provider, create an A record for, say, app.example.com pointing to the VPS.
  2. In the application's Domains tab, add a domain with:
    • Host: app.example.com
    • Container Port: the port your app listens on. The docs' examples are 3000 for Next.js and 8000 for Laravel.
    • HTTPS: on
    • Certificate: letsencrypt

What you should see: for Applications, the Domains page says the change takes effect immediately with no redeploy, because Traefik hot-reloads the file configuration Dokploy writes. Plain HTTP requests get redirected to HTTPS.

Without a domain, use the generated traefik.me hostname to test. It's HTTP only.

Step 8: secure the panel, then firewall the server

  1. Give the Dokploy panel its own domain with HTTPS, using the certificate options on the Domains page.

  2. Only once that works, remove direct IP:port access, as the installation page shows:

    bash
    docker service update --publish-rm "published=3000,target=3000,mode=host" dokploy

    The docs warn that doing this before HTTPS works will lock you out.

  3. Set up the firewall from the hardening guide. Allow only SSH, 80 and 443:

    bash
    sudo apt install -y ufw
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable

    The guide warns that "UFW alone does not protect Docker-published ports", because Docker writes to iptables directly. Its fix is ufw-docker:

    bash
    sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
    sudo chmod +x /usr/local/bin/ufw-docker
    sudo ufw-docker install
    sudo systemctl restart ufw

This page moves the firewall to the end so you don't cut off port 3000 while you still need it. The hardening guide itself lists the firewall under host setup, "before (or right after)" installing Dokploy. Its checklist also covers unattended upgrades, key-only SSH and Fail2Ban. It's worth an afternoon.

Step 9: automatic deploys (and when not to build on the server)

With the GitHub App, auto-deploy needs no setup. The GitHub docs say it's on by default for the branch you selected. Push to main while the app tracks feature, and nothing happens. To run development, staging and production from one repo, the docs suggest three Applications, each on its own branch.

For GitLab, Bitbucket, Gitea or Docker Hub, the Auto Deploy page describes webhooks instead. Toggle Auto Deploy in the General tab, copy the webhook URL from the Deployments tab, and add it in your repository's settings. If the branch doesn't match, you'll get a "Branch Not Match" error.

Builds can freeze a small VPS. The Going Production guide says Nixpacks and buildpack builds use a lot of RAM and CPU, and can take down every app on the server. Its recommended fix is to build the image in CI instead (its example uses GitHub Actions pushing to Docker Hub) and have Dokploy deploy the finished image.

Deploying a Docker Compose app instead

Pick Docker Compose in place of Application to deploy a multi-service stack from a repo or raw YAML. Two documented differences catch people out:

  • Environment variables you set in the UI are written to a .env file, but they are not injected into containers automatically. Add env_file: [.env] to the service, or reference them as ${VAR_NAME}.
  • Domains are set through Traefik labels, so every domain change needs a redeploy.

Troubleshooting (documented issues only)

  • Install fails straight away. Something already holds port 80, 443 or 3000. Stop it and rerun the script.
  • The deploy succeeded, but the domain doesn't load. Check that the domain's container port matches your app's port. Don't also publish the port under Advanced → Ports. And make sure the app listens on 0.0.0.0, not 127.0.0.1, which the docs call common with Vite.
  • Bad Gateway. The same two causes: a port mismatch, or an app bound to localhost. The docs' Vite fix sets preview: { port: 3000, host: true }.
  • No certificate. The DNS record didn't exist when you added the domain. Recreate the domain or restart Traefik.
  • A Compose service or template returns 404 after a domain change. Redeploy it.
  • A Compose domain still doesn't work. Don't map host ports (3000:3000) in the file. List only the container port, and check that any healthcheck you defined actually passes. The docs say a failing healthcheck stops the domain from ever working.
  • Services can't reach each other on a minimal OS (the docs name ZimaOS and other Buildroot images). The kernel lacks IPVS. Reinstall with curl -sSL https://dokploy.com/install.sh | sudo ENDPOINT_MODE=dnsrr sh.

Updating Dokploy

bash
curl -sSL https://dokploy.com/install.sh | sh -s update

What to do next

Sources (12)Show
  1. Dokploy docs: Installation · accessed 2026-09-29
  2. Dokploy docs: GitHub (Git Sources) · accessed 2026-09-29
  3. Dokploy docs: Applications · accessed 2026-09-29
  4. Dokploy docs: Build Type · accessed 2026-09-29
  5. Dokploy docs: Domains · accessed 2026-09-29
  6. Dokploy docs: Auto Deploy · accessed 2026-09-29
  7. Dokploy docs: Docker Compose · accessed 2026-09-29
  8. Dokploy docs: Going Production · accessed 2026-09-29
  9. Dokploy docs: Troubleshooting, Domains & Traefik · accessed 2026-09-29
  10. Dokploy docs: Production Hardening Guide · accessed 2026-09-29
  11. Dokploy docs: Interface Overview · accessed 2026-09-29
  12. GitHub releases API: Dokploy/dokploy (v0.30.7, 2026-09-18), as recorded in the Dokploy profile · accessed 2026-09-29