Add a Linux tips section and move Docker stacks to /srv/docker

This commit is contained in:
Djeex
2026-09-05 12:28:05 +02:00
parent 11d6c275c8
commit 142788d740
40 changed files with 894 additions and 330 deletions
@@ -0,0 +1,2 @@
title: Linux tips for dummies
icon: i-lucide-terminal
@@ -0,0 +1,255 @@
---
title: Command line basics
description: Understand how a Linux command is built, learn the essential terminal commands, what their names mean, and get a cheat sheet to keep at hand.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
A server has no desktop, no icons and no mouse. Everything happens in a terminal, and that black window with a blinking cursor is the single thing that puts people off self-hosting. It shouldn't: the terminal is just a conversation. You type one line, the machine does exactly that and answers. Nothing more magic than a search bar, except it does far more and never hides an option behind three menus.
The good news is that you don't need to know a hundred commands. Ten of them cover almost everything you'll do on a home server, and they all follow the same pattern. Learn the pattern first, and every command you meet later becomes readable, even the ones you've never seen.
## How a command is built
Every command line, without exception, is the same sentence: **what to run**, **how to run it**, **what to run it on**.
```text [Anatomy of a command]
sudo apt install -y nano
│ │ │ │ └─ argument: what the command works on
│ │ │ └──── option: changes how it behaves
│ │ └──────────── subcommand: what the program should do
│ └──────────────── the program you're running
└───────────────────── run it with administrator rights
```
Read out loud, that line says "as an administrator, ask the package manager to install the nano package, and don't ask me to confirm". Spaces are what separate the pieces, which is why a folder named `My Backups` has to be quoted (`cd "My Backups"`) or the shell reads it as two different things.
### Options, short and long
Options change how a command behaves. They come in two flavours, and most commands accept both:
- **Short**, a single dash and a single letter: `ls -a`. They can be stacked, so `ls -l -a -h` is usually written `ls -lah`.
- **Long**, two dashes and a whole word: `ls --all`. Longer to type, but you can still tell what it does six months later, which is why they're the better choice in a script.
Some options expect a value right after them: `ssh-keygen -t ed25519` (`-t` for type), `rsync --exclude @eaDir`. And case matters, always. In `ls`, `-r` reverses the sort order while `-R` walks into subfolders. Two different things, one letter apart.
### Arguments and paths
The argument is the target: a file, a folder, a package name, an address. Many commands accept several at once, separated by spaces, which is what makes the terminal fast: `rm file1.txt file2.txt file3.txt` deletes three files in one go.
When the target is a place on the disk, you write it as a path, and there are a few shortcuts worth knowing:
| Path | Means |
| --- | --- |
| `/` | the root of the whole system, everything lives under it |
| `~` | your own home folder, `/home/username` |
| `.` | the folder you're currently in |
| `..` | the folder just above |
| `/var/log` | an **absolute** path, same result from anywhere |
| `logs/today` | a **relative** path, understood from where you currently stand |
Which folder holds what is a subject of its own, covered in [folders and partitions](/general/linux/filesystem).
The prompt itself tells you where you are: in `username@serveex:~/docker$`, you're logged in as `username` on the machine named `serveex`, inside the `docker` folder of your home. That final `$` means a normal user. If it ever shows `#`, you're root and every typo counts double.
### Getting help
Two habits make you independent from tutorials. `command --help` prints a quick summary of every option, and `man command` opens the full manual (`man` for *manual*), which you leave by pressing :kbd{value="Q"}.
::tip{icon=""}
✨ __Tip:__ three keyboard habits that change everything: :kbd{value="Tab"} completes the file or folder name you started typing, so you almost never type a full path; the :kbd{value="Up"} arrow brings back your previous commands, which saves retyping a long line for one character; and :kbd{value="Ctrl"} + :kbd{value="C"} stops whatever is currently running.
::
### Chaining commands
Once the pattern clicks, commands can be plugged into each other:
- `&&` runs the next one only if the previous one succeeded: `sudo apt update && sudo apt full-upgrade`
- `|`, the pipe, feeds the output of one command into another: `ls -l | grep backup` lists the folder, then keeps only the lines containing "backup"
- `>` writes the output into a file instead of the screen, and `>>` adds to the end of that file: `df -h > disk-report.txt`
## The commands you'll actually use
Most command names are abbreviations of an English phrase. Once you know what they stand for, they stop looking like keyboard noise.
### pwd, print working directory
Tells you where you are. It changes nothing, it just answers the question.
```bash [Terminal]
pwd
```
```console [Output]
/home/username/docker
```
### ls, list
Lists what's in the current folder. On its own it prints bare names, so it's almost always used with options: `-l` for the long format with sizes, dates and permissions, `-a` to also show hidden files (the ones starting with a dot), `-h` for sizes in K/M/G instead of raw bytes.
```bash [Terminal]
ls -lah
```
```console [Output]
total 20K
drwxr-xr-x 4 username username 4.0K Sep 5 10:12 .
drwxr-xr-x 18 username username 4.0K Sep 4 21:03 ..
-rw-r--r-- 1 username username 512 Sep 5 10:12 .env
-rw-r--r-- 1 username username 1.2K Sep 5 09:58 compose.yaml
drwxr-xr-x 3 username username 4.0K Sep 2 18:44 immich
```
The first column is the permissions, `d` at the very start meaning it's a folder. Then the owner, the size, the date of the last change, and the name.
### cd, change directory
Moves you around. With a path it goes there, with `..` it goes up one level, and with nothing at all it takes you back home.
```console [Terminal]
username@serveex:~/docker$ cd /var/log
username@serveex:/var/log$ cd ..
username@serveex:/$ cd
username@serveex:~$
```
Notice the prompt following you around: it always shows where you currently stand, so you rarely need `pwd` in practice.
### mkdir, make directory
Creates a folder. Several at once if you list them, and `-p` creates the whole chain of parents in one shot, which is the version you'll actually use.
```bash [Terminal]
mkdir backups
mkdir -p docker/immich/config
```
```console [Output]
```
Nothing. That's not a bug, it's the rule: most commands say nothing when they succeed and only speak up when something goes wrong. Silence is good news, and `ls` confirms the folder is there.
### cp and mv, copy and move
`cp` copies, `mv` moves. Same shape both times: first the source, then the destination. Copying a folder needs `-r`, for *recursive*, since a folder means everything inside it too. `mv` doubles as the rename command, because renaming a file is just moving it to a new name.
```bash [Terminal]
cp compose.yaml compose.yaml.bak
cp -r config/ config-backup/
mv old-name.txt new-name.txt
ls
```
```console [Output]
compose.yaml compose.yaml.bak config config-backup new-name.txt
```
Three silent commands, and `ls` showing the result: the copy sits next to the original, the folder was duplicated, and `old-name.txt` is gone because moving it to another name is exactly what renaming means.
### rm, remove
Deletes. There is no recycle bin, no undo, no confirmation dialog. `-r` deletes a folder and its contents, `-f` forces without asking.
::warning
`rm -rf` is the command that wipes homelabs. It doesn't check, doesn't warn, and doesn't stop. Read the path twice before pressing :kbd{value="Enter"}, especially when the line starts with `sudo` and contains a `/` or a `*`.
::
### cat and nano, read and edit
`cat` (short for *concatenate*) dumps a whole file to the screen, perfect for a short config. For anything longer, `less` scrolls through it (named as a joke on `more`, the older pager it replaced), and you quit it with :kbd{value="Q"}.
To actually change a file, `nano` opens a simple editor: arrows to move, :kbd{value="Ctrl"} + :kbd{value="O"} to save, :kbd{value="Ctrl"} + :kbd{value="X"} to leave.
```bash [Terminal]
cat .env
```
```properties [Output]
PUID=1000
PGID=1000
TZ=Europe/Paris
```
### grep, search inside files
`grep` stands for *global regular expression print*, which is a mouthful for "find me this text". You give it what to look for and where, and it prints every matching line. `-r` searches a whole folder, `-i` ignores upper and lower case, `-n` shows line numbers.
```bash [Terminal]
grep -rin "password" /home/username/docker
```
```console [Output]
/home/username/docker/immich/.env:6:DB_PASSWORD=changeme
/home/username/docker/vaultwarden/compose.yaml:14: ADMIN_PASSWORD=hunter2
```
Each line is the file, then the line number inside it, then the matching line itself. Very handy for the day you can't remember which stack holds a setting.
### sudo, run as administrator
*Substitute user do*. A normal user can't touch the system's files, which is exactly what protects you from wrecking the machine by accident. Prefixing a command with `sudo` runs that single command with administrator rights, and asks for your password the first time.
```bash [Terminal]
nano /etc/ssh/sshd_config
```
```console [Output]
Error writing /etc/ssh/sshd_config: Permission denied
```
```bash [Terminal]
sudo nano /etc/ssh/sshd_config
```
```console [Output]
[sudo] password for username:
```
::note
If a command answers `Permission denied`, that's usually the whole problem: it needed `sudo`. Resist the reflex of putting `sudo` on everything though, a file created as root will keep annoying you afterwards because your normal user no longer owns it.
::
## Cheat sheet
The ones worth keeping at hand, and where their names come from.
| Command | Short for | What it does |
| --- | --- | --- |
| `pwd` | print working directory | Shows where you are |
| `ls` | list | Lists files and folders |
| `cd` | change directory | Moves you somewhere else |
| `mkdir` | make directory | Creates a folder |
| `touch` | plain English | Creates an empty file, or refreshes its date |
| `cp` | copy | Copies a file or folder |
| `mv` | move | Moves or renames |
| `rm` | remove | Deletes, permanently |
| `cat` | concatenate | Prints a file to the screen |
| `less` | a pun on `more` | Scrolls through a long file |
| `nano` | the editor replacing Pico | Edits a file |
| `grep` | global regular expression print | Searches for text |
| `find` | plain English | Searches for files by name, size or date |
| `man` | manual | Opens a command's full documentation |
| `df` | disk free | Shows free space per partition |
| `lsblk` | list block devices | Draws the tree of disks and partitions |
| `du` | disk usage | Shows what a folder weighs |
| `ps` | process status | Lists running processes |
| `htop` | Hisham's `top` | Live view of CPU, RAM and processes |
| `kill` | plain English | Stops a process by its number |
| `chmod` | change mode | Changes a file's permissions |
| `chown` | change owner | Changes who owns a file |
| `sudo` | substitute user do | Runs one command as administrator |
| `apt` | advanced package tool | Installs, updates and removes packages |
| `systemctl` | control systemd | Starts, stops and enables services |
| `ssh` | secure shell | Opens a session on a remote machine |
| `scp` | secure copy | Copies files over SSH |
| `tar` | tape archive | Packs and unpacks archives |
| `wget` | web get | Downloads a file from a URL |
| `curl` | client URL | Sends a request to a URL |
| `history` | plain English | Lists the commands you typed before |
::tip{icon=""}
✨ __Tip:__ nobody memorises this. You'll look up the same three options for weeks, then one day realise you're typing them without thinking. Until then, `--help` and this table are perfectly legitimate.
::
@@ -0,0 +1,59 @@
---
title: Folders and partitions
description: How the Debian filesystem is organised, what each top-level folder holds, how partitions differ from folders, and the habits that keep a server tidy.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
Windows gives every disk its own letter. Linux doesn't: there is exactly one tree, it starts at `/`, and everything else hangs off it, including your other disks. A second drive isn't `D:`, it's *mounted* at a folder of the tree, `/mnt/data` for example, and from that point on it looks like any other folder. Odd at first, very practical afterwards, since a program never has to care which physical disk it's writing to.
## The tree
That tree isn't arbitrary either. Every Debian install has the same folders in the same places, which is why a tutorial written for someone else's server applies to yours.
| Folder | What's in it |
| --- | --- |
| `/home` | Users' files. Yours is `/home/username`, also written `~` |
| `/root` | The root account's own home, not to be confused with `/` |
| `/etc` | System configuration, all of it plain text files |
| `/var` | Data that grows: logs in `/var/log`, Docker in `/var/lib/docker` |
| `/tmp` | Temporary files, emptied at every reboot |
| `/usr` | The installed programs themselves, managed by `apt` |
| `/opt` | Software installed outside the package manager |
| `/mnt` and `/media` | Where extra disks get mounted, `/media` for removable ones |
| `/boot` | The kernel and the bootloader, on a small partition of its own |
| `/dev` | Your hardware, exposed as files (`/dev/sda` is a disk) |
| `/proc` and `/sys` | The kernel's live state, invented on the fly, not real files |
## Folders are not partitions
Partitions are a different question from folders. A minimal Debian install typically creates two, one for `/` and one for swap, so every folder above except `/boot` lives on the same partition and shares the same free space. Two commands to see the reality of it: `lsblk` draws the tree of disks and partitions, `df -h` shows how full each one is.
```bash [Terminal]
lsblk
```
```console [Output]
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 465.8G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 461.3G 0 part /
└─sda3 8:3 0 4G 0 part [SWAP]
sdb 8:16 0 3.6T 0 disk
└─sdb1 8:17 0 3.6T 0 part /mnt/data
```
## A few habits worth taking
- **Give your Docker stacks one home, and keep them there.** `/srv` is the folder the standard reserves for data served by the machine, which makes it the tidiest choice for compose files and their bind mounts. [Serveex](/serveex/introduction) puts everything in `/srv/docker`, one folder per stack. What matters is picking one place and staying there, rather than scattering half of them into your home folder.
- **Your own files go in your home.** Scripts in `~/bin`, notes, downloads, anything personal. `/root` is the root account's home, not a convenient place to drop things.
- **Never edit anything under `/usr` or `/bin` by hand.** `apt` owns those, and your changes disappear at the next upgrade. What you're allowed to configure lives in `/etc`.
- **In `/etc`, prefer a drop-in file over editing the main one.** Many services read every `.conf` in a `something.d/` folder next to their main config, `/etc/ssh/sshd_config.d/` for instance. Your file then survives a package upgrade that rewrites the original.
- **Mount data disks by UUID, not by `/dev/sdb`.** Device letters are assigned in the order the kernel finds the disks, so they can swap after a reboot or a new drive. `lsblk -f` gives you the UUID to put in `/etc/fstab`.
- **Keep an eye on `/var`.** Docker images, container logs and system logs all pile up there, on the same partition as the rest. `du -sh /var/lib/docker` tells you what the containers weigh, `df -h` whether you should worry.
- **Don't create your files with `sudo` when you don't have to.** A file created as root inside your home stays owned by root, and you'll be fighting permission errors over it for weeks.
::note{to="/general/linux/cli-basics"}
Everything here assumes you can already move around a terminal. If `cd`, `ls` and `sudo` don't mean much yet, start with the **command line basics**.
::
@@ -0,0 +1,200 @@
---
title: Handy CLI tools
description: A handful of terminal tools worth installing on a home server, what each one replaces, and step-by-step instructions to install and use them.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
A minimal Debian install ships with the strict minimum, which means the tools you get are the ones from 1995. They work, but reading `df` output or hunting for what filled a disk with `du` is needlessly painful when better versions exist and cost nothing to install.
Everything below except the last one comes straight from Debian's repositories, so there's no third-party source to trust and `apt` keeps them updated along with the rest of the system.
::note{to="/general/linux/cli-basics"}
Every command here is typed in a terminal over SSH. If `sudo`, `apt` and `cd` don't mean much yet, start with the **command line basics**.
::
## The short version
| Tool | Replaces | What for |
| --- | --- | --- |
| `btop` | `top`, `htop` | Watching CPU, RAM and processes |
| `duf` | `df -h` | Free space, readable |
| `ncdu` | `du -sh` | Finding what filled the disk |
| `tldr` | `man` | The five commands you actually need |
| `lazydocker` | `docker ps` and friends | Managing containers over SSH |
## The impatient version
One line installs all the packaged ones, and each section below explains what you just got.
```bash [Terminal]
sudo apt update
sudo apt install btop duf ncdu tealdeer
```
## btop, watching what the machine is doing
The modern replacement for `top` and `htop`: CPU, RAM, disks, network and processes on one screen, with graphs, colors and a working mouse. This is what you open when something feels slow.
::steps{level="4"}
#### Install it
```bash [Terminal]
sudo apt install btop
```
#### Run it
```bash [Terminal]
sudo btop
```
![btop showing CPU, memory, disks, network and processes](/img/global/linux/btop.png)
Click a process to select it, :kbd{value="Esc"} opens the menu, :kbd{value="Q"} quits. The `+` and `-` keys fold and unfold the panels if the screen feels crowded.
#### Done !
::
## duf, disk space that reads like a table
`df -h` prints every loop device Docker ever created and leaves you squinting at the columns. `duf` shows the same information grouped, aligned and colored, with a usage bar per filesystem.
::steps{level="4"}
#### Install it
```bash [Terminal]
sudo apt install duf
```
#### Run it
```bash [Terminal]
sudo duf
```
![duf listing local, network and special filesystems](/img/global/linux/duf.png)
Local disks, network shares and system mounts are grouped separately. Add `--only local` to hide the pseudo-filesystems Docker leaves behind.
#### Done !
::
## ncdu, finding what ate the disk
When `duf` tells you the disk is full, `ncdu` tells you why. It walks a folder, sorts everything by real size, and lets you drill down with the arrow keys instead of running `du -sh *` twenty times.
::steps{level="4"}
#### Install it
```bash [Terminal]
sudo apt install ncdu
```
#### Point it at a folder
```bash [Terminal]
sudo ncdu /srv/docker
```
Arrows to move, :kbd{value="Enter"} to open a folder, :kbd{value="D"} to delete the selected item, :kbd{value="Q"} to quit. On a big disk the first scan takes a moment, it's reading everything.
::warning
:kbd{value="D"} deletes immediately, with a single confirmation and no recycle bin. Run `ncdu` without `sudo` when you're only looking, so a mistyped key can't touch anything the system owns.
::
#### Done !
::
## tldr, the manual without the 400 lines
`man tar` is exhaustive and unreadable. `tldr tar` gives you the five commands people actually type, with a one-line explanation each. It's community-maintained examples rather than a substitute for the real manual, and on Debian the client is packaged as `tealdeer`.
::steps{level="4"}
#### Install it
```bash [Terminal]
sudo apt install tealdeer
```
#### Download the page cache
```bash [Terminal]
tldr --update
```
The examples are fetched once and stored locally, so the command works offline afterwards. Run it again every few months.
#### Ask it something
```bash [Terminal]
tldr rsync
```
#### Done !
::
## lazydocker, managing containers from the terminal
The one exception: it isn't packaged by Debian. It's a full text interface for Docker, containers, images, volumes and logs in one screen, with keys to restart, stop or follow the logs of anything. Handy when you're already in SSH and don't feel like opening Dockge.
::steps{level="4"}
#### Download the latest release
```bash [Terminal]
curl -Lo /tmp/lazydocker.tar.gz "https://github.com/jesseduffield/lazydocker/releases/latest/download/lazydocker_0.25.2_Linux_x86_64.tar.gz"
```
Check the [releases page](https://github.com/jesseduffield/lazydocker/releases) for the current version number, and take `arm64` instead of `x86_64` if the server is a Raspberry Pi or similar.
#### Install the binary
```bash [Terminal]
sudo tar -xzf /tmp/lazydocker.tar.gz -C /usr/local/bin lazydocker
rm /tmp/lazydocker.tar.gz
```
`/usr/local/bin` is the folder meant for software you install yourself, which is why `apt` never touches it.
#### Check it landed
```bash [Terminal]
lazydocker --version
```
#### Run it
```bash [Terminal]
sudo lazydocker
```
![lazydocker showing services, containers, images, volumes and a container's config](/img/global/linux/lazydocker.png)
It needs access to the Docker socket, hence the `sudo` unless your user is in the `docker` group. The keys worth knowing:
| Key | What it does |
| --- | --- |
| `1` to `6` | Jump to a panel: projects, services, containers, images, volumes, networks |
| Arrows | Move inside the panel, the right side follows the selection |
| :kbd{value="Enter"} | Focus the main panel on the right, :kbd{value="Esc"} comes back |
| `x` | Open the menu of everything you can do with what's selected |
| `m` | Follow the logs |
| `s` / `r` / `p` | Stop, restart, pause the selected container |
| `E` | Open a shell inside the container |
| `d` | Remove it |
| `b` | Bulk commands, pruning images and volumes among others |
| `/` | Filter the list |
| `+` and `_` | Grow or shrink the panels |
| `q` | Quit |
Case matters: `E` opens a shell in the container, `e` hides the stopped ones.
The [full list](https://github.com/jesseduffield/lazydocker/blob/master/docs/keybindings/Keybindings_en.md) is in the project's documentation.
::note
Being outside `apt` also means it won't be updated by `apt full-upgrade`. Repeat these steps when you want a newer version.
::
#### Done !
::