Instalace Claude Code na serveru (Debian)
Vytvořeno: 6.5.2026 | Aktualizováno: 06.05.2026 14:18
Claude Code je AI coding assistant od Anthropicu pro příkazovou řádku. Tento článek popisuje instalaci na Debianu a doporučenou konfiguraci oprávnění pro bezpečné použití na produkčním serveru.
Instalace
Instalace probíhá přes quickstart skript:
curl -fsSL https://claude.ai/install.sh | bash
Po instalaci je potřeba přidat ~/.local/bin do PATH:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
Poté je příkaz claude dostupný z příkazové řádky.
Příprava serveru
Pokud přistupuješ na server jako root bez nastaveného firewallu, je vhodné nejdříve vytvořit neprivilegovaného uživatele, přepnout SSH na nestandardní port a zapnout UFW. Následující skript to provede interaktivně:
- vytvoří nového uživatele s passwordless sudo (volitelně)
- nastaví SSH na port 2022 a zakáže root login
- přidá UFW pravidlo pro nový port a teprve pak firewall zapne
- volitelně nastaví systemd socket override, pokud server používá
ssh.socket
#!/bin/bash # Instalační skript: hostname + nový uživatel + passwordless sudo + SSH + UFW set -e # ── Root check ──────────────────────────────────────────────────────────────── if [[ $EUID -ne 0 ]]; then echo "Spusťte skript jako root: sudo bash $0" exit 1 fi # ── Závislosti ──────────────────────────────────────────────────────────────── echo "[*] Kontrola závislostí..." MISSING_PKGS=() command -v adduser &>/dev/null || MISSING_PKGS+=(adduser) command -v visudo &>/dev/null || MISSING_PKGS+=(sudo) command -v ufw &>/dev/null || MISSING_PKGS+=(ufw) command -v sshd &>/dev/null || MISSING_PKGS+=(openssh-server) command -v hostnamectl &>/dev/null || MISSING_PKGS+=(systemd) command -v jq &>/dev/null || MISSING_PKGS+=(jq) if [[ ${#MISSING_PKGS[@]} -gt 0 ]]; then echo "[*] Instaluji chybějící balíčky: ${MISSING_PKGS[*]}" apt-get update -qq apt-get install -y -qq "${MISSING_PKGS[@]}" echo "[OK] Závislosti nainstalovány." else echo "[OK] Všechny závislosti jsou dostupné." fi echo "" # ── Vstup ───────────────────────────────────────────────────────────────────── read -rp "Vytvořit nového uživatele? [y/N] " CREATE_USER if [[ "$CREATE_USER" =~ ^[Yy]$ ]]; then read -rp "Jméno nového uživatele : " NEW_USER if [[ -z "$NEW_USER" ]]; then echo "Jméno uživatele nesmí být prázdné." exit 1 fi fi read -rp "Nový hostname serveru : " NEW_HOSTNAME if [[ -z "$NEW_HOSTNAME" ]]; then echo "Hostname nesmí být prázdný." exit 1 fi echo "" # ── Vytvoření uživatele ──────────────────────────────────────────────────────── if [[ "$CREATE_USER" =~ ^[Yy]$ ]]; then if id "$NEW_USER" &>/dev/null; then echo "[INFO] Uživatel '$NEW_USER' již existuje – přeskakuji vytvoření." else adduser --gecos "" "$NEW_USER" echo "[OK] Uživatel '$NEW_USER' vytvořen." fi usermod -aG sudo "$NEW_USER" echo "[OK] Uživatel '$NEW_USER' přidán do skupiny sudo." SUDOERS_FILE="/etc/sudoers.d/${NEW_USER}-nopasswd" echo "${NEW_USER} ALL=(ALL) NOPASSWD:ALL" > "$SUDOERS_FILE" chmod 440 "$SUDOERS_FILE" if visudo -cf "$SUDOERS_FILE"; then echo "[OK] Passwordless sudo nakonfigurováno ($SUDOERS_FILE)." else echo "[CHYBA] Neplatná konfigurace sudoers – mažu soubor." rm -f "$SUDOERS_FILE" exit 1 fi else echo "[INFO] Vytvoření uživatele přeskočeno." fi # ── SSH konfigurace ─────────────────────────────────────────────────────────── SSHD_CONFIG="/etc/ssh/sshd_config" BACKUP="${SSHD_CONFIG}.bak.$(date +%Y%m%d_%H%M%S)" cp "$SSHD_CONFIG" "$BACKUP" echo "[OK] Záloha sshd_config → $BACKUP" if grep -qE "^#?Port " "$SSHD_CONFIG"; then sed -i 's/^#\?Port .*/Port 2022/' "$SSHD_CONFIG" else echo "Port 2022" >> "$SSHD_CONFIG" fi if grep -qE "^#?PermitRootLogin " "$SSHD_CONFIG"; then sed -i 's/^#\?PermitRootLogin .*/PermitRootLogin no/' "$SSHD_CONFIG" else echo "PermitRootLogin no" >> "$SSHD_CONFIG" fi if sshd -t; then echo "[OK] Syntaxe sshd_config je v pořádku." else echo "[CHYBA] Špatná konfigurace sshd – obnovuji zálohu!" cp "$BACKUP" "$SSHD_CONFIG" exit 1 fi # ── Hostname ────────────────────────────────────────────────────────────────── hostnamectl set-hostname "$NEW_HOSTNAME" echo "[OK] Hostname nastaven na '$NEW_HOSTNAME'." # ── UFW pravidla (firewall se zatím nezapíná) ───────────────────────────────── ufw allow 2022/tcp echo "[OK] UFW pravidlo přidáno: 2022/tcp." # ── Systemd socket override (jen pokud ssh.socket existuje a je aktivní) ────── USE_SOCKET=false if systemctl list-unit-files ssh.socket &>/dev/null && \ systemctl is-enabled ssh.socket 2>/dev/null | grep -qE "^(enabled|static)"; then USE_SOCKET=true SOCKET_OVERRIDE_DIR="/etc/systemd/system/ssh.socket.d" SOCKET_OVERRIDE_FILE="${SOCKET_OVERRIDE_DIR}/override.conf" mkdir -p "$SOCKET_OVERRIDE_DIR" cat > "$SOCKET_OVERRIDE_FILE" << 'EOF' [Socket] ListenStream= ListenStream=0.0.0.0:2022 ListenStream=[::]:2022 EOF systemctl daemon-reload echo "[OK] Systemd socket override vytvořen ($SOCKET_OVERRIDE_FILE)." else echo "[INFO] ssh.socket není aktivní – port řídí pouze sshd_config." systemctl daemon-reload fi # ── Shrnutí a potvrzení ──────────────────────────────────────────────────────── echo "" echo "════════════════════════════════════════════════════════" echo " Vše je připraveno. Čeká se na aktivaci:" echo "" echo " Hostname : $NEW_HOSTNAME" if [[ "$CREATE_USER" =~ ^[Yy]$ ]]; then echo " Nový uživatel : $NEW_USER (passwordless sudo)" fi echo " SSH port : 2022 (root login zakázán)" echo " UFW : pravidlo pro 2022/tcp přidáno" echo "" echo " Po potvrzení se provede:" echo " 1. Zapnutí UFW (povoleno pouze 2022/tcp)" echo " 2. Restart SSH na portu 2022" echo "" echo " !! Vaše stávající SSH session bude ukončena. !!" if [[ "$CREATE_USER" =~ ^[Yy]$ ]]; then echo " Přihlaste se znovu: ssh -p 2022 ${NEW_USER}@<server>" else echo " Přihlaste se znovu: ssh -p 2022 <uživatel>@<server>" fi echo "════════════════════════════════════════════════════════" echo "" read -rp "Zapnout UFW a restartovat SSH? [y/N] " CONFIRM if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then ufw --force enable echo "[OK] UFW zapnut." echo "[*] Restartuji SSH – tato session bude ukončena..." if [[ "$USE_SOCKET" == true ]]; then systemctl restart ssh.socket fi if systemctl list-unit-files sshd.service &>/dev/null 2>&1; then systemctl restart sshd else systemctl restart ssh fi else echo "" echo "[INFO] Aktivace přeskočena. Až budete připraveni, spusťte ručně:" echo " sudo ufw --force enable" if [[ "$USE_SOCKET" == true ]]; then echo " sudo systemctl restart ssh.socket" fi echo " sudo systemctl restart ssh # nebo sshd na některých Debianu" echo "" if [[ "$CREATE_USER" =~ ^[Yy]$ ]]; then echo " Poté se přihlaste: ssh -p 2022 ${NEW_USER}@<server>" else echo " Poté se přihlaste: ssh -p 2022 <uživatel>@<server>" fi fi
Poznámka: Skript přidá UFW pravidlo pro port 2022, ale firewall nezapne automaticky. Až potvrdíš aktivaci, teprve pak se UFW aktivuje a SSH restartuje — stávající session bude ukončena. Přihlaš se znovu přes:ssh -p 2022 <uživatel>@<server>.
Konfigurace oprávnění
Po přihlášení jako nový uživatel nainstaluj Claude Code a nakonfiguruj ~/.claude/settings.json. Základní filosofie: allowlist, ne denylist. Do automaticky schválených příkazů patří jen příkazy bez vedlejších efektů — ostatní Claude vždy nejdřív navrhne a čeká na potvrzení.
jq je nutnou závislostí pro audit hook níže — skript výše ho nainstaluje automaticky.
.claude/settings.json
{
"permissions": {
"allow": [
"Read(*)",
"Bash(pwd)",
"Bash(echo *)",
"Bash(id)",
"Bash(whoami)",
"Bash(uname *)",
"Bash(uptime)",
"Bash(ls)",
"Bash(ls *)",
"Bash(find *)",
"Bash(grep *)",
"Bash(cat *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(stat *)",
"Bash(ps *)",
"Bash(ss *)",
"Bash(df *)",
"Bash(du *)",
"Bash(free *)",
"Bash(systemctl status *)",
"Bash(systemctl is-active *)",
"Bash(systemctl is-enabled *)",
"Bash(systemctl list-units *)",
"Bash(journalctl *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git show *)"
]
}
}
Záměrně není v allowlistu Bash(env) ani Bash(printenv *) — mohou prozradit citlivé proměnné prostředí (tokeny, hesla).
Co to v praxi znamená
| Operace | Výsledek |
|---|---|
ls, grep, find, cat, head, tail | auto-schváleno |
git status, git diff, git log, git show | auto-schváleno |
systemctl status / is-active / is-enabled / list-units | auto-schváleno |
journalctl * | auto-schváleno |
df, du, free, uptime, ps, ss | auto-schváleno |
rm, mv, cp | Claude se zeptá |
sudo cokoli | Claude se zeptá |
python3 skript.py, bash skript.sh | Claude se zeptá |
apt install, apt remove, apt update | Claude se zeptá |
chmod, chown | Claude se zeptá |
ufw, iptables, nft | Claude se zeptá |
git commit, git push, git reset | Claude se zeptá |
env, printenv | Claude se zeptá |
Edit(soubor), Write(soubor) | Claude se zeptá |
Audit hook
Hooky v Claude Code dostávají vstup jako JSON na stdin, parsovaný přes jq. Logování probíhá dvakrát: PreToolUse zachytí záměr (i když ho pak neschválíš), PostToolUse zachytí dokončení. Když pro nějaký příkaz vidíš jen PRE bez odpovídajícího POST, příkaz buď nebyl schválen, nebo byl přerušen.
Před první session vytvoř adresář pro logy:
mkdir -p ~/log
Sekci hooks přidej do ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"[\\(now | strftime(\\\"%Y-%m-%d %H:%M:%S\\\"))] PRE \\(.tool_input.command)\"' >> $HOME/log/claude-audit.log"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"[\\(now | strftime(\\\"%Y-%m-%d %H:%M:%S\\\"))] POST \\(.tool_input.command)\"' >> $HOME/log/claude-audit.log"
}
]
}
]
}
}
Příklad výstupu v logu:
[2026-05-06 14:22:01] PRE systemctl status nginx
[2026-05-06 14:22:01] POST systemctl status nginx
[2026-05-06 14:22:18] PRE rm /etc/nginx/sites-enabled/old.conf
[2026-05-06 14:22:24] POST rm /etc/nginx/sites-enabled/old.conf
[2026-05-06 14:23:05] PRE apt remove apache2
← chybí POST = neschváleno nebo přerušeno
Statusline
Konfiguraci statusline (zobrazení stavu Claude Code v terminálu) najdeš na stránce Claude Code statusline.