Linux & CLI 101

scp = Secure Copy Protocol

  • Dateiübertragung über SSH
  • scp
Bash
# Lokal -> Remote
scp datei.txt user@host:/pfad/

# Remote -> Lokal
scp user@host:/pfad/datei.txt ./

# Remote -> Lokal in Downloads
scp user@host:/home/michu/deploy.sh ~/Downloads/

# Lokal -> Remote Datei überschreiben (achtung, es gibt kein Schutz der nachfrägt!)
scp index.html user@host:/pfad/index.html

# Mehrere Dateien in einem scp in Downloads Ordner
scp user@host:"/home/michu/{Caddyfile,SETUP.md,backup.sh,restore.sh,deploy.sh,cutover-to-caddy.sh,CYON-RESTIC-SETUP.md}" ~/Downloads/

# Wildcards (alle Dateien in Verzeichnis)
scp 'user@host:/home/michu/*.sh' ~/Downloads/
scp 'user@host:/home/michu/*.md' ~/Downloads/

# Ordner (rekursiv)
scp -r ordner/ user@host:/pfad/

tar = archivieren und extrahieren

  • -c = create (archivieren)
  • -x = extract (entpacken)
  • -z = gzip (komprimieren)
  • -f = file (Dateiname)
Bash
# Ordner archivieren lokal
tar -czf archiv.tar.gz ordner/ # konvention / zeigt, dass es ein Ordner ist
tar -czf archiv.tar.gz ordner # geht auch

# Datei archivieren lokal
tar -czf test.tar.gz test.md # .tar.gz Standard. Zeigt, dass archiviert + komprimiert

# Ordner entpacken 
tar -xzf archiv.tar.gz

scp + tar kombinieren

Bash
# Workflow: zip lokal, auf Server hochladen und entpacken
tar -czf archiv.tar.gz ordner/
scp archiv.tar.gz user@host:/pfad/
ssh user@host "tar -xzf /pfad/archiv.tar.gz -C /zielpfad/"

# Workflow: auf Server archivieren, lokal downloaden und entpacken
ssh user@host "tar -czf /pfad/archiv.tar.gz /quellpfad/"
scp user@host:/pfad/archiv.tar.gz ~/Downloads/
tar -xzf ~/Downloads/archiv.tar.gz

cat = Inhalte in Terminal ausgeben

test.md mit Inhalt „# Hey du“

Bash
cat test.md
# Hey Du

mv = verschieben und umnenennen

Bash
mv alt.txt neu.txt        # achtung, wenn neu.txt schon existiert, wird die direkt überschrieben!
mv -i alt.txt neu.txt     # -i = interactive: fragt nach, ob überschrieben werden soll

mv datei.txt /pfad/       # datei verschieben
mv ordner /pfad/          # ordner verschieben

mv altname /pfad/neuname  # umbenennen + verschieben in einem

cp = kopieren

Bash
cp datei.txt kopie.txt       # datei.txt wird zu identischer Kopie kopie.txt
cp datei.txt /pfad           # datei.txt wird in Ordner kopiert

cp -r ordner/ /pfad          # -r braucht es bei Ordnern zwingend, sonst fehler
cp -i datei.txt kopie.txt    # nachfragen, ob überschrieben werden soll, falls vorhanden

ls = zeige Inhalte

Bash
ls              # aktueller ordner
ls /pfad/       # anderer ordner
ls -l           # details (rechte, grösse, datum)
ls -a           # zeigt versteckte dateien (.dotfiles)
ls -la          # beides kombiniert
ls -lh          # menschenlesbare grössen (KB, MB)
ls -lah         # alles kombinieren

mkdir = Ordner erstellen

Bash
mkdir ordner
mkdir -p /pfad/ordner/unterordner    # -p = parents: erstellt alle ebenen auf einmal

touch = Datei erstellen

Bash
touch index.html                       # eine Datei erstellen
touch index.html style.css script.js   # mehrere Dateien gleichzeitig erstellen

nano = Datei mit nano bearbeiten

