614 lines
17 KiB
Django/Jinja
614 lines
17 KiB
Django/Jinja
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Generated at: {{ meta.generated_at }}
|
|
|
|
if [[ "${EUID}" -ne 0 ]]; then
|
|
echo "Run as root: sudo bash $0"
|
|
exit 1
|
|
fi
|
|
|
|
log() { echo "[setup] $*"; }
|
|
|
|
ensure_pkg() {
|
|
local pkg="$1"
|
|
if ! dpkg -s "$pkg" >/dev/null 2>&1; then
|
|
apt-get update -y
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y "$pkg"
|
|
fi
|
|
}
|
|
|
|
backup_file() {
|
|
local f="$1"
|
|
if [[ -f "$f" ]]; then
|
|
cp -a "$f" "${f}.bak.$(date +%Y%m%d%H%M%S)"
|
|
fi
|
|
}
|
|
|
|
{% if flags.install_docker %}
|
|
install_docker() {
|
|
log "Installing Docker + compose plugin"
|
|
ensure_pkg ca-certificates
|
|
ensure_pkg curl
|
|
ensure_pkg gnupg
|
|
ensure_pkg lsb-release
|
|
ensure_pkg acl
|
|
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then
|
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
fi
|
|
|
|
local codename
|
|
codename="$(. /etc/os-release && echo "$VERSION_CODENAME")"
|
|
|
|
cat >/etc/apt/sources.list.d/docker.list <<EOF
|
|
deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${codename} stable
|
|
EOF
|
|
|
|
apt-get update -y
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
|
|
# Configure Docker to use custom data directory if specified
|
|
{% if flags.docker_admin_user %}
|
|
local docker_dir="{{ params.docker_data_dir }}"
|
|
if [[ -d "${docker_dir}" ]]; then
|
|
log "Configuring Docker to use custom data directory: ${docker_dir}"
|
|
mkdir -p /etc/docker
|
|
backup_file /etc/docker/daemon.json
|
|
|
|
# Create or update daemon.json
|
|
if [[ -f /etc/docker/daemon.json ]]; then
|
|
# Use jq if available, otherwise use sed/python fallback
|
|
if command -v jq >/dev/null 2>&1; then
|
|
jq ". + {\"data-root\": \"${docker_dir}\"}" /etc/docker/daemon.json > /tmp/daemon.json.tmp && mv /tmp/daemon.json.tmp /etc/docker/daemon.json
|
|
else
|
|
# Fallback: create new daemon.json with data-root
|
|
cat >/etc/docker/daemon.json <<EOF
|
|
{
|
|
"data-root": "${docker_dir}"
|
|
}
|
|
EOF
|
|
fi
|
|
else
|
|
cat >/etc/docker/daemon.json <<EOF
|
|
{
|
|
"data-root": "${docker_dir}"
|
|
}
|
|
EOF
|
|
fi
|
|
chmod 644 /etc/docker/daemon.json
|
|
log "Docker daemon.json configured. Restart Docker to apply: systemctl restart docker"
|
|
fi
|
|
{% endif %}
|
|
|
|
systemctl enable --now docker
|
|
log "Docker installed"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.docker_admin_user %}
|
|
create_docker_admin_user() {
|
|
local user="{{ params.admin_username }}"
|
|
log "Creating docker operator user: ${user} (non-login)"
|
|
if ! id "${user}" >/dev/null 2>&1; then
|
|
# system user, no home by default; create home only if you want it
|
|
useradd --system --create-home --home-dir "/home/${user}" --shell /usr/sbin/nologin "${user}"
|
|
fi
|
|
|
|
# docker group exists after docker install; create if missing
|
|
if ! getent group docker >/dev/null 2>&1; then
|
|
groupadd docker
|
|
fi
|
|
|
|
usermod -aG docker "${user}"
|
|
|
|
# Create docker data directory with restricted permissions
|
|
local docker_dir="{{ params.docker_data_dir }}"
|
|
log "Creating docker data directory: ${docker_dir}"
|
|
|
|
# Create directory if it doesn't exist
|
|
if [[ ! -d "${docker_dir}" ]]; then
|
|
mkdir -p "${docker_dir}"
|
|
fi
|
|
|
|
# Set ownership to docker user and docker group
|
|
chown -R "${user}:docker" "${docker_dir}"
|
|
|
|
# Set permissions: owner (rwx), group (rwx), others (no access)
|
|
chmod 770 "${docker_dir}"
|
|
|
|
# Set ACL to ensure only docker user and docker group have access
|
|
ensure_pkg acl
|
|
setfacl -R -m u:"${user}":rwx "${docker_dir}"
|
|
setfacl -R -m g:docker:rwx "${docker_dir}"
|
|
setfacl -R -m o::--- "${docker_dir}"
|
|
setfacl -R -d -m u:"${user}":rwx "${docker_dir}"
|
|
setfacl -R -d -m g:docker:rwx "${docker_dir}"
|
|
setfacl -R -d -m o::--- "${docker_dir}"
|
|
|
|
log "Docker directory ${docker_dir} created with restricted permissions for ${user}"
|
|
|
|
# Optional: allow admins to run docker as that user using sudo
|
|
# This does NOT allow interactive login to the user.
|
|
cat >/etc/sudoers.d/90-docker-operator <<EOF
|
|
# Allow members of sudo group to run docker commands as {{ params.admin_username }}
|
|
%sudo ALL=( {{ params.admin_username }} ) NOPASSWD: /usr/bin/docker, /usr/bin/docker-compose, /usr/bin/docker-*
|
|
EOF
|
|
chmod 0440 /etc/sudoers.d/90-docker-operator
|
|
|
|
log "Docker operator user configured"
|
|
log "NOTE: To use custom docker directory, configure Docker daemon.json:"
|
|
log " { \"data-root\": \"${docker_dir}\" }"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.open_ports %}
|
|
setup_firewall() {
|
|
log "Configuring UFW firewall"
|
|
ensure_pkg ufw
|
|
|
|
ufw --force reset
|
|
ufw default deny incoming
|
|
ufw default allow outgoing
|
|
|
|
{% for p in params.ports %}
|
|
ufw allow {{ p }}/tcp
|
|
{% endfor %}
|
|
|
|
ufw --force enable
|
|
ufw status verbose || true
|
|
log "UFW configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.combine_lan %}
|
|
setup_netplan_bond_bridge() {
|
|
log "Writing netplan for bond+bridge (static IP)"
|
|
|
|
# WARNING: This can lock you out if done over SSH on a remote host.
|
|
# Make sure you have console/iLO/IPMI access or test carefully.
|
|
|
|
local ifaces=( {% for i in params.lan_ifaces %}"{{ i }}"{% if not loop.last %} {% endif %}{% endfor %} )
|
|
|
|
# Basic validation
|
|
for i in "${ifaces[@]}"; do
|
|
if ! ip link show "$i" >/dev/null 2>&1; then
|
|
echo "Interface not found: $i"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
backup_file /etc/netplan/01-lan.yaml
|
|
|
|
cat >/etc/netplan/01-lan.yaml <<'EOF'
|
|
network:
|
|
version: 2
|
|
renderer: networkd
|
|
|
|
ethernets:
|
|
{% for i in params.lan_ifaces %}
|
|
{{ i }}:
|
|
dhcp4: false
|
|
{% endfor %}
|
|
|
|
bonds:
|
|
bond0:
|
|
interfaces:
|
|
{% for i in params.lan_ifaces %}
|
|
- {{ i }}
|
|
{% endfor %}
|
|
parameters:
|
|
mode: 802.3ad
|
|
mii-monitor-interval: 100
|
|
|
|
bridges:
|
|
br0:
|
|
interfaces:
|
|
- bond0
|
|
addresses:
|
|
- {{ params.static_ip_cidr }}
|
|
routes:
|
|
- to: default
|
|
via: {{ params.gateway_ip }}
|
|
nameservers:
|
|
addresses:
|
|
{% for d in params.dns %}
|
|
- {{ d }}
|
|
{% endfor %}
|
|
EOF
|
|
|
|
netplan generate
|
|
netplan apply
|
|
log "Netplan applied"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.prelogin_banner %}
|
|
setup_prelogin_banner() {
|
|
log "Configuring SSH pre-login banner"
|
|
ensure_pkg openssh-server
|
|
|
|
# Use /etc/issue.net for SSH Banner
|
|
cat >/etc/issue.net <<'EOF'
|
|
{{ params.prelogin_text }}
|
|
EOF
|
|
|
|
# Replace owner placeholders with actual values
|
|
sed -i "s|\[OWNER_NAME\]|{{ params.owner_name }}|g" /etc/issue.net
|
|
sed -i "s|\[OWNER_WEBSITE\]|{{ params.owner_website }}|g" /etc/issue.net
|
|
sed -i "s|\[OWNER_EMAIL\]|{{ params.owner_email }}|g" /etc/issue.net
|
|
|
|
backup_file /etc/ssh/sshd_config
|
|
|
|
# Ensure Banner points to /etc/issue.net
|
|
if grep -qE '^\s*Banner\s+' /etc/ssh/sshd_config; then
|
|
sed -i 's|^\s*Banner\s\+.*|Banner /etc/issue.net|' /etc/ssh/sshd_config
|
|
else
|
|
echo "Banner /etc/issue.net" >> /etc/ssh/sshd_config
|
|
fi
|
|
|
|
systemctl restart ssh
|
|
log "Pre-login banner configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.postlogin_banner %}
|
|
setup_postlogin_banner() {
|
|
log "Configuring post-login MOTD"
|
|
# Simple approach: overwrite /etc/motd
|
|
cat >/etc/motd <<'EOF'
|
|
{{ params.postlogin_text }}
|
|
EOF
|
|
|
|
# Replace owner placeholders with actual values
|
|
sed -i "s|\[OWNER_NAME\]|{{ params.owner_name }}|g" /etc/motd
|
|
sed -i "s|\[OWNER_WEBSITE\]|{{ params.owner_website }}|g" /etc/motd
|
|
sed -i "s|\[OWNER_EMAIL\]|{{ params.owner_email }}|g" /etc/motd
|
|
|
|
log "Post-login banner configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.ssh_2fa %}
|
|
install_google_authenticator() {
|
|
log "Installing Google Authenticator (PAM module)"
|
|
|
|
# Only install the package, do not configure it
|
|
ensure_pkg libpam-google-authenticator
|
|
|
|
log "Google Authenticator installed. Manual configuration required."
|
|
log "To configure 2FA, users must run: google-authenticator"
|
|
log "Then configure PAM and SSH settings manually."
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.system_update %}
|
|
system_update() {
|
|
log "Updating system packages"
|
|
apt-get update -y
|
|
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
|
|
DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y
|
|
apt-get autoremove -y
|
|
apt-get autoclean -y
|
|
log "System updated"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.auto_security_updates %}
|
|
setup_auto_security_updates() {
|
|
log "Configuring automatic security updates"
|
|
ensure_pkg unattended-upgrades
|
|
|
|
# Enable automatic security updates
|
|
cat >/etc/apt/apt.conf.d/50unattended-upgrades <<'EOF'
|
|
Unattended-Upgrade::Allowed-Origins {
|
|
"${distro_id}:${distro_codename}-security";
|
|
"${distro_id}ESMApps:${distro_codename}-apps-security";
|
|
"${distro_id}ESM:${distro_codename}-infra-security";
|
|
};
|
|
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
|
Unattended-Upgrade::MinimalSteps "true";
|
|
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Automatic-Reboot "false";
|
|
EOF
|
|
|
|
# Enable automatic updates
|
|
echo 'APT::Periodic::Update-Package-Lists "1";' > /etc/apt/apt.conf.d/20auto-upgrades
|
|
echo 'APT::Periodic::Unattended-Upgrade "1";' >> /etc/apt/apt.conf.d/20auto-upgrades
|
|
|
|
systemctl enable unattended-upgrades
|
|
systemctl restart unattended-upgrades
|
|
log "Automatic security updates configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.setup_timezone %}
|
|
setup_timezone() {
|
|
log "Setting timezone to {{ params.timezone }}"
|
|
ensure_pkg tzdata
|
|
timedatectl set-timezone {{ params.timezone }}
|
|
log "Timezone configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.setup_hostname %}
|
|
setup_hostname() {
|
|
{% if params.hostname %}
|
|
log "Setting hostname to {{ params.hostname }}"
|
|
hostnamectl set-hostname {{ params.hostname }}
|
|
echo "127.0.0.1 {{ params.hostname }}" >> /etc/hosts
|
|
log "Hostname configured"
|
|
{% else %}
|
|
log "Skipping hostname setup (not specified)"
|
|
{% endif %}
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.setup_ntp %}
|
|
setup_ntp() {
|
|
log "Configuring NTP time synchronization"
|
|
ensure_pkg chrony
|
|
|
|
# Configure chrony with reliable time servers
|
|
backup_file /etc/chrony/chrony.conf
|
|
cat >/etc/chrony/chrony.conf <<'EOF'
|
|
pool 0.pool.ntp.org iburst
|
|
pool 1.pool.ntp.org iburst
|
|
pool 2.pool.ntp.org iburst
|
|
pool 3.pool.ntp.org iburst
|
|
|
|
# Record the rate at which the system clock gains/losses time
|
|
driftfile /var/lib/chrony/drift
|
|
|
|
# Allow the system clock to be stepped in the first three updates
|
|
makestep 1.0 3
|
|
|
|
# Enable kernel synchronization of the real-time clock
|
|
rtcsync
|
|
|
|
# Enable hardware timestamping on all interfaces
|
|
#hwtimestamp *
|
|
|
|
# Increase the minimum number of selectable sources
|
|
#minsources 2
|
|
|
|
# Allow NTP client access from local network
|
|
#allow 192.168.0.0/16
|
|
|
|
# Serve time even if not synchronized to a time source
|
|
#local stratum 10
|
|
|
|
# Specify file containing keys for NTP authentication
|
|
keyfile /etc/chrony/chrony.keys
|
|
|
|
# Save the drift between the system clock and the hardware clock
|
|
#initstepslew 10 client1.example.com client2.example.com
|
|
|
|
# Get TAI-UTC offset and leap seconds from the system tz database
|
|
leapsectz right/UTC
|
|
EOF
|
|
|
|
systemctl enable chronyd
|
|
systemctl restart chronyd
|
|
chronyc sources
|
|
log "NTP configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.setup_swap %}
|
|
setup_swap() {
|
|
log "Configuring swap file ({{ params.swap_size_gb }}GB)"
|
|
|
|
# Swap Configuration Explanation:
|
|
# Swap is virtual memory stored on disk. When RAM is full, Linux moves
|
|
# less-used data to swap to free up RAM. This prevents "out of memory"
|
|
# crashes but is slower than RAM. Swappiness (0-100) controls how
|
|
# aggressively Linux uses swap. Lower values (10) prefer RAM, higher (60+)
|
|
# use swap more aggressively. For servers, 10 is recommended.
|
|
|
|
# Check if swap already exists
|
|
if swapon --show | grep -q "/swapfile"; then
|
|
log "Swap file already exists, skipping"
|
|
return
|
|
fi
|
|
|
|
# Create swap file
|
|
fallocate -l {{ params.swap_size_gb }}G /swapfile || dd if=/dev/zero of=/swapfile bs=1G count={{ params.swap_size_gb }}
|
|
chmod 600 /swapfile
|
|
mkswap /swapfile
|
|
swapon /swapfile
|
|
|
|
# Make swap permanent
|
|
if ! grep -q "/swapfile" /etc/fstab; then
|
|
echo "/swapfile none swap sw 0 0" >> /etc/fstab
|
|
fi
|
|
|
|
# Configure swappiness (10 = less aggressive, 60 = default)
|
|
# Lower value = prefer RAM, higher = use swap more
|
|
if ! grep -q "vm.swappiness" /etc/sysctl.conf; then
|
|
echo "vm.swappiness=10" >> /etc/sysctl.conf
|
|
sysctl vm.swappiness=10
|
|
fi
|
|
|
|
log "Swap file configured ({{ params.swap_size_gb }}GB, swappiness=10)"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.ssh_harden %}
|
|
harden_ssh() {
|
|
log "Hardening SSH configuration"
|
|
ensure_pkg openssh-server
|
|
|
|
backup_file /etc/ssh/sshd_config
|
|
|
|
# Disable root login
|
|
sed -i 's|^#*PermitRootLogin.*|PermitRootLogin no|' /etc/ssh/sshd_config
|
|
|
|
# Change SSH port if specified
|
|
{% if params.ssh_port != 22 %}
|
|
sed -i "s|^#*Port.*|Port {{ params.ssh_port }}|" /etc/ssh/sshd_config
|
|
{% endif %}
|
|
|
|
# Security settings
|
|
sed -i 's|^#*PasswordAuthentication.*|PasswordAuthentication yes|' /etc/ssh/sshd_config
|
|
sed -i 's|^#*PubkeyAuthentication.*|PubkeyAuthentication yes|' /etc/ssh/sshd_config
|
|
sed -i 's|^#*PermitEmptyPasswords.*|PermitEmptyPasswords no|' /etc/ssh/sshd_config
|
|
sed -i 's|^#*MaxAuthTries.*|MaxAuthTries 3|' /etc/ssh/sshd_config
|
|
sed -i 's|^#*ClientAliveInterval.*|ClientAliveInterval 300|' /etc/ssh/sshd_config
|
|
sed -i 's|^#*ClientAliveCountMax.*|ClientAliveCountMax 2|' /etc/ssh/sshd_config
|
|
|
|
# Disable X11 forwarding for security
|
|
sed -i 's|^#*X11Forwarding.*|X11Forwarding no|' /etc/ssh/sshd_config
|
|
|
|
# Use only strong ciphers
|
|
if ! grep -q "^Ciphers" /etc/ssh/sshd_config; then
|
|
echo "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" >> /etc/ssh/sshd_config
|
|
fi
|
|
|
|
systemctl restart ssh
|
|
log "SSH hardened"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.install_fail2ban %}
|
|
install_fail2ban() {
|
|
log "Installing and configuring Fail2ban"
|
|
ensure_pkg fail2ban
|
|
|
|
# Create local jail configuration
|
|
cat >/etc/fail2ban/jail.local <<EOF
|
|
[DEFAULT]
|
|
bantime = 3600
|
|
findtime = 600
|
|
maxretry = 5
|
|
destemail = root@localhost
|
|
sendername = Fail2Ban
|
|
action = %(action_)s
|
|
|
|
[sshd]
|
|
enabled = true
|
|
port = {{ params.ssh_port }}
|
|
logpath = %(sshd_log)s
|
|
backend = %(sshd_backend)s
|
|
maxretry = 3
|
|
bantime = 7200
|
|
EOF
|
|
|
|
systemctl enable fail2ban
|
|
systemctl restart fail2ban
|
|
fail2ban-client status
|
|
log "Fail2ban configured"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.create_admin_user %}
|
|
create_admin_user() {
|
|
log "Creating admin user: {{ params.new_admin_username }}"
|
|
|
|
if id "{{ params.new_admin_username }}" >/dev/null 2>&1; then
|
|
log "User {{ params.new_admin_username }} already exists"
|
|
else
|
|
# Create user with sudo access
|
|
useradd -m -s /bin/bash {{ params.new_admin_username }}
|
|
usermod -aG sudo {{ params.new_admin_username }}
|
|
|
|
# Create .ssh directory
|
|
mkdir -p /home/{{ params.new_admin_username }}/.ssh
|
|
chmod 700 /home/{{ params.new_admin_username }}/.ssh
|
|
|
|
# Add SSH public keys if provided
|
|
{% if params.ssh_public_keys %}
|
|
cat >/home/{{ params.new_admin_username }}/.ssh/authorized_keys <<'EOF'
|
|
{% for key in params.ssh_public_keys %}
|
|
{{ key }}
|
|
{% endfor %}
|
|
EOF
|
|
chmod 600 /home/{{ params.new_admin_username }}/.ssh/authorized_keys
|
|
chown -R {{ params.new_admin_username }}:{{ params.new_admin_username }} /home/{{ params.new_admin_username }}/.ssh
|
|
log "SSH keys added for {{ params.new_admin_username }}"
|
|
{% else %}
|
|
log "No SSH keys provided - user will need to set password or add keys manually"
|
|
{% endif %}
|
|
|
|
log "Admin user {{ params.new_admin_username }} created with sudo access"
|
|
log "IMPORTANT: Set a password with: passwd {{ params.new_admin_username }}"
|
|
fi
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.install_monitoring_tools %}
|
|
install_monitoring_tools() {
|
|
log "Installing monitoring and system utilities"
|
|
|
|
# Essential monitoring tools
|
|
ensure_pkg htop
|
|
ensure_pkg iotop
|
|
ensure_pkg net-tools
|
|
ensure_pkg curl
|
|
ensure_pkg wget
|
|
ensure_pkg vim
|
|
ensure_pkg nano
|
|
ensure_pkg tree
|
|
ensure_pkg unzip
|
|
ensure_pkg zip
|
|
ensure_pkg rsync
|
|
ensure_pkg tmux
|
|
ensure_pkg screen
|
|
|
|
log "Monitoring tools installed"
|
|
}
|
|
{% endif %}
|
|
|
|
{% if flags.install_build_tools %}
|
|
install_build_tools() {
|
|
log "Installing build tools and development utilities"
|
|
|
|
ensure_pkg build-essential
|
|
ensure_pkg git
|
|
ensure_pkg make
|
|
ensure_pkg cmake
|
|
ensure_pkg pkg-config
|
|
|
|
log "Build tools installed"
|
|
}
|
|
{% endif %}
|
|
|
|
main() {
|
|
log "Starting setup"
|
|
|
|
# System Setup (run first)
|
|
{% if flags.system_update %} system_update {% endif %}
|
|
{% if flags.setup_timezone %} setup_timezone {% endif %}
|
|
{% if flags.setup_hostname %} setup_hostname {% endif %}
|
|
{% if flags.setup_ntp %} setup_ntp {% endif %}
|
|
{% if flags.setup_swap %} setup_swap {% endif %}
|
|
{% if flags.auto_security_updates %} setup_auto_security_updates {% endif %}
|
|
|
|
# Security & Hardening
|
|
{% if flags.ssh_harden %} harden_ssh {% endif %}
|
|
{% if flags.install_fail2ban %} install_fail2ban {% endif %}
|
|
{% if flags.prelogin_banner %} setup_prelogin_banner {% endif %}
|
|
{% if flags.postlogin_banner %} setup_postlogin_banner {% endif %}
|
|
{% if flags.ssh_2fa %} install_google_authenticator {% endif %}
|
|
|
|
# User Management
|
|
{% if flags.create_admin_user %} create_admin_user {% endif %}
|
|
|
|
# Docker & Services
|
|
{% if flags.install_docker %} install_docker {% endif %}
|
|
{% if flags.docker_admin_user %} create_docker_admin_user {% endif %}
|
|
{% if flags.open_ports %} setup_firewall {% endif %}
|
|
{% if flags.combine_lan %} setup_netplan_bond_bridge {% endif %}
|
|
|
|
# Monitoring & Utilities
|
|
{% if flags.install_monitoring_tools %} install_monitoring_tools {% endif %}
|
|
{% if flags.install_build_tools %} install_build_tools {% endif %}
|
|
|
|
log "Done"
|
|
}
|
|
|
|
main "$@"
|