DEV Community

Cover image for Self-hosting DocuSeal on a Hetzner Ubuntu Server
atakanozt
atakanozt

Posted on • Originally published at sliplane.io

Self-hosting DocuSeal on a Hetzner Ubuntu Server

Want to sign documents using DocuSeal but prefer to fully control your infrastructure? By self-hosting DocuSeal on a Linux Ubuntu server, you can cut down costs, keep your sensitive documents private, and avoid per-signature fees!

Looking for something simpler? Deploy in 25 seconds

Prerequisites

Before we start, make sure you have:

  • A Hetzner account (or any other cloud provider)
  • Basic SSH experience
  • An SSH key pair on your local machine

Step 0: Create a Server on Hetzner

Log into your Hetzner Cloud Console and click Create Resource.

Hetzner Cloud Console showing Create Resource button

Choose Shared Resources > Cost-Optimized. The CX23 server (2 vCPU, 4GB RAM) is perfect at just €2.99/month.

Selecting CX23 server type in Hetzner

Select a location close to your users and Ubuntu 24.04 as the operating system.

Selecting Ubuntu 24.04 and server location

Add your SSH public key:

# On macOS
pbcopy < ~/.ssh/id_ed25519.pub

# On Linux
cat ~/.ssh/id_ed25519.pub
Enter fullscreen mode Exit fullscreen mode

Copying SSH public key from terminal

Adding SSH key in Hetzner console

Give your server a name and click Create & Buy now. Once created, copy the IP address and connect:

Naming server and clicking Create and Buy now

ssh root@YOUR_SERVER_IP
Enter fullscreen mode Exit fullscreen mode

Server IP address in Hetzner dashboard

Successful SSH connection to Ubuntu server

Step 1: Update Your Server

sudo apt-get update
sudo apt-get upgrade -y
Enter fullscreen mode Exit fullscreen mode

Terminal output showing apt-get upgrade completed

Step 2: Install and Configure UFW Firewall

sudo apt install ufw -y
sudo ufw allow 22    # SSH
sudo ufw allow 80    # HTTP
sudo ufw allow 443   # HTTPS
sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

Verify with sudo ufw status verbose.

UFW firewall status showing ports 22, 80, and 443 open

Note: Docker can sometimes ignore UFW rules. See this guide for extra settings.

Step 3: Docker Installation

Setup dependencies and Docker's GPG key:

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Enter fullscreen mode Exit fullscreen mode

Add Docker repository:

echo \
  "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
Enter fullscreen mode Exit fullscreen mode

Install Docker Engine:

sudo apt-get install docker-ce docker-ce-cli \
containerd.io docker-buildx-plugin docker-compose-plugin -y
Enter fullscreen mode Exit fullscreen mode

Verify with sudo docker run hello-world.

Docker hello-world container running successfully

Step 4: Installing Caddy for Automatic HTTPS

Caddy handles SSL certificates automatically from Let's Encrypt.

Important: Point your domain's A record (IPv4) and AAAA record (IPv6) to your server's IP before this step.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install caddy -y
Enter fullscreen mode Exit fullscreen mode

Edit the Caddyfile:

sudo nano /etc/caddy/Caddyfile
Enter fullscreen mode Exit fullscreen mode

Replace contents with:

yourdomain.com {
    reverse_proxy localhost:3000
}
Enter fullscreen mode Exit fullscreen mode

Caddyfile configuration with reverse proxy

Restart Caddy: sudo systemctl restart caddy

Step 5: Running DocuSeal with Docker Compose

Create a directory and compose file:

mkdir ~/docuseal
cd ~/docuseal
nano compose.yml
Enter fullscreen mode Exit fullscreen mode

Docker Compose file for DocuSeal

Add the following:

services:
  docuseal:
    image: docuseal/docuseal:2.2.9
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - docuseal_data:/data

volumes:
  docuseal_data:
Enter fullscreen mode Exit fullscreen mode

Deploy:

sudo docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Step 6: Access Your DocuSeal Instance

Visit your domain in any web browser. Follow the setup steps to create your admin account.

DocuSeal initial setup page to create admin account

πŸŽ‰ Congratulations! You now have your own self-hosted DocuSeal instance!

DocuSeal dashboard ready to use

Optional Configurations

Using PostgreSQL Instead of SQLite
For production environments, update your compose.yml:
services:
  docuseal:
    image: docuseal/docuseal:2.2.9
    restart: always
    depends_on:
      - postgres
    ports:
      - "3000:3000"
    volumes:
      - docuseal_data:/data
    environment:
      - DATABASE_URL=postgres://docuseal:your_secure_password@postgres:5432/docuseal

  postgres:
    image: postgres:16
    restart: always
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=docuseal
      - POSTGRES_PASSWORD=your_secure_password
      - POSTGRES_DB=docuseal

volumes:
  docuseal_data:
  postgres_data:
Enter fullscreen mode Exit fullscreen mode

Restart: sudo docker compose down && sudo docker compose up -d


Configuring Email Notifications
Add SMTP settings to your compose.yml:
environment:
  - SMTP_ADDRESS=smtp.example.com
  - SMTP_PORT=587
  - SMTP_USERNAME=your-email@example.com
  - SMTP_PASSWORD=your-password
  - SMTP_DOMAIN=your-domain.com
Enter fullscreen mode Exit fullscreen mode

Updating DocuSeal
Since we're using a specific version tag (2.2.9):
  1. Check for new versions on DocuSeal's DockerHub
  2. Update the image tag in compose.yml
  3. Run:
cd ~/docuseal
sudo docker compose pull
sudo docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Security Recommendations

  • Regularly apply updates and security patches
  • Set strong passwords and control user access
  • Monitor server logs for suspicious activity
  • Install Fail2ban for extra security
  • Keep Docker images updated
  • Set up regular backups of your /data volume

Cost Comparison with SaaS Alternatives

Service Monthly Cost Documents/Month Custom Branding
DocuSign €45-€65+ Limited Paid plans only
HelloSign €25-€65+ Limited Paid plans only
PandaDoc €35-€65+ Limited Paid plans only
Hetzner (self-hosted) ~€3-5 Unlimited Free

Comparison with Managed Hosting

Provider vCPU RAM Monthly Cost
Render.com 1 2 GB ~€35-€45
Fly.io 2 2 GB ~€20-€25
Railway 2 2 GB ~€15-€66*
sliplane.io 2 2 GB ~€9/month flat

*Railway charges for actual usage.

With self-hosting on Hetzner, you get similar specs for ~€3/month, but you handle all setup and maintenance.

See the full tutorial with screenshots on Sliplane.io


If managing your own server is too much, check out how easy it is to deploy DocuSeal on Sliplane in just 25 seconds!

Happy self-hosting! πŸš€

Top comments (2)

Collapse
 
code42cate profile image
Jonas Scholz

TIL there is compliance standards for electronic signing lol

Collapse
 
yulei-chen profile image
Yulei Chen

thank you for the detailed tutorial!!