Bash
Ctrl+O            # = speichern
Ctrl+X            # = beenden
Ctrl+K            # = zeile löschen
Ctrl+W            # = suchen
Ctrl+W & Ctrl+R   # = suchen und ersetzen
Ctrl+U            # = einfügen (nach K)

vim = Datei mit vim bearbeiten

Bash
i     # = insert-modus (schreiben)
esc   # = zurück zu normal-modus
:w    # = speichern
:q    # = beenden
:wq   # = speichern + beenden
:q!   # = beenden ohne speichern
gg    # = ganz nach oben
G     # = ganz nach unten
dd    # = zeile löschen
3dd   # = 3 zeilen löschen
yy    # = zeile kopieren
3yy   # = 3 zeilen kopieren
p     # = einfügen
ggVG  # = alles auswählen
ggdG  # = alles löschen

u        # = undo
Ctrl+R   # = redo
b        # = nächstes wort rückwärts
w        # = nächstes wort vorwärts
0        # = zum zeilenanfang
$        # = zum zeilenende

/suchbegriff  # = suchbegriff suchen
n             # = nächster suchtreffer
N             # = vorheriger suchtreffer

:%s/alt/neu/g    # = text ersetzen im ganzen dokument
:%s/alt/neu/gc   # = text ersetzen mit bestätigung (c = confirm)

:set number      # = zeilennummern anzeigen

rm = Dateien entfernen

Bash
rm datei.txt      # datei löschen
rm -i datei.txt   # nachfragen
rm -r ordner/     # ordner löschen
rm -ri ordner/    # ordner löschen mit nachfragen
rm -rf ordner/    # ordner löschen ohne nachfragen
rm *.txt          # alle .txt löschen

cd & pwd = navigieren innerhalb System

Bash
cd /pfad/       # absoluter pfad
cd ordner       # relativer pfad
cd ..           # einen ordner hoch
cd ~            # home-verzeichnis
cd -            # vorheriges verzeichnis
cd /            # zum root des systems
pwd             # zeigt aktuelles verzeichnis

Output & Logs

Bash
> index.html                     # leer das file
>> datei.txt                     # anhängen (nicht überschreiben)
echo "neuer text" >> datei.txt   # hängt neuer text am ende der datei.txt an

command > /dev/null              # output wegwerfen
command 2>&1                     # stderr zu stdout
command > /dev/null 2>&1         # alles wegwerfen
command >> log.txt               # output in logfile
command >> log.txt 2>&1          # alles in logfile
nohup command &                  # prozess läuft weiter nach logout
nohup command > log.txt 2>&1 &   # + alles loggen

echo "$(date): backup gestartet" >> /var/log/mein-script.log # = custom log erstellen

Logrotate

Bash
vim /etc/logrotate.d/mein-script
Bash
/var/log/mein-script.log {
    weekly
    rotate 2
    compress
    missingok
    notifempty
}

# Option               # Bedeutung
# daily                # tächlig rotieren
# weekly               # wöchentlich rotieren
# monthly              # monatlich rotieren
# yearly               # jährlich rotieren

# rotate 14            # je nach rotation oben, wie viele behalten. daily + rotate 14 = 14 tage. weekly + rotate 2 = 2 wochen

# compress             # alte logs als .gz speichern
# delaycompress        # neueste logs nicht sofort komprimieren. erst 2 tag. als addon zu compress nutzen, alleine gehts nicht

# missingok            # kein fehler wenn log fehlt

# notifempty           # nicht rotieren wenn leer

# create 0640 root root   # rechte für neues logfile setzen
Bash
logrotate -d /etc/logrotate.d/mein-script   # -d = dry-run, zeigt was passieren würde

Linux Dateisystem

Bash
/               # wurzel, alles startet hier
├── etc/        # konfigurationsdateien (nginx, ssh, logrotate...)
├── home/       # user-verzeichnisse (/home/michu)
├── root/       # home des root-users
├── var/        # variable daten: logs, cache, datenbanken
   └── log/    # logfiles
