port Tailscale as its own section, early, and stop it hanging
Moved to position 7 — after core utils, which give it curl, and well before SSH
hardening, which is the step that can lock you out. The argument is that
Tailscale is a second way into the machine, so it wants to exist before anything
that can go wrong does.
── Why the original hung, and what stops it now ──
Its prompt accepted an empty auth key and passed it anyway. `tailscale up
--authkey ""` falls back to the interactive flow: it prints a URL and blocks,
with no timeout, forever. From the outside that is a script that has frozen.
Nothing here passes an empty key — the flag is omitted entirely, and the run says
in advance that a URL is coming and that it will wait. Every call carries
--timeout=60s, and a timeout is reported with the command to run by hand rather
than left as silence. State is read with `tailscale status --json` before
anything is run, so a node that is already up is offered a reconfigure instead of
having `up` fired at it blindly.
Diagnosed on this host rather than guessed at, and honestly the diagnosis is
partial: the exit-node branch left no trace at all — no /etc/sysctl.d file,
networkd-dispatcher present but with zero mentions in apt history, so it came
with the image. ip_forward=1 came from the unconditional part of the section, not
the branch. That points at `tailscale up` as where it stopped, and the empty-key
path is the candidate that fits, but I could not reproduce it to be certain.
── What the section now covers ──
control plane Tailscale's own service by default; a self-hosted headscale as
an explicit choice with NO suggested URL. The original defaulted
to headscale.pastilhas.eu, so a stranger running it pointed
their machine at somebody else's control plane.
auth key, or the browser flow, stated as an equal option
Tailscale SSH ssh over the tailnet with no keys, governed by tailnet ACLs —
and pointed out as a way back in if the sshd hardening later in
the run goes wrong
subnet router homelab only, defaulting to this machine's actual LAN CIDR
exit node with what it means for whose traffic goes where
forwarding sysctls and Tailscale's recommended NIC offload settings, and
only when an exit node or a route actually needs them
Approval is mentioned: an advertised route or exit node does nothing until it is
approved in the admin console, which is otherwise a silent non-event.
Also added --only <step> and --list, because this section in particular needs to
be run on its own while it is being worked on. A step run that way ignores the
progress file and does not record itself — asking for one step is not progress
through the script.
One bash quirk fixed on the way: "${VAR:-Tailscale's own service}" does not
parse. An apostrophe inside a ${:-} default opens a quoted section that swallows
the closing brace, and the error surfaces as "unexpected EOF" 400 lines away.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -85,8 +85,25 @@ fail() {
|
|||||||
# step_ok
|
# step_ok
|
||||||
# fi
|
# fi
|
||||||
|
|
||||||
|
# Set by --only. When it is set, every step whose name does not match is passed
|
||||||
|
# over in silence, and the one that does matches runs regardless of the progress
|
||||||
|
# file — the point of asking for a single step is to run that step.
|
||||||
|
ONLY_STEP="${ONLY_STEP:-}"
|
||||||
|
|
||||||
step() {
|
step() {
|
||||||
CURRENT_STEP="$1"
|
CURRENT_STEP="$1"
|
||||||
|
|
||||||
|
if [[ -n "$ONLY_STEP" ]]; then
|
||||||
|
if [[ "${1,,}" == "${ONLY_STEP,,}" ]]; then
|
||||||
|
SKIP_STEP=false
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD}── $1 ──${NC}"
|
||||||
|
else
|
||||||
|
SKIP_STEP=true
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
if grep -qxF "$1" "$PROGRESS_FILE" 2>/dev/null; then
|
if grep -qxF "$1" "$PROGRESS_FILE" 2>/dev/null; then
|
||||||
echo -e " ${GREEN}SKIP${NC}: $1 (already done)"
|
echo -e " ${GREEN}SKIP${NC}: $1 (already done)"
|
||||||
SKIP_STEP=true
|
SKIP_STEP=true
|
||||||
@@ -100,6 +117,9 @@ step() {
|
|||||||
skip() { [[ "$SKIP_STEP" == true ]]; }
|
skip() { [[ "$SKIP_STEP" == true ]]; }
|
||||||
|
|
||||||
step_ok() {
|
step_ok() {
|
||||||
|
# A single step run on its own is not progress through the script, and
|
||||||
|
# recording it would make the next full run skip it.
|
||||||
|
[[ -n "$ONLY_STEP" ]] && return 0
|
||||||
echo "$CURRENT_STEP" >>"$PROGRESS_FILE"
|
echo "$CURRENT_STEP" >>"$PROGRESS_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# =============================================================================
|
||||||
|
# machine-setup — Tailscale
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# Definitions only, like the other lib/ files.
|
||||||
|
#
|
||||||
|
# ── Why this runs early ──
|
||||||
|
#
|
||||||
|
# It is a second way into the machine. The section that can lock you out is SSH
|
||||||
|
# hardening, and everything after this one can break networking in some smaller
|
||||||
|
# way; having the tailnet up first means a mistake is recoverable rather than a
|
||||||
|
# trip to a rescue console.
|
||||||
|
#
|
||||||
|
# ── Why it matters to Officer specifically ──
|
||||||
|
#
|
||||||
|
# The platform's CLAUDE.md is explicit: the perimeter IS the tailnet.
|
||||||
|
# ALLOW_ANY_ORIGIN defaults ON, and that is only defensible because the machine is
|
||||||
|
# not reachable from the open internet in the first place — a valid token plus the
|
||||||
|
# tailnet is the lock. An Officer install with no tailnet is an Officer install
|
||||||
|
# with one fewer layer than it was designed around.
|
||||||
|
#
|
||||||
|
# ── Why the original hung ──
|
||||||
|
#
|
||||||
|
# It passed --authkey unconditionally, and its prompt accepted an empty answer.
|
||||||
|
# `tailscale up --authkey ""` falls back to interactive login: it prints a URL and
|
||||||
|
# blocks, with no timeout, forever. Nothing here passes an empty key, every call
|
||||||
|
# has a timeout, and the state is read before anything is run.
|
||||||
|
|
||||||
|
[[ -n "${MACHINE_SETUP_TAILSCALE_LOADED:-}" ]] && return 0
|
||||||
|
MACHINE_SETUP_TAILSCALE_LOADED=1
|
||||||
|
|
||||||
|
TS_EXIT_SYSCTL=/etc/sysctl.d/99-tailscale-exit.conf
|
||||||
|
TS_DISPATCHER=/etc/networkd-dispatcher/routable.d/50-tailscale-exit
|
||||||
|
|
||||||
|
tailscale_is_installed() { command -v tailscale &>/dev/null; }
|
||||||
|
|
||||||
|
# NeedsLogin, Running, Stopped, NoState… Read before acting, because the original's
|
||||||
|
# failure was running `up` blindly against a node that was already up.
|
||||||
|
tailscale_state() {
|
||||||
|
tailscale status --json 2>/dev/null | awk -F'"' '/"BackendState"/ { print $4; exit }'
|
||||||
|
}
|
||||||
|
|
||||||
|
tailscale_ip() { tailscale ip -4 2>/dev/null | head -1; }
|
||||||
|
|
||||||
|
# Which control plane this node is talking to. Empty means Tailscale's own.
|
||||||
|
tailscale_control_url() {
|
||||||
|
tailscale debug prefs 2>/dev/null | awk -F'"' '/"ControlURL"/ { print $4; exit }'
|
||||||
|
}
|
||||||
|
|
||||||
|
tailscale_install() { curl -fsSL https://tailscale.com/install.sh | sh; }
|
||||||
|
|
||||||
|
# Routing has to be on before this machine can forward anyone else's packets,
|
||||||
|
# whether as an exit node or as a subnet router. Written as a drop-in so it is
|
||||||
|
# visible as this script's doing.
|
||||||
|
enable_ip_forwarding() {
|
||||||
|
cat >"$TS_EXIT_SYSCTL" <<'EOF'
|
||||||
|
# Written by machine-setup: required to forward traffic for other tailnet nodes,
|
||||||
|
# as an exit node or as a subnet router.
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
|
net.ipv6.conf.all.forwarding = 1
|
||||||
|
EOF
|
||||||
|
sysctl --system >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# UDP GRO forwarding, which Tailscale documents as roughly doubling throughput on
|
||||||
|
# a node that forwards for others. Applied on every routable event rather than
|
||||||
|
# once, because the settings are per-interface and do not survive the link going
|
||||||
|
# down and back up.
|
||||||
|
install_exit_node_tuning() {
|
||||||
|
pkg_is_installed networkd-dispatcher || pkg_install_now networkd-dispatcher
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$TS_DISPATCHER")"
|
||||||
|
cat >"$TS_DISPATCHER" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Written by machine-setup. NIC offload settings for a Tailscale exit node or
|
||||||
|
# subnet router — Tailscale's own recommendation for forwarding throughput.
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
IF="${IFACE:-}"
|
||||||
|
if [[ -z "${IF}" ]]; then
|
||||||
|
IF="$(ip -o route get 8.8.8.8 2>/dev/null | awk '{for (i = 1; i <= NF; i++) if ($i == "dev") {print $(i + 1); exit}}')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -n "${IF}" ]] || exit 0
|
||||||
|
command -v ethtool >/dev/null 2>&1 || exit 0
|
||||||
|
|
||||||
|
ethtool -k "${IF}" 2>/dev/null | grep -q "^generic-receive-offload: " && ethtool -K "${IF}" gro on || true
|
||||||
|
ethtool -k "${IF}" 2>/dev/null | grep -q "^rx-udp-gro-forwarding: " && ethtool -K "${IF}" rx-udp-gro-forwarding on || true
|
||||||
|
ethtool -k "${IF}" 2>/dev/null | grep -q "^large-receive-offload: " && ethtool -K "${IF}" lro off || true
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
chmod 755 "$TS_DISPATCHER"
|
||||||
|
systemctl enable --now networkd-dispatcher >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# And once now, for the interface that is already up.
|
||||||
|
IFACE="$(default_iface)" bash "$TS_DISPATCHER" >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# The LAN this machine sits on, as a CIDR — the useful default for a subnet
|
||||||
|
# router, and the number nobody remembers offhand.
|
||||||
|
lan_cidr() {
|
||||||
|
local iface
|
||||||
|
iface="$(default_iface)"
|
||||||
|
ip -4 route show dev "$iface" 2>/dev/null |
|
||||||
|
awk '$1 ~ /\// && $1 !~ /^default/ { print $1; exit }'
|
||||||
|
}
|
||||||
@@ -13,6 +13,32 @@ set -e
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROGRESS_FILE="$SCRIPT_DIR/.setup-progress"
|
PROGRESS_FILE="$SCRIPT_DIR/.setup-progress"
|
||||||
|
|
||||||
|
# --only <step> runs one section and nothing else, for working on it. Pre-flight
|
||||||
|
# still runs, because every section needs what it establishes — the system, the
|
||||||
|
# role, the account and its home.
|
||||||
|
ONLY_STEP=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--only)
|
||||||
|
ONLY_STEP="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--only=*)
|
||||||
|
ONLY_STEP="${1#*=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-l | --list)
|
||||||
|
grep -oP '^step "\K[^"]+' "${BASH_SOURCE[0]}"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
echo "usage: machine-setup.sh [--only <step>] [--list]"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*) echo "unknown option: $1" >&2 && exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# Shared state, output helpers, the step/resume machine and OS detection. Kept in
|
# Shared state, output helpers, the step/resume machine and OS detection. Kept in
|
||||||
# lib/ so a step can eventually be read — or run — on its own without dragging the
|
# lib/ so a step can eventually be read — or run — on its own without dragging the
|
||||||
# whole script in. Definitions only; nothing in there acts.
|
# whole script in. Definitions only; nothing in there acts.
|
||||||
@@ -36,6 +62,8 @@ source "$SCRIPT_DIR/lib/network.sh"
|
|||||||
source "$SCRIPT_DIR/lib/dev.sh"
|
source "$SCRIPT_DIR/lib/dev.sh"
|
||||||
# shellcheck source=lib/docker.sh
|
# shellcheck source=lib/docker.sh
|
||||||
source "$SCRIPT_DIR/lib/docker.sh"
|
source "$SCRIPT_DIR/lib/docker.sh"
|
||||||
|
# shellcheck source=lib/tailscale.sh
|
||||||
|
source "$SCRIPT_DIR/lib/tailscale.sh"
|
||||||
|
|
||||||
# Trap errors with context. Installed here rather than in lib/base.sh, because
|
# Trap errors with context. Installed here rather than in lib/base.sh, because
|
||||||
# that file is definitions only and a trap is a side effect on whoever sources it.
|
# that file is definitions only and a trap is a side effect on whoever sources it.
|
||||||
@@ -357,7 +385,170 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 7. Locale
|
# 7. Tailscale
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# Placed here, before everything that can go wrong, because it is a second way
|
||||||
|
# into the machine. It needs curl, so it cannot come before core utils; it wants
|
||||||
|
# to come before SSH hardening, which is the step that can lock you out.
|
||||||
|
|
||||||
|
step "Tailscale"
|
||||||
|
if ! skip; then
|
||||||
|
echo ""
|
||||||
|
info "Tailscale — a private network between your machines, over WireGuard"
|
||||||
|
echo " Every device you enrol gets a stable 100.x address and can reach"
|
||||||
|
echo " every other, wherever they are. Nothing is published to the open"
|
||||||
|
echo " internet: no port forwarding, no exposed ports, no firewall holes."
|
||||||
|
echo ""
|
||||||
|
echo " For Officer this is not a convenience. The platform is built assuming"
|
||||||
|
echo " the tailnet IS the perimeter — ALLOW_ANY_ORIGIN defaults on, and that"
|
||||||
|
echo " is only defensible because the machine is not reachable from outside"
|
||||||
|
echo " in the first place. Installed here, before anything that can lock you"
|
||||||
|
echo " out, so there is always a second way in."
|
||||||
|
|
||||||
|
if ! tailscale_is_installed; then
|
||||||
|
echo ""
|
||||||
|
echo " not installed"
|
||||||
|
if confirm "Install Tailscale?"; then
|
||||||
|
tailscale_install
|
||||||
|
tailscale_is_installed && ok "$(tailscale version 2>/dev/null | head -1) installed"
|
||||||
|
else
|
||||||
|
warn "skipped by request"
|
||||||
|
SUMMARY+=("Tailscale: SKIPPED by request")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if tailscale_is_installed; then
|
||||||
|
TS_STATE="$(tailscale_state)"
|
||||||
|
TS_URL_NOW="$(tailscale_control_url)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " state: ${TS_STATE:-unknown}"
|
||||||
|
echo " control plane: ${TS_URL_NOW:-tailscale.com (the default service)}"
|
||||||
|
[[ "$TS_STATE" == "Running" ]] && echo " this machine: $(tailscale_ip) ($(hostname))"
|
||||||
|
|
||||||
|
TS_CONNECT=true
|
||||||
|
if [[ "$TS_STATE" == "Running" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo " Already connected. Reconnecting is only needed to change the"
|
||||||
|
echo " control plane or what this node advertises."
|
||||||
|
confirm "Reconfigure it?" n || TS_CONNECT=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$TS_CONNECT" == false ]]; then
|
||||||
|
SUMMARY+=("Tailscale: connected, unchanged ($(tailscale_ip))")
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
info "Which control plane?"
|
||||||
|
echo " [1] Tailscale's own service (tailscale.com)"
|
||||||
|
echo " [2] a self-hosted headscale"
|
||||||
|
echo ""
|
||||||
|
TS_LOGIN_SERVER=""
|
||||||
|
TS_PLANE=""
|
||||||
|
while [[ -z "$TS_PLANE" ]]; do
|
||||||
|
if ! read -rp " Which one? (1/2) [1]: " TS_PLANE_CHOICE; then
|
||||||
|
echo ""
|
||||||
|
fail "No answer."
|
||||||
|
fi
|
||||||
|
case "${TS_PLANE_CHOICE:-1}" in
|
||||||
|
1) TS_PLANE="tailscale" ;;
|
||||||
|
2)
|
||||||
|
# No default offered. A control-plane URL is somebody's private
|
||||||
|
# infrastructure, and a machine that joins the wrong tailnet has
|
||||||
|
# joined a stranger's network.
|
||||||
|
read -rp " headscale URL (e.g. https://headscale.example.com): " TS_LOGIN_SERVER || fail "No answer."
|
||||||
|
if [[ "$TS_LOGIN_SERVER" =~ ^https?:// ]]; then
|
||||||
|
TS_PLANE="headscale"
|
||||||
|
else
|
||||||
|
warn "That needs to be a full URL, starting with https://"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*) warn "Pick 1 or 2." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
info "How should this machine authenticate?"
|
||||||
|
echo " An auth key enrols it without a browser. Leaving this blank is"
|
||||||
|
echo " fine — Tailscale then prints a URL to open, and waits for you."
|
||||||
|
echo ""
|
||||||
|
read -rp " Auth key (blank for the browser flow): " TS_AUTHKEY || fail "No answer."
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
info "What should this machine offer the tailnet?"
|
||||||
|
echo ""
|
||||||
|
echo " Tailscale SSH — ssh to this machine over the tailnet with no keys"
|
||||||
|
echo " at all; who may connect is decided by your tailnet's ACLs rather"
|
||||||
|
echo " than by authorized_keys. Independent of the sshd hardening later"
|
||||||
|
echo " in this run, and a useful way back in if that goes wrong."
|
||||||
|
TS_SSH=""
|
||||||
|
confirm "Enable Tailscale SSH?" n && TS_SSH="--ssh"
|
||||||
|
|
||||||
|
TS_ROUTES=""
|
||||||
|
if is_role homelab; then
|
||||||
|
echo ""
|
||||||
|
echo " Subnet router — makes this machine a door onto its LAN, so"
|
||||||
|
echo " every tailnet device can reach the printers, NAS and switches"
|
||||||
|
echo " here without each of them running Tailscale."
|
||||||
|
LAN="$(lan_cidr)"
|
||||||
|
if [[ -n "$LAN" ]] && confirm "Advertise ${LAN} to the tailnet?" n; then
|
||||||
|
TS_ROUTES="--advertise-routes=${LAN}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " Exit node — lets other tailnet devices send ALL their internet"
|
||||||
|
echo " traffic out through this machine, as a VPN would. Useful from a"
|
||||||
|
echo " phone on hostile wifi; it means this machine's connection carries"
|
||||||
|
echo " their traffic, and their browsing exits from this IP."
|
||||||
|
TS_EXIT=""
|
||||||
|
confirm "Advertise as an exit node?" n && TS_EXIT="--advertise-exit-node"
|
||||||
|
|
||||||
|
if [[ -n "$TS_EXIT" || -n "$TS_ROUTES" ]]; then
|
||||||
|
echo ""
|
||||||
|
info " forwarding other machines' packets needs routing enabled — writing ${TS_EXIT_SYSCTL}"
|
||||||
|
enable_ip_forwarding
|
||||||
|
info " applying Tailscale's recommended NIC offload settings (roughly doubles forwarding throughput)"
|
||||||
|
install_exit_node_tuning
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
TS_ARGS=(up --timeout=60s)
|
||||||
|
[[ "$TS_PLANE" == "headscale" ]] && TS_ARGS+=(--login-server "$TS_LOGIN_SERVER")
|
||||||
|
# Never passed empty. `--authkey ""` silently falls back to the interactive
|
||||||
|
# flow and blocks forever, which is exactly how the original hung.
|
||||||
|
[[ -n "$TS_AUTHKEY" ]] && TS_ARGS+=(--authkey "$TS_AUTHKEY")
|
||||||
|
[[ -n "$TS_SSH" ]] && TS_ARGS+=("$TS_SSH")
|
||||||
|
[[ -n "$TS_ROUTES" ]] && TS_ARGS+=("$TS_ROUTES")
|
||||||
|
[[ -n "$TS_EXIT" ]] && TS_ARGS+=("$TS_EXIT")
|
||||||
|
|
||||||
|
if [[ -z "$TS_AUTHKEY" ]]; then
|
||||||
|
warn "no auth key given — a URL will be printed below, and this waits for you to open it"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if tailscale "${TS_ARGS[@]}"; then
|
||||||
|
TS_IP="$(tailscale_ip)"
|
||||||
|
ok "connected as ${TS_IP} on $(hostname)"
|
||||||
|
SUMMARY+=("Tailscale: ${TS_IP}${TS_SSH:+, Tailscale SSH}${TS_ROUTES:+, subnet router}${TS_EXIT:+, exit node}")
|
||||||
|
if [[ -n "$TS_EXIT" || -n "$TS_ROUTES" ]]; then
|
||||||
|
warn "an exit node or advertised route must be approved in the admin console before it carries traffic"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Loud rather than silent. The original had no timeout at all, so a
|
||||||
|
# failure to authenticate looked like the script having frozen.
|
||||||
|
warn "tailscale up did not complete within 60s"
|
||||||
|
echo " Run it by hand to see what it is waiting for: tailscale up"
|
||||||
|
ERRORS+=("Tailscale: up did not complete")
|
||||||
|
SUMMARY+=("Tailscale: NOT connected")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
step_ok
|
||||||
|
fi
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 8. Locale
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# LOCALE in the environment overrides the default.
|
# LOCALE in the environment overrides the default.
|
||||||
@@ -395,7 +586,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 8. Timezone
|
# 9. Timezone
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# TIMEZONE in the environment answers the prompt ahead of time.
|
# TIMEZONE in the environment answers the prompt ahead of time.
|
||||||
@@ -461,7 +652,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 9. Swap
|
# 10. Swap
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# Disk the kernel can park cold pages on when RAM fills, so a spike costs
|
# Disk the kernel can park cold pages on when RAM fills, so a spike costs
|
||||||
@@ -515,7 +706,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 10. Emergency disk ballast
|
# 11. Emergency disk ballast
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# Always offered, whatever the role — the role only decides which way the
|
# Always offered, whatever the role — the role only decides which way the
|
||||||
@@ -639,7 +830,7 @@ elif ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 11. earlyoom
|
# 12. earlyoom
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "earlyoom"
|
step "earlyoom"
|
||||||
@@ -674,7 +865,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 12. inotify watch limit
|
# 13. inotify watch limit
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "inotify watch limit"
|
step "inotify watch limit"
|
||||||
@@ -713,7 +904,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 13. Sleep and suspend
|
# 14. Sleep and suspend
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "Sleep and suspend"
|
step "Sleep and suspend"
|
||||||
@@ -781,7 +972,7 @@ elif ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 14. Boot hang
|
# 15. Boot hang
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "Boot hang"
|
step "Boot hang"
|
||||||
@@ -837,7 +1028,7 @@ elif ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 15. SSH access
|
# 16. SSH access
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# Keys and hardening in one section, deliberately. They were two in the original,
|
# Keys and hardening in one section, deliberately. They were two in the original,
|
||||||
@@ -951,7 +1142,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 16. DNS
|
# 17. DNS
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "DNS"
|
step "DNS"
|
||||||
@@ -1044,7 +1235,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 17. Network address
|
# 18. Network address
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# Homelab only. On a vps the provider's DHCP is authoritative and already stable,
|
# Homelab only. On a vps the provider's DHCP is authoritative and already stable,
|
||||||
@@ -1175,7 +1366,7 @@ elif ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 18. fail2ban
|
# 19. fail2ban
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# Installed as part of core utils rather than here — it is a distro package and
|
# Installed as part of core utils rather than here — it is a distro package and
|
||||||
@@ -1208,7 +1399,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 19. Unattended upgrades
|
# 20. Unattended upgrades
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
#
|
#
|
||||||
# The package comes from core utils. This makes sure it is actually switched on,
|
# The package comes from core utils. This makes sure it is actually switched on,
|
||||||
@@ -1272,7 +1463,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 20. Git
|
# 21. Git
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "Git"
|
step "Git"
|
||||||
@@ -1352,7 +1543,7 @@ if ! skip; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 21. Docker
|
# 22. Docker
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
step "Docker"
|
step "Docker"
|
||||||
@@ -1485,7 +1676,7 @@ fi
|
|||||||
#
|
#
|
||||||
# Sections still to move across from scripts/setup-old/setup-ubuntu.sh, in order:
|
# Sections still to move across from scripts/setup-old/setup-ubuntu.sh, in order:
|
||||||
#
|
#
|
||||||
# zsh + prompt (incl. .tmux.conf) · tailscale · neovim · js runtimes ·
|
# zsh + prompt (incl. .tmux.conf) · neovim · js runtimes ·
|
||||||
# dev tools · ufw · zshrc
|
# dev tools · ufw · zshrc
|
||||||
#
|
#
|
||||||
# And one that is new rather than ported, to come last of all:
|
# And one that is new rather than ported, to come last of all:
|
||||||
@@ -1500,7 +1691,7 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 15. Summary
|
# 23. Summary
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user