Last active 3 weeks ago

beanman109 revised this gist 3 weeks ago. Go to revision

1 file changed, 0 insertions, 0 deletions

readme.md renamed to 0 - readme.md

File renamed without changes

beanman109 revised this gist 1 month ago. Go to revision

No changes

beanman109 revised this gist 1 month ago. Go to revision

1 file changed, 1 insertion

readme.md(file created)

@@ -0,0 +1 @@
1 + wget -qO- 'https://beanman.net/gist/beanman109/debian-13-initial-setup/raw/HEAD/debian-13-initial-setup.sh' | bash

beanman109 revised this gist 1 month ago. Go to revision

1 file changed, 0 insertions, 0 deletions

debian-13-initial-setup renamed to debian-13-initial-setup.sh

File renamed without changes

beanman109 revised this gist 1 month ago. Go to revision

1 file changed, 352 insertions

debian-13-initial-setup(file created)

@@ -0,0 +1,352 @@
1 + #!/usr/bin/env bash
2 + set -euo pipefail
3 +
4 + # ============================================================
5 + # Debian 13 VPS Initial Setup Script
6 + #
7 + # Includes:
8 + # 1. Base update + useful tools
9 + # 2. Chrony time sync
10 + # 3. Fail2ban
11 + # 4. Automatic security updates
12 + # 5. Kernel/network tuning
13 + # 6. Journald log limits
14 + # 7. Locale
15 + # 8. Reboot-required check
16 + # ============================================================
17 +
18 + export DEBIAN_FRONTEND=noninteractive
19 +
20 + # -----------------------------
21 + # Config
22 + # -----------------------------
23 +
24 + TIMEZONE="UTC"
25 +
26 + # Change this if you prefer en_AU.UTF-8 or en_NZ.UTF-8
27 + LOCALE_NAME="en_US.UTF-8"
28 +
29 + # Journald limits
30 + JOURNAL_SYSTEM_MAX_USE="500M"
31 + JOURNAL_RUNTIME_MAX_USE="100M"
32 + JOURNAL_MAX_RETENTION="1month"
33 +
34 + # Fail2ban SSH settings
35 + FAIL2BAN_MAXRETRY="5"
36 + FAIL2BAN_FINDTIME="10m"
37 + FAIL2BAN_BANTIME="1h"
38 +
39 + # -----------------------------
40 + # Helpers
41 + # -----------------------------
42 +
43 + log() {
44 + echo
45 + echo "============================================================"
46 + echo "$1"
47 + echo "============================================================"
48 + }
49 +
50 + warn() {
51 + echo
52 + echo "WARNING: $1"
53 + }
54 +
55 + require_root() {
56 + if [ "$(id -u)" -ne 0 ]; then
57 + echo "This script must be run as root."
58 + exit 1
59 + fi
60 + }
61 +
62 + detect_debian() {
63 + if [ ! -f /etc/os-release ]; then
64 + warn "Cannot detect OS because /etc/os-release is missing."
65 + return
66 + fi
67 +
68 + . /etc/os-release
69 +
70 + echo "Detected OS: ${PRETTY_NAME:-unknown}"
71 +
72 + if [ "${ID:-}" != "debian" ]; then
73 + warn "This script is intended for Debian. Continuing anyway."
74 + fi
75 +
76 + if [ "${VERSION_ID:-}" != "13" ]; then
77 + warn "This script is intended for Debian 13. Detected VERSION_ID=${VERSION_ID:-unknown}. Continuing anyway."
78 + fi
79 + }
80 +
81 + safe_systemctl_enable_now() {
82 + local service="$1"
83 +
84 + if systemctl list-unit-files "$service" >/dev/null 2>&1; then
85 + systemctl enable --now "$service"
86 + else
87 + warn "Service $service not found, skipping enable/start."
88 + fi
89 + }
90 +
91 + # -----------------------------
92 + # Start
93 + # -----------------------------
94 +
95 + require_root
96 + detect_debian
97 +
98 + log "Step 1/8: Updating APT package lists and upgrading system"
99 +
100 + apt-get update
101 + apt-get upgrade -y
102 +
103 + log "Step 1/8: Installing base useful packages"
104 +
105 + apt-get install -y \
106 + apt-transport-https \
107 + bash-completion \
108 + btop \
109 + ca-certificates \
110 + curl \
111 + dnsutils \
112 + git \
113 + gnupg \
114 + htop \
115 + iftop \
116 + iotop \
117 + iproute2 \
118 + jq \
119 + less \
120 + lsb-release \
121 + lsof \
122 + nano \
123 + ncdu \
124 + net-tools \
125 + openssh-client \
126 + openssh-server \
127 + rsync \
128 + screen \
129 + strace \
130 + sudo \
131 + tar \
132 + tcpdump \
133 + tmux \
134 + tree \
135 + unzip \
136 + vim \
137 + wget \
138 + zip
139 +
140 + log "Step 2/8: Installing and enabling Chrony time sync"
141 +
142 + apt-get install -y chrony
143 +
144 + timedatectl set-timezone "$TIMEZONE" || warn "Could not set timezone to $TIMEZONE"
145 +
146 + safe_systemctl_enable_now chrony.service
147 +
148 + echo
149 + echo "Current time status:"
150 + timedatectl || true
151 +
152 + log "Step 3/8: Installing and configuring Fail2ban"
153 +
154 + apt-get install -y fail2ban
155 +
156 + mkdir -p /etc/fail2ban/jail.d
157 +
158 + cat >/etc/fail2ban/jail.d/sshd.local <<EOF
159 + [sshd]
160 + enabled = true
161 + port = ssh
162 + filter = sshd
163 + backend = systemd
164 + maxretry = ${FAIL2BAN_MAXRETRY}
165 + findtime = ${FAIL2BAN_FINDTIME}
166 + bantime = ${FAIL2BAN_BANTIME}
167 + EOF
168 +
169 + safe_systemctl_enable_now fail2ban.service
170 +
171 + systemctl restart fail2ban || warn "Could not restart fail2ban."
172 +
173 + echo
174 + echo "Fail2ban SSH jail status:"
175 + fail2ban-client status sshd || true
176 +
177 + log "Step 4/8: Installing and configuring automatic security updates"
178 +
179 + apt-get install -y unattended-upgrades apt-listchanges needrestart
180 +
181 + cat >/etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
182 + APT::Periodic::Update-Package-Lists "1";
183 + APT::Periodic::Unattended-Upgrade "1";
184 + APT::Periodic::AutocleanInterval "7";
185 + APT::Periodic::Verbose "1";
186 + EOF
187 +
188 + cat >/etc/apt/apt.conf.d/51unattended-upgrades-local <<'EOF'
189 + Unattended-Upgrade::Origins-Pattern {
190 + "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
191 + "origin=Debian,codename=${distro_codename},label=Debian";
192 + };
193 +
194 + Unattended-Upgrade::Package-Blacklist {
195 + };
196 +
197 + Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
198 + Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
199 + Unattended-Upgrade::Remove-Unused-Dependencies "false";
200 +
201 + Unattended-Upgrade::Automatic-Reboot "false";
202 + Unattended-Upgrade::SyslogEnable "true";
203 + EOF
204 +
205 + systemctl restart unattended-upgrades || true
206 + safe_systemctl_enable_now unattended-upgrades.service
207 +
208 + echo
209 + echo "Testing unattended-upgrades config:"
210 + unattended-upgrade --dry-run --debug || warn "unattended-upgrades dry run returned a warning/error. Review output above."
211 +
212 + log "Step 5/8: Applying kernel and network tuning"
213 +
214 + cat >/etc/sysctl.d/99-vps-tuning.conf <<'EOF'
215 + # ============================================================
216 + # VPS kernel/network tuning
217 + # ============================================================
218 +
219 + # Use fair queueing. Recommended with BBR.
220 + net.core.default_qdisc = fq
221 +
222 + # Enable BBR congestion control.
223 + net.ipv4.tcp_congestion_control = bbr
224 +
225 + # Enable TCP Fast Open.
226 + net.ipv4.tcp_fastopen = 3
227 +
228 + # Do not act as a router by default.
229 + net.ipv4.ip_forward = 0
230 + net.ipv6.conf.all.forwarding = 0
231 +
232 + # Basic anti-spoofing / safer IPv4 behaviour.
233 + net.ipv4.conf.all.rp_filter = 1
234 + net.ipv4.conf.default.rp_filter = 1
235 +
236 + # Ignore ICMP redirects.
237 + net.ipv4.conf.all.accept_redirects = 0
238 + net.ipv4.conf.default.accept_redirects = 0
239 + net.ipv6.conf.all.accept_redirects = 0
240 + net.ipv6.conf.default.accept_redirects = 0
241 +
242 + # Do not send ICMP redirects.
243 + net.ipv4.conf.all.send_redirects = 0
244 + net.ipv4.conf.default.send_redirects = 0
245 +
246 + # Ignore source-routed packets.
247 + net.ipv4.conf.all.accept_source_route = 0
248 + net.ipv4.conf.default.accept_source_route = 0
249 + net.ipv6.conf.all.accept_source_route = 0
250 + net.ipv6.conf.default.accept_source_route = 0
251 +
252 + # Log suspicious martian packets.
253 + net.ipv4.conf.all.log_martians = 1
254 + net.ipv4.conf.default.log_martians = 1
255 +
256 + # Reasonable file handle limit.
257 + fs.file-max = 2097152
258 +
259 + # Reasonable memory behaviour for small VPSes.
260 + vm.swappiness = 10
261 + vm.vfs_cache_pressure = 50
262 + EOF
263 +
264 + sysctl --system
265 +
266 + echo
267 + echo "Current TCP congestion control:"
268 + sysctl net.ipv4.tcp_congestion_control || true
269 +
270 + echo
271 + echo "Available TCP congestion controls:"
272 + sysctl net.ipv4.tcp_available_congestion_control || true
273 +
274 + log "Step 6/8: Setting journald log size limits"
275 +
276 + mkdir -p /etc/systemd/journald.conf.d
277 +
278 + cat >/etc/systemd/journald.conf.d/99-vps-limits.conf <<EOF
279 + [Journal]
280 + SystemMaxUse=${JOURNAL_SYSTEM_MAX_USE}
281 + RuntimeMaxUse=${JOURNAL_RUNTIME_MAX_USE}
282 + MaxRetentionSec=${JOURNAL_MAX_RETENTION}
283 + Compress=yes
284 + EOF
285 +
286 + systemctl restart systemd-journald
287 +
288 + echo
289 + echo "Current journal disk usage:"
290 + journalctl --disk-usage || true
291 +
292 + log "Step 7/8: Configuring locale"
293 +
294 + apt-get install -y locales
295 +
296 + if grep -q "^# *${LOCALE_NAME} UTF-8" /etc/locale.gen; then
297 + sed -i "s/^# *${LOCALE_NAME} UTF-8/${LOCALE_NAME} UTF-8/" /etc/locale.gen
298 + elif ! grep -q "^${LOCALE_NAME} UTF-8" /etc/locale.gen; then
299 + echo "${LOCALE_NAME} UTF-8" >> /etc/locale.gen
300 + fi
301 +
302 + locale-gen
303 + update-locale LANG="$LOCALE_NAME"
304 +
305 + echo
306 + echo "Configured locale:"
307 + localectl status || true
308 +
309 + log "Cleaning up packages"
310 +
311 + apt-get autoremove -y
312 + apt-get autoclean -y
313 +
314 + log "Step 8/8: Reboot-required check"
315 +
316 + REBOOT_REQUIRED="no"
317 +
318 + if [ -f /var/run/reboot-required ]; then
319 + REBOOT_REQUIRED="yes"
320 + fi
321 +
322 + if command -v needrestart >/dev/null 2>&1; then
323 + echo
324 + echo "needrestart summary:"
325 + needrestart -b || true
326 + fi
327 +
328 + echo
329 + echo "============================================================"
330 + echo "Debian 13 VPS initial setup complete."
331 + echo "============================================================"
332 + echo "Timezone: $TIMEZONE"
333 + echo "Locale: $LOCALE_NAME"
334 + echo "Reboot required: $REBOOT_REQUIRED"
335 + echo
336 +
337 + if [ "$REBOOT_REQUIRED" = "yes" ]; then
338 + echo "A reboot is recommended:"
339 + echo " reboot"
340 + else
341 + echo "No reboot-required flag detected."
342 + fi
343 +
344 + echo
345 + echo "Useful checks:"
346 + echo " systemctl status chrony"
347 + echo " systemctl status fail2ban"
348 + echo " fail2ban-client status sshd"
349 + echo " systemctl status unattended-upgrades"
350 + echo " journalctl --disk-usage"
351 + echo " sysctl net.ipv4.tcp_congestion_control"
352 + echo
Newer Older