Quick Answer: Get a VPS ($3-5/month), SSH in, create a non-root user, set up SSH keys, enable firewall, install Docker, set up Nginx reverse proxy with Let's Encrypt SSL. Then deploy any app with
docker compose up -d. This guide walks through every step.
Need a VPS? Get started with DigitalOcean ($200 free credit for 60 days) or Vultr , or RackNerd ($100 free credit).
Self-hosting means running your own services on your own server instead of relying on third-party companies. Your own VPN, your own cloud storage, your own website, your own email — you control the data, you control the uptime, you control the cost.
This guide takes you from zero to a fully configured, secured, production-ready server. Every section builds on the previous one, and by the end, you will have the foundation to host anything.
Part 1: Get a Server
Choosing a VPS Provider
A VPS (Virtual Private Server) is a virtual machine in a data center that you rent by the month. You get root access, a public IP, and full control.
| Provider | Starting Price | Strengths |
|---|---|---|
| DigitalOcean | $4/month | Beginner-friendly UI, great docs |
| Vultr , or RackNerd | $3.50/month | Budget-friendly, many locations |
| Hetzner | $3.29/month | Best value in Europe |
| Linode (Akamai) | $5/month | Reliable, good support |
| Oracle Cloud | Free tier | 4 ARM cores free forever (limited) |
Recommended Starting Specs
- 1 vCPU, 1 GB RAM, 25 GB SSD — enough for 2-3 lightweight apps
- Ubuntu 22.04 LTS or Debian 12 — most tutorials target these
- Location — pick the closest to your users
Create and Connect
After creating the VPS, you get an IP address and root password.
ssh root@YOUR_SERVER_IP
First time? Type yes when asked about the fingerprint.
For the full initial setup walkthrough, see our VPS Setup Guide.
Part 2: Secure Your Server
An unsecured server gets compromised within hours. Do these before anything else.
Create a Non-Root User
adduser sam
usermod -aG sudo sam
Set Up SSH Keys
On your local machine:
ssh-keygen -t ed25519
ssh-copy-id sam@YOUR_SERVER_IP
Now disable password login:
sudo nano /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
sudo systemctl restart sshd
Full guide: How to Set Up SSH Keys
Enable Firewall
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
Full guide: UFW Firewall Cheat Sheet
Install Fail2ban
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
Blocks brute-force attacks automatically. Full guide: Fail2ban Setup
Enable Automatic Security Updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure unattended-upgrades
For a comprehensive security checklist, see our Server Hardening Guide and SSH Hardening Guide.
Part 3: Install Docker
Docker lets you run applications in isolated containers. Instead of installing software directly on your server (and dealing with dependency conflicts), you run each app in its own container with everything it needs bundled in.
Install
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker sam
Log out and back in for the group change to take effect.
Verify
docker --version
docker compose version
docker run hello-world
Essential Docker Commands
docker ps # Running containers
docker ps -a # All containers
docker logs container-name # View logs
docker exec -it container-name bash # Shell into container
docker stop container-name # Stop
docker rm container-name # Remove
docker system prune -a # WARNING: removes ALL unused images and containers — re-downloads needed
Full reference: Docker Cheat Sheet
Part 4: Set Up a Reverse Proxy (Nginx)
A reverse proxy sits in front of all your apps and handles:
- SSL certificates (HTTPS) — one place for all certs
- Domain routing — app1.yourdomain.com goes to container A, app2.yourdomain.com goes to container B
- Security — rate limiting, headers, access control
Install Nginx
sudo apt install nginx -y
sudo systemctl enable --now nginx
Basic Config
Create /etc/nginx/sites-available/myapp:
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Full guide: Nginx Reverse Proxy Guide
Part 5: Get SSL Certificates (HTTPS)
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d app.yourdomain.com
Certbot automatically:
- Gets a free Let's Encrypt certificate
- Configures Nginx for HTTPS
- Sets up auto-renewal
That is it. Your app is now at https://app.yourdomain.com.
Full guide: SSL/TLS Explained
Part 6: Deploy Applications
Now your server is secured, Docker is running, Nginx handles routing, and SSL is active. Deploy anything.
Example: Deploy a Web App
Create compose.yml:
services:
app:
image: your-app-image
restart: unless-stopped
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://db:5432/myapp
depends_on:
- db
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
- POSTGRES_PASSWORD=secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
docker compose up -d
Add an Nginx config pointing app.yourdomain.com to localhost:3000, run certbot, and it is live.
More examples: Docker Compose Examples
Popular Self-Hosted Apps
| App | What It Does | Docker Image |
|---|---|---|
| Nextcloud | Cloud storage (like Google Drive) | nextcloud |
| Vaultwarden | Password manager (Bitwarden compatible) | vaultwarden/server |
| Gitea | Git hosting (like GitHub) | gitea/gitea |
| Uptime Kuma | Uptime monitoring | louislam/uptime-kuma |
| Portainer | Docker management UI | portainer/portainer-ce |
| Pi-hole | Network-wide ad blocker | pihole/pihole |
| Jellyfin | Media server (like Plex) | jellyfin/jellyfin |
| n8n | Workflow automation | n8nio/n8n |
| Grafana + Prometheus | Monitoring and dashboards | grafana/grafana |
Each of these is a single docker compose up -d away from running.
Part 7: Set Up a VPN
Run your own VPN so your internet traffic goes through your server. No commercial VPN needed.
WireGuard (Recommended)
The fastest, simplest VPN protocol.
Easy method with SamNet-WG:
curl -sSL https://raw.githubusercontent.com/SamNet-dev/wg-orchestrator/main/install.sh | sudo bash
SamNet-WG (wg-orchestrator) gives you a full management TUI, web dashboard, QR codes for mobile, per-peer bandwidth tracking, and zero-touch setup.
sudo samnet # Open the TUI
# Peers → Add Peer → Scan QR on your phone
Full guide: WireGuard Setup Guide
For Censorship Bypass
If you are in a country with heavy internet censorship (Iran, China, Russia), standard VPN protocols get blocked. Use tools designed to bypass Deep Packet Inspection:
- paqctl — Paqet (KCP over raw TCP) and GFW-Knocker (violated TCP + QUIC) — specifically designed to defeat censorship firewalls
- VLESS + Reality — via 3X-UI panel — makes traffic look like a real TLS connection to a legitimate website
- MTProxyMax — Telegram-specific proxy with FakeTLS obfuscation
More: Every Way to Bypass Internet Censorship
Part 8: Domain and DNS
Get a Domain
Buy a domain from Namecheap, Cloudflare Registrar, or Porkbun. Cost: $8-15/year.
Point DNS to Your Server
Create an A record pointing your domain to your server's IP:
Type: A
Name: @ (or subdomain)
Value: YOUR_SERVER_IP
TTL: Auto
Use Cloudflare (Recommended)
Cloudflare adds a free CDN, DDoS protection, and SSL in front of your server:
- Add your domain to Cloudflare (free plan)
- Change nameservers at your registrar
- Set SSL mode to Full (Strict)
- Enable "Always Use HTTPS"
Full guide: Cloudflare Setup Guide
Part 9: Backups
The most important thing most self-hosters forget.
Automated Database Backups
# Create backup script
cat > /opt/backup.sh << 'EOF'
#!/bin/bash
DATE=$(date +%Y%m%d)
docker exec postgres pg_dumpall -U postgres | gzip > /backups/db-$DATE.sql.gz
find /backups -name "*.sql.gz" -mtime +30 -delete
EOF
chmod +x /opt/backup.sh
# Run daily at 2 AM
(crontab -l; echo "0 2 * * * /opt/backup.sh") | crontab -
Backup Docker Volumes
# Stop containers, backup volumes, restart
docker compose stop
tar czf /backups/volumes-$(date +%Y%m%d).tar.gz /var/lib/docker/volumes/
docker compose start
Off-Site Backup
Always keep a copy outside your server:
# Sync to a backup server
rsync -avz /backups/ backup-server:/remote-backups/
# Or use rclone for cloud storage (S3, B2, etc.)
rclone sync /backups remote:bucket-name/backups/
Full guide: Crontab Tutorial
Part 10: Monitoring
Know when something breaks before your users tell you.
Simple Monitoring: Uptime Kuma
services:
uptime-kuma:
image: louislam/uptime-kuma
restart: unless-stopped
ports:
- "3001:3001"
volumes:
- uptime-data:/app/data
volumes:
uptime-data:
Web-based dashboard that pings your services and alerts you via email, Telegram, Slack, or Discord when something goes down.
Server Monitoring: htop + journalctl
# Real-time resource usage
htop
# Service logs
journalctl -u nginx -f
journalctl -u docker -f
# Disk usage
df -h
# Check for issues
systemctl --failed
Full guide: Linux Log Files Explained
Part 11: Maintenance Routine
Weekly
- Check
df -h— make sure disk isn't full - Check
docker system df— prune if needed - Review
journalctl --since "1 week ago" -p err— any errors? - Verify backups exist and are recent
Monthly
sudo apt update && sudo apt upgrade— update system packagesdocker compose pull && docker compose up -d— update containers- Review Fail2ban logs —
sudo fail2ban-client status - Test restoring a backup (actually try it)
After Any Change
nginx -t— test config before reloading- Check app logs:
docker compose logs -f - Verify SSL cert:
certbot certificates
The Complete Stack (Summary)
┌──────────────────────────────────┐
│ Cloudflare CDN │ Free DDoS protection + caching
├──────────────────────────────────┤
│ Nginx + SSL │ Reverse proxy + Let's Encrypt
├──────────────────────────────────┤
│ Docker Containers │ Your apps in isolated containers
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │App 1│ │App 2│ │ DB │ │
│ └─────┘ └─────┘ └─────┘ │
├──────────────────────────────────┤
│ Ubuntu 22.04 LTS │ Base OS
│ UFW + Fail2ban + SSH keys │ Security
├──────────────────────────────────┤
│ VPS ($3-5/month) │ DigitalOcean / Vultr / Hetzner
└──────────────────────────────────┘
Related Guides on SamNet
Setup:
- VPS Setup from Scratch
- Docker Cheat Sheet
- Docker Compose Examples
- Nginx Reverse Proxy
- Nginx Cheat Sheet
- Cloudflare Setup
Security:
- Server Hardening Guide
- SSH Keys Setup
- SSH Hardening
- Fail2ban Setup
- UFW Cheat Sheet
- iptables Cheat Sheet
- SSL/TLS Explained
VPN & Proxy:
Tools: