Skip to main content

Self-Hosting Security: 20 Things to Fix 2026

·OSSAlt Team
securityself-hostinghardeningdockerguide
Share:

Self-Hosting Security Checklist: 20 Things to Lock Down

Self-hosting gives you control, but you're also responsible for security. Here are the 20 things you need to lock down before exposing any self-hosted service to the internet.

Server Access (Items 1-5)

1. ✅ Disable Root Login

# /etc/ssh/sshd_config
PermitRootLogin no
sudo systemctl restart sshd

Create a regular user and use sudo:

adduser deployer
usermod -aG sudo deployer

2. ✅ SSH Key-Only Authentication

# On your local machine
ssh-keygen -t ed25519 -C "your@email.com"
ssh-copy-id deployer@your-server

# Then disable password auth
# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes

3. ✅ Change SSH Port

# /etc/ssh/sshd_config
Port 2222  # Pick any non-standard port

Reduces automated brute force attempts by 99%.

4. ✅ Set Up Fail2Ban

sudo apt install -y fail2ban

# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222
filter = sshd
maxretry = 3
bantime = 3600
findtime = 600
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

5. ✅ Configure UFW Firewall

sudo ufw default deny incoming
sudo ufw default allow outgoing

# SSH (your custom port)
sudo ufw allow 2222/tcp

# HTTP/HTTPS (for Caddy)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable
sudo ufw enable
sudo ufw status

Never expose database ports (5432, 3306, 6379) to the internet.

Docker Security (Items 6-10)

6. ✅ Don't Run Containers as Root

# docker-compose.yml
services:
  myapp:
    user: "1000:1000"  # Non-root user

Or in Dockerfile:

RUN adduser -D appuser
USER appuser

7. ✅ Limit Container Resources

services:
  myapp:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          memory: 512M

Prevents a single container from consuming all server resources.

8. ✅ Use Read-Only File Systems Where Possible

services:
  myapp:
    read_only: true
    tmpfs:
      - /tmp
      - /var/tmp
    volumes:
      - app_data:/data  # Only mount what's needed

9. ✅ Don't Bind to 0.0.0.0 for Internal Services

# BAD — exposed to internet
ports:
  - "5432:5432"

# GOOD — only accessible from localhost (for reverse proxy)
ports:
  - "127.0.0.1:5432:5432"

# BEST — no port binding, use Docker networks
# (services communicate via Docker internal DNS)

10. ✅ Use Docker Networks for Service Isolation

services:
  app:
    networks:
      - frontend
      - backend

  db:
    networks:
      - backend  # Not accessible from frontend network

networks:
  frontend:
  backend:
    internal: true  # No external access

Web Security (Items 11-14)

11. ✅ Force HTTPS Everywhere

Caddy does this automatically. For other reverse proxies:

# Nginx
server {
    listen 80;
    return 301 https://$host$request_uri;
}

12. ✅ Security Headers

Caddy adds basic headers. For stricter security:

# /etc/caddy/Caddyfile
(security_headers) {
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        X-XSS-Protection "1; mode=block"
        Referrer-Policy strict-origin-when-cross-origin
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
    }
}

myapp.yourdomain.com {
    import security_headers
    reverse_proxy localhost:3000
}

13. ✅ Rate Limiting

# Caddy rate limiting
myapp.yourdomain.com {
    rate_limit {
        zone dynamic_zone {
            key {remote_host}
            events 100
            window 1m
        }
    }
    reverse_proxy localhost:3000
}

14. ✅ Restrict Admin Panels by IP

# Only allow admin access from specific IPs
admin.yourdomain.com {
    @blocked not remote_ip 1.2.3.4 5.6.7.8
    respond @blocked "Forbidden" 403

    reverse_proxy localhost:3000
}

Application Security (Items 15-17)

15. ✅ Use Strong, Unique Passwords for Every Service

Generate strong passwords:

openssl rand -hex 32  # Database passwords
openssl rand -hex 64  # Secret keys, encryption keys

Never reuse passwords between services. Store them in Vaultwarden.

16. ✅ Enable 2FA on All Admin Accounts

Tool2FA Support
VaultwardenTOTP, WebAuthn, YubiKey
Uptime KumaTOTP
GiteaTOTP, WebAuthn
NextcloudTOTP, WebAuthn
KeycloakTOTP, WebAuthn
OutlineVia Keycloak SSO

17. ✅ Disable Sign-Ups After Setup

Most tools let you disable public registration:

# Vaultwarden
SIGNUPS_ALLOWED=false

# n8n
N8N_USER_MANAGEMENT_DISABLED=true

# Gitea
DISABLE_REGISTRATION=true

# Grafana
GF_USERS_ALLOW_SIGN_UP=false

Invite users through admin panel instead.

Monitoring & Maintenance (Items 18-20)

18. ✅ Automatic Security Updates

# Ubuntu/Debian — enable unattended upgrades
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

# Verify it's enabled
cat /etc/apt/apt.conf.d/20auto-upgrades

19. ✅ Monitor for Intrusions

Check auth logs regularly:

# Failed SSH attempts
journalctl -u sshd --since "24 hours ago" | grep "Failed"

# Fail2ban status
sudo fail2ban-client status sshd

Set up alerts:

  • Monitor with Uptime Kuma for service availability
  • Set up Fail2Ban email notifications
  • Monitor disk usage (prevent denial of service)

20. ✅ Keep Docker Images Updated

# Check for updates
docker compose pull

# Update all services
docker compose up -d

# Clean up old images
docker image prune -f

Schedule monthly updates:

# First Sunday of each month at 4 AM
0 4 1-7 * 0 cd /opt/mystack && docker compose pull && docker compose up -d

Security Audit Script

Run this to check your server's security posture:

#!/bin/bash
# security-check.sh

echo "=== Security Audit ==="

# SSH config
echo -n "Root login disabled: "
grep -q "^PermitRootLogin no" /etc/ssh/sshd_config && echo "✅" || echo "❌"

echo -n "Password auth disabled: "
grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config && echo "✅" || echo "❌"

# Firewall
echo -n "UFW active: "
sudo ufw status | grep -q "active" && echo "✅" || echo "❌"

# Fail2Ban
echo -n "Fail2Ban running: "
systemctl is-active fail2ban > /dev/null && echo "✅" || echo "❌"

# Docker
echo -n "Exposed ports (should be minimal): "
docker ps --format '{{.Ports}}' | grep "0.0.0.0" | wc -l

# Updates
echo -n "Unattended upgrades: "
dpkg -l | grep -q unattended-upgrades && echo "✅" || echo "❌"

# SSL
echo -n "SSL certificates valid: "
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null && echo "✅" || echo "❌"

echo "=== Done ==="

Common Mistakes

MistakeRiskFix
Exposing database ports publiclyDirect database accessUse Docker networks, bind to 127.0.0.1
Default passwordsUnauthorized accessGenerate unique passwords for everything
No firewallAll ports openEnable UFW with deny-by-default
Running as rootFull server compromise if app is exploitedCreate non-root users
No backupsTotal data lossImplement 3-2-1 backup strategy
No monitoringAttacks go unnoticedSet up Uptime Kuma + Fail2Ban alerts
Outdated softwareKnown vulnerabilitiesEnable automatic updates
HTTP without redirectData interceptionForce HTTPS via reverse proxy

Find secure, self-hostable tools on OSSAlt — security features, licensing, and deployment guides side by side.

Security Gains Only Count If You Reduce Hidden Trust

Self-hosting can improve security, but only when it reduces trust assumptions instead of moving them around. Bringing a service in-house is not automatically safer if the result is one unpatched VPS, a wide-open admin panel, and no log review. The real gain comes from shrinking who can read the data, who can change configuration, and how many external processors sit between your users and their information. That is why privacy and security articles need to focus on control boundaries. Ask which credentials unlock the system, where audit trails live, and how incident response changes when the software is on infrastructure you administer directly.

Useful adjacent tools reinforce that boundary model. Vaultwarden guide matters because weak shared secrets are still one of the fastest ways to negate every other security measure. CrowdSec guide belongs in the conversation because exposure without ban rules or log-based detection is just optimism. Authelia guide is the missing layer when teams have multiple internal apps but no unified MFA and policy engine. None of those tools replaces process, but together they make a small-team security posture far more coherent.

A Defensible Security Baseline for Small Teams

For most organizations, the defensible baseline is surprisingly attainable. Put admin interfaces behind SSO or at least MFA, remove public exposure where a VPN or access gateway is enough, enforce automatic updates on the host OS, send logs somewhere durable, and test restores regularly. Then document one incident playbook that covers credential compromise, failed upgrades, and suspicious traffic spikes. That playbook does not have to be enterprise-grade to be valuable. It only has to exist before the bad day arrives.

The practical advantage of open source here is inspectability and composability. You can audit default settings, place reverse proxies and WAF rules in front of services, and export metrics into your own monitoring stack. More importantly, you can keep sensitive workloads off third-party dashboards entirely. That combination of transparency and constrained trust is the strongest argument for self-hosted security-minded systems, and it is more persuasive than any simplistic claim that open source is inherently safer.

Decision Framework for Picking the Right Fit

The simplest way to make a durable decision is to score the options against the constraints you cannot change: who will operate the system, how often it will be upgraded, whether the workload is business critical, and what kinds of failures are tolerable. That sounds obvious, but many migrations still start with screenshots and end with painful surprises around permissions, backup windows, or missing audit trails. A short written scorecard forces the trade-offs into the open. It also keeps the project grounded when stakeholders ask for new requirements halfway through rollout.

One more practical rule helps: optimize for reversibility. A good self-hosted choice preserves export paths, avoids proprietary lock-in inside the replacement itself, and can be documented well enough that another engineer could take over without archaeology. The teams that get the most value from self-hosting are not necessarily the teams with the fanciest infrastructure. They are the teams that keep their systems legible, replaceable, and easy to reason about.

Security Gains Only Count If You Reduce Hidden Trust

Self-hosting can improve security, but only when it reduces trust assumptions instead of moving them around. Bringing a service in-house is not automatically safer if the result is one unpatched VPS, a wide-open admin panel, and no log review. The real gain comes from shrinking who can read the data, who can change configuration, and how many external processors sit between your users and their information. That is why privacy and security articles need to focus on control boundaries. Ask which credentials unlock the system, where audit trails live, and how incident response changes when the software is on infrastructure you administer directly.

Useful adjacent tools reinforce that boundary model. Vaultwarden guide matters because weak shared secrets are still one of the fastest ways to negate every other security measure. CrowdSec guide belongs in the conversation because exposure without ban rules or log-based detection is just optimism. Authelia guide is the missing layer when teams have multiple internal apps but no unified MFA and policy engine. None of those tools replaces process, but together they make a small-team security posture far more coherent.

A Defensible Security Baseline for Small Teams

For most organizations, the defensible baseline is surprisingly attainable. Put admin interfaces behind SSO or at least MFA, remove public exposure where a VPN or access gateway is enough, enforce automatic updates on the host OS, send logs somewhere durable, and test restores regularly. Then document one incident playbook that covers credential compromise, failed upgrades, and suspicious traffic spikes. That playbook does not have to be enterprise-grade to be valuable. It only has to exist before the bad day arrives.

The practical advantage of open source here is inspectability and composability. You can audit default settings, place reverse proxies and WAF rules in front of services, and export metrics into your own monitoring stack. More importantly, you can keep sensitive workloads off third-party dashboards entirely. That combination of transparency and constrained trust is the strongest argument for self-hosted security-minded systems, and it is more persuasive than any simplistic claim that open source is inherently safer.

Security Gains Only Count If You Reduce Hidden Trust

Self-hosting can improve security, but only when it reduces trust assumptions instead of moving them around. Bringing a service in-house is not automatically safer if the result is one unpatched VPS, a wide-open admin panel, and no log review. The real gain comes from shrinking who can read the data, who can change configuration, and how many external processors sit between your users and their information. That is why privacy and security articles need to focus on control boundaries. Ask which credentials unlock the system, where audit trails live, and how incident response changes when the software is on infrastructure you administer directly.

Useful adjacent tools reinforce that boundary model. Vaultwarden guide matters because weak shared secrets are still one of the fastest ways to negate every other security measure. CrowdSec guide belongs in the conversation because exposure without ban rules or log-based detection is just optimism. Authelia guide is the missing layer when teams have multiple internal apps but no unified MFA and policy engine. None of those tools replaces process, but together they make a small-team security posture far more coherent.

A Defensible Security Baseline for Small Teams

For most organizations, the defensible baseline is surprisingly attainable. Put admin interfaces behind SSO or at least MFA, remove public exposure where a VPN or access gateway is enough, enforce automatic updates on the host OS, send logs somewhere durable, and test restores regularly. Then document one incident playbook that covers credential compromise, failed upgrades, and suspicious traffic spikes. That playbook does not have to be enterprise-grade to be valuable. It only has to exist before the bad day arrives.

The practical advantage of open source here is inspectability and composability. You can audit default settings, place reverse proxies and WAF rules in front of services, and export metrics into your own monitoring stack. More importantly, you can keep sensitive workloads off third-party dashboards entirely. That combination of transparency and constrained trust is the strongest argument for self-hosted security-minded systems, and it is more persuasive than any simplistic claim that open source is inherently safer.

Incident Readiness Notes

Incident readiness starts with fast credential rotation, immutable backups, and central logging. If those three controls are weak, every other security improvement becomes harder to rely on under pressure.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.