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.
Choose Shared Resources > Cost-Optimized. The CX23 server (2 vCPU, 4GB RAM) is perfect at just β¬2.99/month.
Select a location close to your users and Ubuntu 24.04 as the operating system.
Add your SSH public key:
# On macOS
pbcopy < ~/.ssh/id_ed25519.pub
# On Linux
cat ~/.ssh/id_ed25519.pub
Give your server a name and click Create & Buy now. Once created, copy the IP address and connect:
ssh root@YOUR_SERVER_IP
Step 1: Update Your Server
sudo apt-get update
sudo apt-get upgrade -y
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
Verify with sudo ufw status verbose.
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
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
Install Docker Engine:
sudo apt-get install docker-ce docker-ce-cli \
containerd.io docker-buildx-plugin docker-compose-plugin -y
Verify with sudo docker run hello-world.
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
Edit the Caddyfile:
sudo nano /etc/caddy/Caddyfile
Replace contents with:
yourdomain.com {
reverse_proxy localhost:3000
}
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
Add the following:
services:
docuseal:
image: docuseal/docuseal:2.2.9
restart: always
ports:
- "3000:3000"
volumes:
- docuseal_data:/data
volumes:
docuseal_data:
Deploy:
sudo docker compose up -d
Step 6: Access Your DocuSeal Instance
Visit your domain in any web browser. Follow the setup steps to create your admin account.
π Congratulations! You now have your own self-hosted DocuSeal instance!
Optional Configurations
Restart: 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:
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
Updating DocuSeal
Since we're using a specific version tag (2.2.9):
compose.yml
cd ~/docuseal
sudo docker compose pull
sudo docker compose up -d
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
/datavolume
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)
TIL there is compliance standards for electronic signing lol
thank you for the detailed tutorial!!