├── usr/        # programme und bibliotheken
├── bin/        # grundlegende befehle (ls, cp, mv...)
├── tmp/        # temporäre dateien (wird bei reboot geleert)
└── srv/        # serverdaten (websites, ftp...)

# am häufigsten genutzt /etc, /home, /var/log, /tmp

Linux User-System

Bei Installation gibt es:

  • root = Superuser, darf alles
  • dein User (z.B. michu) = normaler User
Bash
# root
# - darf alles
# - kein sudo nötig
# - home: /root (cd /root)

# normaler user (z.b. michu)
# - darf eigene files
# - /etc/ und system = kein zugriff
# - sudo = befehl als root ausführen
# - home: /home/michu (cd ~)

whoami          # aktueller user anzeigen
id              # user + gruppen anzeigen
sudo befehl     # befehl als root ausführen
su -            # zu root wechseln (falls erlaubt)
Bash
# user anlegen
adduser michu                    # user + home-verzeichnis erstellen

# sudo-rechte geben
usermod -aG sudo michu           # zu sudo-gruppe hinzufügen

# als michu einloggen
su - michu

# prüfen
whoami
id

# user löschen
userdel michu           # user löschen
userdel -r michu        # user + home-verzeichnis löschen

Gruppen

Bash
groups              # eigene gruppen anzeigen
id                  # user + gruppen
cat /etc/group      # alle gruppen auf system
usermod -aG docker michu   # user zu gruppe hinzufügen

Dateirechte

Bash
ls -la
# -rw-r--r-- 1 michu michu 1234 mai 19 deploy.sh
#  ^^^^^^^^^   ^^^^^
#  rechte       owner

Rechte verstehen

Bash
-  rw-  r--  r--
|   |    |    |
|   |    |    └── andere (others)
|   |    └─────── gruppe (group)
|   └──────────── owner
└──────────────── typ (- = datei, d = ordner)

# r    lesen        4
# w    schreiben    2
# x    ausführen    1
# -    kein recht   0  
Bash
# rechte setzen
chmod 640 datei.txt            # owner=rw, gruppe=r, andere=nichts
chmod 755 script.sh            # owner=rwx, gruppe=rx, andere=rx
chown michu:michu datei.txt    # owner ändern

# 644   normale dateien (config, html, css, htaccess)
# 640   sensible configs (passwörter, .env, .wp-config.php)
# 755   ordner, scripts (ausführbar, backup.sh, restore.sh, wp-content) -> chmod +x (ausführbar machen)
# 700   sensible ordner (nur owner, .ssh, secrets)
# 600   private keys, ssh keys

# touch script.sh        # erstellen
# vim script.sh          # bearbeiten + speichern
# chmod +x script.sh     # ausführbar machen
# ./script.sh            # ausführen

Schwierigkeit der User + Berechtigungen

Jeder Dienst läuft als eigener User/Gruppe:

  • nginx läuft als www-data → nur www-data bekommt Zugriff auf Webfiles
  • docker läuft als docker → nur docker-gruppe für Docker-Socket
  • mysql läuft als mysql → nur mysql für DB-Dateien

So kann nginx nicht auf DB-Dateien zugreifen und umgekehrt – Isolation.

Wenn nginx eine Datei lesen will, muss www-data Leserecht haben.

Bash
# datei gehört michu, nginx kann nicht lesen
-rw------- michu michu index.php   # 600 = nur michu

# fix: gruppe www-data hinzufügen
chown michu:www-data index.php
chmod 640 index.php   # owner=rw, gruppe=r

# oder user zu gruppe hinzufügen:
usermod -aG www-data michu
Bash
# nginx/php braucht zugriff auf wordpress files
chown -R michu:www-data /home/michu/sites/site1/
chmod -R 755 /home/michu/sites/site1/
chmod -R 640 /home/michu/sites/site1/*.php

Faustregel:

  • Owner = dein user (michu)
  • Gruppe = dienst der zugriff braucht (www-data, docker)
  • Nie 777 – das ist ein Sicherheitsproblem