====== Instalace Claude Code na serveru (Debian) ======
//Vytvořeno: **6.5.2026** | Aktualizováno: **~~LASTMOD~~**//
[[https://code.claude.com/|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 [[https://code.claude.com/docs/en/quickstart|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}@"
else
echo " Přihlaste se znovu: ssh -p 2022 @"
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}@"
else
echo " Poté se přihlaste: ssh -p 2022 @"
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 @''.
===== 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 [[ai:platformy:claude-code:statusline|Claude Code statusline]].
===== Zdroje =====
* [[https://code.claude.com/docs/en/quickstart|Claude Code – quickstart]]