Moved homelab-mastery repo content into homelab-mastery/ subdirectory. Covers architecture, concepts, certifications, interview-prep, and learning-path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
185 lines
6 KiB
Markdown
185 lines
6 KiB
Markdown
# Linux — Commands and Concepts to Own
|
|
|
|
You've been running Linux commands without fully owning them. This fixes that.
|
|
|
|
---
|
|
|
|
## The Filesystem
|
|
|
|
Everything in Linux is a file. The filesystem tree starts at `/` (root):
|
|
|
|
```
|
|
/
|
|
├── etc/ Configuration files (system-wide)
|
|
├── home/ User home directories (/home/kenpat)
|
|
├── opt/ Optional/third-party software (kscloud1 services live here)
|
|
├── proc/ Virtual filesystem — running processes, kernel info
|
|
│ ├── uptime System uptime in seconds
|
|
│ └── net/route Routing table (used by metrics API to find active interface)
|
|
├── sys/ Virtual filesystem — hardware/kernel info
|
|
├── var/ Variable data — logs, databases, cache
|
|
└── usr/ User programs and libraries
|
|
```
|
|
|
|
---
|
|
|
|
## File Permissions
|
|
|
|
Every file has three permission sets: **owner**, **group**, **others**.
|
|
|
|
```bash
|
|
ls -la ~/kitestacks-live/docker/kavita/config/kavita.db
|
|
-rw-r--r-- 1 kenpat kenpat 2.4M Jun 11 kavita.db
|
|
```
|
|
|
|
Breaking it down:
|
|
- `-` — it's a file (not a directory `d` or symlink `l`)
|
|
- `rw-` — owner (kenpat): read + write
|
|
- `r--` — group (kenpat): read only
|
|
- `r--` — others: read only
|
|
|
|
**chmod** changes permissions. **chown** changes owner.
|
|
|
|
Why this mattered: When syncing kavita.db to kscloud1, you ran `chown 1000:1000` because the Kavita container runs as user ID 1000. If the file is owned by the wrong user ID, the container can't write to it.
|
|
|
|
```bash
|
|
chmod 644 kavita.db # rw-r--r--
|
|
chmod 755 script.sh # rwxr-xr-x (executable)
|
|
chown 1000:1000 kavita.db # set owner to UID 1000, GID 1000
|
|
chown -R kenpat:kenpat ./ # recursive (-R) on a directory
|
|
```
|
|
|
|
---
|
|
|
|
## Processes
|
|
|
|
```bash
|
|
ps aux # all running processes
|
|
ps aux | grep forgejo # find forgejo processes
|
|
kill 1234 # send SIGTERM to PID 1234 (polite stop)
|
|
kill -9 1234 # send SIGKILL (force kill, no cleanup)
|
|
```
|
|
|
|
**systemctl** manages systemd services (services that start on boot):
|
|
```bash
|
|
systemctl status tailscaled # is tailscale running?
|
|
systemctl restart tailscaled # restart it
|
|
systemctl enable tailscaled # start on boot
|
|
journalctl -u tailscaled # logs for tailscale service
|
|
```
|
|
|
|
Your containers don't use systemd — Docker manages them with `restart: unless-stopped`.
|
|
|
|
---
|
|
|
|
## Networking Commands
|
|
|
|
```bash
|
|
# What ports is this machine listening on?
|
|
ss -tlnp # TCP listening, numeric, with process
|
|
ss -tlnp | grep :3006 # is Forgejo's port bound?
|
|
|
|
# Test connectivity
|
|
ping 8.8.8.8 # can I reach Google DNS?
|
|
curl -I https://auth.kitestacks.com # HTTP headers from Authentik
|
|
curl -s http://localhost:8000/api/health # test metrics API
|
|
|
|
# DNS lookup
|
|
dig www.kitestacks.com # full DNS query details
|
|
nslookup gitforge.kitestacks.com # simpler DNS lookup
|
|
|
|
# Firewall
|
|
sudo ufw status # what rules are active?
|
|
sudo ufw allow 22/tcp # allow SSH
|
|
sudo ufw deny 3306/tcp # block MySQL from outside
|
|
```
|
|
|
|
---
|
|
|
|
## Piping and Redirection
|
|
|
|
The `|` (pipe) sends output of one command as input to another:
|
|
|
|
```bash
|
|
docker ps | grep forgejo # filter docker ps output
|
|
cat prometheus.yml | grep job # find job lines in config
|
|
docker logs authentik 2>&1 | grep ERROR # show only errors
|
|
```
|
|
|
|
`2>&1` redirects stderr (error output, stream 2) to stdout (stream 1) — so errors appear in the same stream as normal output and can be piped.
|
|
|
|
`>` redirects output to a file (overwrites):
|
|
```bash
|
|
pg_dump authentik > authentik-backup.sql
|
|
```
|
|
|
|
`>>` appends to a file:
|
|
```bash
|
|
echo "new line" >> ~/.ssh/config
|
|
```
|
|
|
|
---
|
|
|
|
## SSH
|
|
|
|
SSH (Secure Shell) gives you a terminal session on a remote machine.
|
|
|
|
```bash
|
|
ssh kenpat@5.78.x.x # basic SSH
|
|
ssh -i ~/.ssh/id_ed25519_kscloud1 kenpat@5.78.x.x # specify key
|
|
ssh -L 5099:localhost:5000 kenpat@5.78.x.x # local port forward
|
|
```
|
|
|
|
**Local port forward** (`-L local:remote_host:remote_port`):
|
|
`ssh -L 5099:localhost:5000 kenpat@kscloud1` means:
|
|
- Traffic to YOUR localhost:5099
|
|
- Gets tunneled through the SSH connection
|
|
- And hits kscloud1's localhost:5000
|
|
|
|
You used this to access kscloud1's Kavita instance (running on port 5000) from your browser at http://localhost:5099 — without opening that port to the internet.
|
|
|
|
---
|
|
|
|
## sudo and Non-Interactive Usage
|
|
|
|
`sudo` runs a command as root. It normally prompts for your password.
|
|
|
|
**The kscloud1 problem:** In automated scripts, there's no terminal to enter a password. Solution:
|
|
```bash
|
|
echo YOUR_PASSWORD | sudo -S command
|
|
# -S reads password from stdin instead of terminal
|
|
```
|
|
|
|
You used this to run ufw commands non-interactively. In real production environments, this is handled differently (sudoers file with NOPASSWD for specific commands, or SSH key-based service accounts).
|
|
|
|
---
|
|
|
|
## Grep, Sed, Awk
|
|
|
|
**grep** finds lines matching a pattern:
|
|
```bash
|
|
grep "error" /var/log/syslog # lines containing "error"
|
|
grep -i "error" logfile # case-insensitive
|
|
grep -n "AUTHENTIK" docker-compose.yml # show line numbers
|
|
grep -r "p12217177" /opt/kitestacks/ # recursive search in directory
|
|
```
|
|
|
|
**sed** (stream editor) modifies text:
|
|
```bash
|
|
sed 's/old_text/new_text/g' file.txt # replace all occurrences
|
|
sed -i 's/old/new/g' file.txt # -i edits file in place
|
|
```
|
|
|
|
**awk** processes structured text (columns):
|
|
```bash
|
|
grep PG_PASS .env | cut -d= -f2- # get value after = (including trailing =)
|
|
# cut -d= splits on =, -f2- means "field 2 and everything after"
|
|
# This is why: PG_PASS=abc= → if you use -f2, you get "abc" (loses trailing =)
|
|
# With -f2-, you get "abc=" (correct)
|
|
```
|
|
|
|
---
|
|
|
|
## What to Say About Linux
|
|
|
|
> *"All services run on Linux hosts. I'm comfortable with file permissions, process management, SSH configuration (including local port forwarding for secure access to non-exposed services), firewall rules with ufw, and command-line tools like grep, curl, and docker CLI. I diagnosed and fixed a network configuration issue on the cloud VPS where ufw's default-deny policy was blocking Docker container traffic to a host-network-mode service."*
|