adze.uk — The Digital Toolshed

Linux Essentials — The Self-Hoster's OS

A practical Linux guide for self-hosters — distributions, essential commands, file permissions, systemd, and troubleshooting.

Why Linux?

Almost every self-hosted tool runs on Linux. Docker runs natively on Linux. NAS operating systems are based on Linux. Understanding the basics makes everything else in this toolshed easier.

You don't need to become a Linux expert. You need about 20 commands and a willingness to read error messages.

Choosing a Distribution

DistributionBest ForPackage ManagerNotes
Debian 12Servers, stabilityaptStable, conservative, excellent default
Ubuntu Server 24.04Servers, broad supportaptBased on Debian, larger community
Alpine LinuxContainers, minimalapkTiny (5MB base), used in many Docker images
Proxmox VEVirtualisationaptDebian-based, VM + container host
TrueNAS ScaleNAS + DockerN/A (appliance)Debian-based, web-managed
UnraidNAS + Docker + VMsSlackwareProprietary, but excellent for home labs
Arch LinuxLearning, cutting-edgepacmanRolling release, not for servers

For self-hosting: Debian 12 or Ubuntu Server 24.04. Both have excellent Docker support, vast documentation, and long-term security updates.

Essential Commands

File Operations

ls -la              # List files with details and hidden files
cd /path/to/dir     # Change directory
pwd                 # Print working directory
cp file1 file2      # Copy
mv file1 file2      # Move/rename
rm file             # Delete (careful — no recycle bin)
rm -rf directory    # Delete directory and contents (very careful)
mkdir -p path/to/dir # Create nested directories
cat file            # Display file contents
less file           # Page through a file (q to quit)
head -20 file       # First 20 lines
tail -20 file       # Last 20 lines
tail -f file        # Follow file in real-time (great for logs)

System Information

uname -a            # System information
hostname            # Machine name
uptime              # How long since last reboot
free -h             # Memory usage
df -h               # Disk space usage
du -sh /path        # Size of a directory
top / htop          # Running processes
lsblk               # Block devices (disks, partitions)
ip addr             # Network interfaces and IP addresses
ss -tlnp            # Listening ports

Package Management (Debian/Ubuntu)

sudo apt update              # Refresh package lists
sudo apt upgrade             # Upgrade installed packages
sudo apt install <package>   # Install a package
sudo apt remove <package>    # Remove a package
sudo apt autoremove          # Remove unused dependencies

File Permissions

Linux permissions use a three-group model: owner, group, others.

-rw-r--r-- 1 user group 4096 Mar 15 README.md
 │││ │││ │││
 │││ │││ └── Others: read only
 │││ └──── Group: read only
 └────── Owner: read + write

Common permission commands:

chmod 600 .env          # Owner read/write only (secrets)
chmod 644 config.yml    # Owner read/write, others read
chmod 755 script.sh     # Owner all, others read/execute
chmod -R 755 /data      # Recursive
chown user:group file   # Change ownership
chown -R 1000:1000 /data # Common for Docker volumes

Systemd: Managing Services

Most modern Linux distributions use systemd to manage services.

sudo systemctl start docker      # Start a service
sudo systemctl stop docker       # Stop a service
sudo systemctl restart docker    # Restart
sudo systemctl enable docker     # Start on boot
sudo systemctl disable docker    # Don't start on boot
sudo systemctl status docker     # Check status
journalctl -u docker -f          # Follow service logs

Creating a Custom Service

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/run.sh
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now myapp

SSH: Remote Access

ssh user@server-ip          # Connect
ssh -p 2222 user@server-ip  # Non-standard port
scp file user@server:/path  # Copy file to server
scp user@server:/path file  # Copy file from server
rsync -avz /local/ user@server:/remote/  # Sync directories

SSH Config File

Save typing with ~/.ssh/config:

Host mynas
    HostName 192.168.1.100
    User admin
    Port 2222
    IdentityFile ~/.ssh/id_ed25519

Host docker-server
    HostName 192.168.1.101
    User deploy

Now just type ssh mynas instead of the full command.

Troubleshooting

Read the Logs

# System logs
journalctl -xe                    # Recent errors
journalctl --since "1 hour ago"   # Last hour

# Docker container logs
docker logs container-name
docker logs -f --tail 50 container-name  # Follow last 50 lines

# Application-specific
cat /var/log/syslog | grep error

Check Connectivity

ping 8.8.8.8                    # Can we reach the internet?
ping google.com                 # Does DNS work?
curl -I https://example.com     # Is HTTP working?
dig yourdomain.com              # DNS resolution check
traceroute 8.8.8.8              # Where does the connection break?
ss -tlnp                        # What's listening on which ports?

Check Resources

htop                            # Interactive process viewer
df -h                           # Disk space
free -h                         # Memory
docker stats                    # Container resource usage
iostat                          # Disk I/O

The command line is your most powerful tool. Every error message is a clue. Read them, search for them, and learn from them.

Product links may include affiliate partnerships — see our affiliate disclosure for details.