Add new template for debian trixie without luks encryption; fix disk resizing on first boot; set default user and ssh keys for cloud init
This commit is contained in:
parent
775215f230
commit
e57f2d977b
19 changed files with 2341 additions and 17 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
# Project
|
# Project
|
||||||
/credentials.auto.pkrvars.hcl
|
/credentials.auto.pkrvars.hcl
|
||||||
/downloaded_iso_path
|
/downloaded_iso_path
|
||||||
overwrite-if.auto.pkrvars.hcl
|
overwrite*.auto.pkrvars.hcl
|
||||||
|
|
||||||
# Linux
|
# Linux
|
||||||
*~
|
*~
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -12,7 +12,6 @@
|
||||||
- [Build](#build)
|
- [Build](#build)
|
||||||
- [Build LUKS encrypted Templates](#build-luks-encrypted-templates)
|
- [Build LUKS encrypted Templates](#build-luks-encrypted-templates)
|
||||||
- [Setup new templates](#setup-new-templates)
|
- [Setup new templates](#setup-new-templates)
|
||||||
- [ToDo](#todo)
|
|
||||||
|
|
||||||
## Templates
|
## Templates
|
||||||
|
|
||||||
|
|
@ -106,14 +105,3 @@ mise run setup <distribution name> <version>
|
||||||
```
|
```
|
||||||
|
|
||||||
E.g. `mise run setup debian 13-trixie` or `mise run setup debian 13-trixie-luks`.
|
E.g. `mise run setup debian 13-trixie` or `mise run setup debian 13-trixie-luks`.
|
||||||
|
|
||||||
## ToDo
|
|
||||||
|
|
||||||
- [ ] Debian 13 with LUKS
|
|
||||||
- [x] Setup image with LUKS
|
|
||||||
- [ ] Automated unlock from packer on 1st boot after installation
|
|
||||||
- [ ] Setup dropbear
|
|
||||||
- [ ] Setup Clevis/Tang
|
|
||||||
- [x] Copy initial setup script, to expand the disk and do various setup steps
|
|
||||||
- [x] Lock down root user (remove password, prohibit all logins)
|
|
||||||
- [x] Lock down SSH Server
|
|
||||||
|
|
|
||||||
2
debian/13-trixie-luks/debian-trixie.pkr.hcl
vendored
2
debian/13-trixie-luks/debian-trixie.pkr.hcl
vendored
|
|
@ -114,7 +114,7 @@ build {
|
||||||
inline = [
|
inline = [
|
||||||
"export DEBIAN_FRONTEND=noninteractive",
|
"export DEBIAN_FRONTEND=noninteractive",
|
||||||
"apt-get update",
|
"apt-get update",
|
||||||
"apt-get install -y age apt-transport-https aria2 bat bc bmon btop ca-certificates curl duf eza fastfetch fzf git gnupg htop iftop iotop iperf jq lsof magic-wormhole mosh mtr ncdu parted progress pv ripgrep rsync smartmontools socat sudo tmux usbutils vim wget yq zsh zstd"
|
"apt-get install -y age apt-transport-https aria2 bat bc bmon btop ca-certificates curl duf eza fastfetch fzf gdisk git gnupg htop iftop iotop iperf jq lsof magic-wormhole mosh mtr ncdu parted progress pv ripgrep rsync smartmontools socat sudo tmux usbutils vim wget yq zsh zstd"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
26
debian/13-trixie-luks/files/initial-setup.sh
vendored
26
debian/13-trixie-luks/files/initial-setup.sh
vendored
|
|
@ -279,6 +279,28 @@ refresh_partition_table() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repair_gpt_backup_header() {
|
||||||
|
local disk="$1"
|
||||||
|
|
||||||
|
if command -v sgdisk >/dev/null 2>&1; then
|
||||||
|
if sgdisk -e "$disk" >/dev/null 2>&1; then
|
||||||
|
refresh_partition_table "$disk"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if parted -s "$disk" print >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf 'Fix\n' | parted ---pretend-input-tty "$disk" print >/dev/null 2>&1; then
|
||||||
|
refresh_partition_table "$disk"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
wait_for_partition_growth() {
|
wait_for_partition_growth() {
|
||||||
local part="$1"
|
local part="$1"
|
||||||
local old_bytes="$2"
|
local old_bytes="$2"
|
||||||
|
|
@ -436,6 +458,10 @@ resize_lvm_on_luks() {
|
||||||
log_info "Disk: ${DISK_DEV} | Partition number: ${PART_NUM}"
|
log_info "Disk: ${DISK_DEV} | Partition number: ${PART_NUM}"
|
||||||
[ -n "$LUKS_NAME" ] && log_info "LUKS mapper name: ${LUKS_NAME}"
|
[ -n "$LUKS_NAME" ] && log_info "LUKS mapper name: ${LUKS_NAME}"
|
||||||
|
|
||||||
|
if ! repair_gpt_backup_header "$DISK_DEV"; then
|
||||||
|
log_warn "Unable to repair or verify GPT backup header on ${DISK_DEV}; resize may fail."
|
||||||
|
fi
|
||||||
|
|
||||||
if ! is_last_partition_on_disk "$DISK_DEV" "$PART_NUM"; then
|
if ! is_last_partition_on_disk "$DISK_DEV" "$PART_NUM"; then
|
||||||
log_warn "Partition ${PART_NUM} is not the last partition on ${DISK_DEV}. Automatic growth is skipped."
|
log_warn "Partition ${PART_NUM} is not the last partition on ${DISK_DEV}. Automatic growth is skipped."
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
1
debian/13-trixie/credentials.auto.pkrvars.hcl
vendored
Symbolic link
1
debian/13-trixie/credentials.auto.pkrvars.hcl
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../credentials.auto.pkrvars.hcl
|
||||||
233
debian/13-trixie/debian-trixie.pkr.hcl
vendored
Normal file
233
debian/13-trixie/debian-trixie.pkr.hcl
vendored
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
packer {
|
||||||
|
required_plugins {
|
||||||
|
proxmox = {
|
||||||
|
version = "~> 1"
|
||||||
|
source = "github.com/hashicorp/proxmox"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source "proxmox-iso" "debian-13-trixie" {
|
||||||
|
# Proxmox Connection Settings
|
||||||
|
proxmox_url = "${var.proxmox_api_url}"
|
||||||
|
username = "${var.proxmox_api_token_id}"
|
||||||
|
token = "${var.proxmox_api_token_secret}"
|
||||||
|
|
||||||
|
# Skip TLS Verification
|
||||||
|
insecure_skip_tls_verify = "${var.proxmox_skip_tls_verify}"
|
||||||
|
|
||||||
|
# VM General Settings
|
||||||
|
node = "${var.proxmox_node}"
|
||||||
|
vm_id = "${var.template_vm_id}"
|
||||||
|
vm_name = "debian-13-trixie-${local.timestamp}"
|
||||||
|
template_description = "Debian 13 Trixie, built with Packer on ${local.timestamp}"
|
||||||
|
os = "l26"
|
||||||
|
qemu_agent = true
|
||||||
|
|
||||||
|
# VM Hardware Settings
|
||||||
|
machine = "q35"
|
||||||
|
cpu_type = "${var.template_cpu_type}"
|
||||||
|
cores = 2
|
||||||
|
memory = 2048
|
||||||
|
ballooning_minimum = 2048
|
||||||
|
bios = "ovmf"
|
||||||
|
scsi_controller = "virtio-scsi-single"
|
||||||
|
disks {
|
||||||
|
disk_size = "30G"
|
||||||
|
format = "raw"
|
||||||
|
storage_pool = "${var.disk_storage_pool}"
|
||||||
|
type = "scsi" # VirtIO-SCSI better maintained as virtio-blk has been deprecated in Proxmox VE 7.4+ and may cause issues with newer Linux kernels
|
||||||
|
io_thread = true
|
||||||
|
ssd = true
|
||||||
|
}
|
||||||
|
|
||||||
|
efi_config {
|
||||||
|
efi_storage_pool = "${var.disk_storage_pool}"
|
||||||
|
pre_enrolled_keys = true
|
||||||
|
efi_format = "raw"
|
||||||
|
efi_type = "4m"
|
||||||
|
}
|
||||||
|
|
||||||
|
serials = [
|
||||||
|
"socket"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Download ISO
|
||||||
|
boot_iso {
|
||||||
|
type = "scsi"
|
||||||
|
iso_url = "${var.iso_url}"
|
||||||
|
unmount = true
|
||||||
|
iso_storage_pool = "${var.iso_storage_pool}"
|
||||||
|
iso_checksum = "${var.iso_checksum}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# VM Network Settings
|
||||||
|
network_adapters {
|
||||||
|
model = "virtio"
|
||||||
|
mac_address = "${var.mac_address}"
|
||||||
|
bridge = "${var.network_bridge}"
|
||||||
|
firewall = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
# VM Cloud-Init Settings
|
||||||
|
cloud_init = true
|
||||||
|
cloud_init_storage_pool = "${var.disk_storage_pool}"
|
||||||
|
cloud_init_disk_type = "scsi"
|
||||||
|
|
||||||
|
# PACKER Boot Commands
|
||||||
|
boot = "order=scsi0;scsi1"
|
||||||
|
boot_wait = "10s"
|
||||||
|
communicator = "ssh"
|
||||||
|
boot_command = [
|
||||||
|
"<wait3>c<wait3>",
|
||||||
|
"linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
|
||||||
|
"DEBIAN_FRONTEND=text ",
|
||||||
|
"console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 ",
|
||||||
|
"passwd/root-password='${var.default_root_passphrase}' ",
|
||||||
|
"passwd/root-password-again='${var.default_root_passphrase}' ",
|
||||||
|
"preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg noprompt<enter>",
|
||||||
|
"initrd /install.amd/initrd.gz<enter>",
|
||||||
|
"DEBCONF_DEBUG=5<enter>",
|
||||||
|
"boot<enter>"
|
||||||
|
]
|
||||||
|
# Static IP
|
||||||
|
# boot_command = [
|
||||||
|
# "<wait3>c<wait3>",
|
||||||
|
# "linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
|
||||||
|
# "DEBIAN_FRONTEND=text ",
|
||||||
|
# "console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 ",
|
||||||
|
# "passwd/root-password='${var.default_root_passphrase}' ",
|
||||||
|
# "passwd/root-password-again='${var.default_root_passphrase}' ",
|
||||||
|
# "netcfg/disable_autoconfig=true ",
|
||||||
|
# "netcfg/get_ipaddress=172.16.2.254 ",
|
||||||
|
# "netcfg/get_netmask=255.255.255.0 ",
|
||||||
|
# "netcfg/get_gateway=172.16.2.3 ",
|
||||||
|
# "netcfg/get_nameservers=172.16.2.3 ",
|
||||||
|
# "netcfg/confirm_static=true ",
|
||||||
|
# "netcfg/get_hostname=debian-installer ",
|
||||||
|
# "netcfg/get_domain=local ",
|
||||||
|
# "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg noprompt<enter>",
|
||||||
|
# "initrd /install.amd/initrd.gz<enter>",
|
||||||
|
# "DEBCONF_DEBUG=5<enter>",
|
||||||
|
# "boot<enter>"
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# PACKER Autoinstall Settings
|
||||||
|
http_directory = "debian/13-trixie/http"
|
||||||
|
http_interface = "${var.source_proxmox_http_interface}"
|
||||||
|
|
||||||
|
# SSH Settings
|
||||||
|
ssh_username = "root"
|
||||||
|
ssh_password = "${var.default_root_passphrase}"
|
||||||
|
ssh_timeout = "20m"
|
||||||
|
ssh_pty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
build {
|
||||||
|
name = "debian-13-trixie-image"
|
||||||
|
sources = ["source.proxmox-iso.debian-13-trixie"]
|
||||||
|
|
||||||
|
# Install dependencies and default packages
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
"export DEBIAN_FRONTEND=noninteractive",
|
||||||
|
"apt-get update",
|
||||||
|
"apt-get install -y age apt-transport-https aria2 bat bc bmon btop ca-certificates curl duf eza fastfetch fzf gdisk git gnupg htop iftop iotop iperf jq lsof magic-wormhole mosh mtr ncdu parted progress pv ripgrep rsync smartmontools socat sudo tmux usbutils vim wget yq zsh zstd"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Tailscale
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "debian/13-trixie/scripts/tailscale.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup CrowdSec Repo
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "debian/13-trixie/scripts/crowdsec-repo-setup.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install CrowdSec
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
"apt-get install -y crowdsec",
|
||||||
|
"apt-get install -y crowdsec-firewall-bouncer-iptables"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure CrowdSec
|
||||||
|
provisioner "shell" {
|
||||||
|
script = "debian/13-trixie/scripts/crowdsec-configuration.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Provisioning the VM Template for Cloud-Init Integration in Proxmox #2
|
||||||
|
provisioner "file" {
|
||||||
|
source = "debian/13-trixie/files/99-pve.cfg"
|
||||||
|
destination = "/tmp/99-pve.cfg"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Provisioning the VM Template for Cloud-Init Integration in Proxmox #3
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["sudo cp /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/99-pve.cfg"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove APT sources.list
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = ["rm -f /etc/apt/sources.list /etc/apt/sources.list~"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add custom APT sources
|
||||||
|
provisioner "file" {
|
||||||
|
source = "debian/13-trixie/files/debian.sources"
|
||||||
|
destination = "/etc/apt/sources.list.d/debian.sources"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
source = "debian/13-trixie/files/90-initial-login-setup.sh"
|
||||||
|
destination = "/etc/profile.d/90-initial-login-setup.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
source = "debian/13-trixie/files/initial-setup.sh"
|
||||||
|
destination = "/usr/local/bin/initial-setup.sh"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
"chmod +x /usr/local/bin/initial-setup.sh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup Serial Console for xterm.js in Proxmox VE
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
"sed -i 's/#\\?GRUB_CMDLINE_LINUX=.*\"/GRUB_CMDLINE_LINUX=\"console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0\"/' /etc/default/grub",
|
||||||
|
"sed -i 's/#\\?GRUB_TERMINAL=.*/GRUB_TERMINAL=\"serial console\"/' /etc/default/grub",
|
||||||
|
"sed -i 's/#\\?GRUB_SERIAL_COMMAND=.*/GRUB_SERIAL_COMMAND=\"serial --speed=115200\"/' /etc/default/grub",
|
||||||
|
"update-grub"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Provisioning the VM Template for Cloud-Init Integration in Proxmox #1
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
"rm /etc/ssh/ssh_host_*",
|
||||||
|
"truncate -s 0 /etc/machine-id",
|
||||||
|
"apt -y autoremove --purge 2> /dev/null",
|
||||||
|
"apt -y clean 2> /dev/null",
|
||||||
|
"apt -y autoclean 2> /dev/null",
|
||||||
|
"rm -rf /var/cache/apt/archives /var/lib/apt/lists/*",
|
||||||
|
"cloud-init clean",
|
||||||
|
"rm -f /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg",
|
||||||
|
"sync"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove temporary settings and configuration for packer build
|
||||||
|
provisioner "shell" {
|
||||||
|
inline = [
|
||||||
|
"sed -i 's/^#\\?PermitRootLogin .*/PermitRootLogin no/' /etc/ssh/sshd_config",
|
||||||
|
"sed -i 's/^#\\?PasswordAuthentication .*/PasswordAuthentication no/' /etc/ssh/sshd_config",
|
||||||
|
"passwd -dl root"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
25
debian/13-trixie/files/90-initial-login-setup.sh
vendored
Normal file
25
debian/13-trixie/files/90-initial-login-setup.sh
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#! /bin/sed 2,5!d;s/^#.//
|
||||||
|
# This script must be sourced from within a shell
|
||||||
|
# and not executed. For instance with:
|
||||||
|
#
|
||||||
|
# . /usr/local/bin/initial-setup.sh
|
||||||
|
|
||||||
|
# Only run in interactive shells
|
||||||
|
case $- in
|
||||||
|
*i*) ;;
|
||||||
|
*) return ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
if ! command -v sudo >/dev/null 2>&1 || ! sudo -n true >/dev/null 2>&1; then
|
||||||
|
echo "Error: must be root or have sudo privileges to run initial login setup." >&2
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
SENTINEL="/var/lib/initial-login-setup.done"
|
||||||
|
|
||||||
|
if [ ! -f "$SENTINEL" ] && [ -x /usr/local/bin/initial-setup.sh ]; then
|
||||||
|
sudo touch "$SENTINEL"
|
||||||
|
sudo /usr/local/bin/initial-setup.sh
|
||||||
|
fi
|
||||||
19
debian/13-trixie/files/99-pve.cfg
vendored
Normal file
19
debian/13-trixie/files/99-pve.cfg
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
datasource_list: [ConfigDrive, NoCloud]
|
||||||
|
|
||||||
|
users:
|
||||||
|
- default
|
||||||
|
|
||||||
|
system_info:
|
||||||
|
default_user:
|
||||||
|
name: b23
|
||||||
|
gecos: base23 default user
|
||||||
|
groups: [adm, audio, cdrom, dialout, dip, floppy, netdev, plugdev, sudo, video]
|
||||||
|
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
shell: /bin/bash
|
||||||
|
lock_passwd: true
|
||||||
|
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBiiCLKXIHS639MGp/5ckFO0cpTIBX6WehDKBbL7zLse Philip Henning <philip.henning@base23.de>
|
||||||
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGh/6DRjKCZHByW4/Inig9LXKI9c3M395fjpv7Ox4Jkz Dennis Michaelis <dennis.michaelis@base23.de>
|
||||||
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILFK9liU5igL7cZBuEzPD/k/YngMJ4YGwT53SvFFnPyy Simon Stumpe <simon.stumpe@base23.de>
|
||||||
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGi0nRU/9QgbMoRfU27L5GNLqosKiLm8zsGmQhG7vz5J Maik Tirock <maik.tirock@base23.de>
|
||||||
38
debian/13-trixie/files/debian.sources
vendored
Normal file
38
debian/13-trixie/files/debian.sources
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
Types: deb
|
||||||
|
URIs: http://ftp.de.debian.org/debian/
|
||||||
|
Suites: trixie
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
Types: deb-src
|
||||||
|
URIs: http://ftp.de.debian.org/debian/
|
||||||
|
Suites: trixie
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
|
||||||
|
Types: deb
|
||||||
|
URIs: http://ftp.de.debian.org/debian/
|
||||||
|
Suites: trixie-updates
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
Types: deb-src
|
||||||
|
URIs: http://ftp.de.debian.org/debian/
|
||||||
|
Suites: trixie-updates
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
|
||||||
|
Types: deb
|
||||||
|
URIs: http://security.debian.org/
|
||||||
|
Suites: trixie-security
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
|
Types: deb-src
|
||||||
|
URIs: http://security.debian.org/
|
||||||
|
Suites: trixie-security
|
||||||
|
Components: main contrib non-free non-free-firmware
|
||||||
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||||
|
|
||||||
660
debian/13-trixie/files/initial-setup.sh
vendored
Normal file
660
debian/13-trixie/files/initial-setup.sh
vendored
Normal file
|
|
@ -0,0 +1,660 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
SCRIPT_NAME="$(basename "$0")"
|
||||||
|
TASK_INDEX=0
|
||||||
|
TASK_TOTAL=0
|
||||||
|
STORAGE_DETECTED=0
|
||||||
|
|
||||||
|
ROOT_SOURCE=""
|
||||||
|
VG_NAME=""
|
||||||
|
LV_NAME=""
|
||||||
|
PV_NAME=""
|
||||||
|
DISK_DEV=""
|
||||||
|
PART_NUM=""
|
||||||
|
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
BOLD="$(tput bold 2>/dev/null || true)"
|
||||||
|
DIM="$(tput dim 2>/dev/null || true)"
|
||||||
|
RED="$(tput setaf 1 2>/dev/null || true)"
|
||||||
|
GREEN="$(tput setaf 2 2>/dev/null || true)"
|
||||||
|
YELLOW="$(tput setaf 3 2>/dev/null || true)"
|
||||||
|
BLUE="$(tput setaf 4 2>/dev/null || true)"
|
||||||
|
RESET="$(tput sgr0 2>/dev/null || true)"
|
||||||
|
else
|
||||||
|
BOLD=""
|
||||||
|
DIM=""
|
||||||
|
RED=""
|
||||||
|
GREEN=""
|
||||||
|
YELLOW=""
|
||||||
|
BLUE=""
|
||||||
|
RESET=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo "${RED}Error:${RESET} $*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo "${BLUE}INFO:${RESET} $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_ok() {
|
||||||
|
echo "${GREEN}OK:${RESET} $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn() {
|
||||||
|
echo "${YELLOW}WARN:${RESET} $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
section() {
|
||||||
|
local title="$1"
|
||||||
|
echo
|
||||||
|
echo "${BOLD}${title}${RESET}"
|
||||||
|
echo "${DIM}------------------------------------------------------------${RESET}"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_tty() {
|
||||||
|
if [ ! -t 0 ] || [ ! -t 1 ]; then
|
||||||
|
die "This setup must run interactively in a TTY."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_root() {
|
||||||
|
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
log_info "Re-running with sudo..."
|
||||||
|
exec sudo -E "$0" "$@"
|
||||||
|
fi
|
||||||
|
die "Must be root or have sudo privileges to run this setup."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
log_warn "Missing command: $cmd"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_input() {
|
||||||
|
local label="$1"
|
||||||
|
local default="${2:-}"
|
||||||
|
local value=""
|
||||||
|
if [ -n "$default" ]; then
|
||||||
|
read -r -p "${label} [${default}]: " value </dev/tty
|
||||||
|
value="${value:-$default}"
|
||||||
|
else
|
||||||
|
read -r -p "${label}: " value </dev/tty
|
||||||
|
fi
|
||||||
|
printf '%s' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_secret() {
|
||||||
|
local label="$1"
|
||||||
|
local value=""
|
||||||
|
while true; do
|
||||||
|
read -r -s -p "${label}: " value </dev/tty
|
||||||
|
printf '\n' >/dev/tty
|
||||||
|
if [ -n "$value" ]; then
|
||||||
|
printf '%s' "$value"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log_warn "Value cannot be empty."
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_secret_confirm() {
|
||||||
|
local label="$1"
|
||||||
|
local confirm_label="$2"
|
||||||
|
local a=""
|
||||||
|
local b=""
|
||||||
|
while true; do
|
||||||
|
read -r -s -p "${label}: " a </dev/tty
|
||||||
|
printf '\n' >/dev/tty
|
||||||
|
read -r -s -p "${confirm_label}: " b </dev/tty
|
||||||
|
printf '\n' >/dev/tty
|
||||||
|
if [ -z "$a" ]; then
|
||||||
|
log_warn "Value cannot be empty."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ "$a" != "$b" ]; then
|
||||||
|
log_warn "Values do not match. Please try again."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
printf '%s' "$a"
|
||||||
|
return 0
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
local label="$1"
|
||||||
|
local default="${2:-yes}"
|
||||||
|
local prompt=""
|
||||||
|
local answer=""
|
||||||
|
|
||||||
|
if [ "$default" = "yes" ]; then
|
||||||
|
prompt="[Y/n]"
|
||||||
|
else
|
||||||
|
prompt="[y/N]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -r -p "${label} ${prompt} " answer </dev/tty
|
||||||
|
if [ -z "$answer" ]; then
|
||||||
|
answer="$default"
|
||||||
|
fi
|
||||||
|
case "${answer,,}" in
|
||||||
|
y|yes) return 0 ;;
|
||||||
|
n|no) return 1 ;;
|
||||||
|
*) log_warn "Please answer yes or no." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
human_bytes() {
|
||||||
|
local bytes="$1"
|
||||||
|
if command -v numfmt >/dev/null 2>&1; then
|
||||||
|
numfmt --to=iec --suffix=B "$bytes"
|
||||||
|
else
|
||||||
|
awk -v b="$bytes" 'BEGIN {
|
||||||
|
split("B KiB MiB GiB TiB", u, " ");
|
||||||
|
i=1;
|
||||||
|
while (b>=1024 && i<5) { b/=1024; i++; }
|
||||||
|
printf "%.1f %s", b, u[i];
|
||||||
|
}'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mib_to_human() {
|
||||||
|
local mib="$1"
|
||||||
|
awk -v m="$mib" 'BEGIN { printf "%.1f GiB", m/1024 }'
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task() {
|
||||||
|
TASK_TITLES+=("$1")
|
||||||
|
TASK_FUNCS+=("$2")
|
||||||
|
TASK_TOTAL=$((TASK_TOTAL + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tasks() {
|
||||||
|
local i
|
||||||
|
local title
|
||||||
|
local func
|
||||||
|
for i in "${!TASK_FUNCS[@]}"; do
|
||||||
|
TASK_INDEX=$((TASK_INDEX + 1))
|
||||||
|
title="${TASK_TITLES[$i]}"
|
||||||
|
func="${TASK_FUNCS[$i]}"
|
||||||
|
section "Task ${TASK_INDEX}/${TASK_TOTAL}: ${title}"
|
||||||
|
"$func"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
lsblk_attr() {
|
||||||
|
local path="$1"
|
||||||
|
local attr="$2"
|
||||||
|
lsblk -dn -o "$attr" "$path" 2>/dev/null | head -n1 | xargs || true
|
||||||
|
}
|
||||||
|
|
||||||
|
infer_disk_part_from_partition() {
|
||||||
|
local part_path="$1"
|
||||||
|
local resolved
|
||||||
|
local base
|
||||||
|
|
||||||
|
resolved="$(readlink -f "$part_path" 2>/dev/null || printf '%s' "$part_path")"
|
||||||
|
base="$(basename "$resolved")"
|
||||||
|
|
||||||
|
if [[ "$base" =~ ^(nvme[0-9]+n[0-9]+)p([0-9]+)$ ]]; then
|
||||||
|
printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ "$base" =~ ^(mmcblk[0-9]+)p([0-9]+)$ ]]; then
|
||||||
|
printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ "$base" =~ ^(md[0-9]+)p([0-9]+)$ ]]; then
|
||||||
|
printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ "$base" =~ ^((sd|vd|xvd|hd)[a-z]+)([0-9]+)$ ]]; then
|
||||||
|
printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[3]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_partition_table() {
|
||||||
|
local disk="$1"
|
||||||
|
if command -v partprobe >/dev/null 2>&1; then
|
||||||
|
partprobe "$disk" || true
|
||||||
|
fi
|
||||||
|
if command -v partx >/dev/null 2>&1; then
|
||||||
|
partx -u "$disk" || true
|
||||||
|
fi
|
||||||
|
if command -v udevadm >/dev/null 2>&1; then
|
||||||
|
udevadm settle || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
repair_gpt_backup_header() {
|
||||||
|
local disk="$1"
|
||||||
|
|
||||||
|
if command -v sgdisk >/dev/null 2>&1; then
|
||||||
|
if sgdisk -e "$disk" >/dev/null 2>&1; then
|
||||||
|
refresh_partition_table "$disk"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if parted -s "$disk" print >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf 'Fix\n' | parted ---pretend-input-tty "$disk" print >/dev/null 2>&1; then
|
||||||
|
refresh_partition_table "$disk"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_partition_growth() {
|
||||||
|
local part="$1"
|
||||||
|
local old_bytes="$2"
|
||||||
|
local new_bytes=0
|
||||||
|
local i=0
|
||||||
|
|
||||||
|
for ((i = 0; i < 12; i++)); do
|
||||||
|
new_bytes="$(blockdev --getsize64 "$part" 2>/dev/null || echo 0)"
|
||||||
|
if [ "$new_bytes" -gt "$old_bytes" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
is_last_partition_on_disk() {
|
||||||
|
local disk="$1"
|
||||||
|
local part_num="$2"
|
||||||
|
local last_part
|
||||||
|
|
||||||
|
last_part="$(parted -ms "$disk" unit s print 2>/dev/null | awk -F: '$1 ~ /^[0-9]+$/ {last=$1} END {print last}')"
|
||||||
|
[ -n "$last_part" ] && [ "$part_num" = "$last_part" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
get_trailing_free_bytes() {
|
||||||
|
local disk="$1"
|
||||||
|
local part_num="$2"
|
||||||
|
local disk_bytes
|
||||||
|
local part_end_bytes
|
||||||
|
local free_bytes
|
||||||
|
|
||||||
|
disk_bytes="$(blockdev --getsize64 "$disk" 2>/dev/null || true)"
|
||||||
|
part_end_bytes="$(parted -ms "$disk" unit B print 2>/dev/null | awk -F: -v p="$part_num" '$1==p {gsub("B","",$3); print $3; exit}')"
|
||||||
|
if [ -z "$disk_bytes" ] || [ -z "$part_end_bytes" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
free_bytes=$((disk_bytes - part_end_bytes - 1))
|
||||||
|
if [ "$free_bytes" -lt 0 ]; then
|
||||||
|
free_bytes=0
|
||||||
|
fi
|
||||||
|
echo "$free_bytes"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_disk_layout() {
|
||||||
|
local disk="$1"
|
||||||
|
local disk_bytes
|
||||||
|
|
||||||
|
disk_bytes="$(blockdev --getsize64 "$disk" 2>/dev/null || true)"
|
||||||
|
if [ -n "$disk_bytes" ]; then
|
||||||
|
log_info "Full disk size: $(human_bytes "$disk_bytes")"
|
||||||
|
else
|
||||||
|
log_warn "Unable to determine full disk size for ${disk}."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Current disk layout:"
|
||||||
|
if ! lsblk -i -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS "$disk" 2>/dev/null | sed 's/^/ /'; then
|
||||||
|
log_warn "Unable to show current partition layout for ${disk}."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_storage_stack() {
|
||||||
|
STORAGE_DETECTED=0
|
||||||
|
DISK_DEV=""
|
||||||
|
PART_NUM=""
|
||||||
|
|
||||||
|
require_cmd findmnt || return 1
|
||||||
|
require_cmd lvs || return 1
|
||||||
|
require_cmd pvs || return 1
|
||||||
|
require_cmd lsblk || return 1
|
||||||
|
|
||||||
|
ROOT_SOURCE="$(findmnt -n -o SOURCE / || true)"
|
||||||
|
if [ -z "$ROOT_SOURCE" ] || [ ! -e "$ROOT_SOURCE" ]; then
|
||||||
|
log_warn "Unable to detect root device."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VG_NAME="$(lvs --noheadings -o vg_name "$ROOT_SOURCE" 2>/dev/null | xargs || true)"
|
||||||
|
LV_NAME="$(lvs --noheadings -o lv_name "$ROOT_SOURCE" 2>/dev/null | xargs || true)"
|
||||||
|
if [ -z "$VG_NAME" ]; then
|
||||||
|
log_warn "Root does not appear to be on LVM."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PV_NAME="$(pvs --noheadings -o pv_name --select "vg_name=${VG_NAME}" 2>/dev/null | head -n1 | xargs || true)"
|
||||||
|
if [ -z "$PV_NAME" ]; then
|
||||||
|
log_warn "Unable to detect LVM physical volume."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -b "$PV_NAME" ]; then
|
||||||
|
log_warn "Detected LVM physical volume is not a block device: ${PV_NAME}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local inferred
|
||||||
|
local inferred_disk=""
|
||||||
|
local inferred_part=""
|
||||||
|
inferred="$(infer_disk_part_from_partition "$PV_NAME" || true)"
|
||||||
|
if [ -n "$inferred" ]; then
|
||||||
|
inferred_disk="$(printf '%s\n' "$inferred" | sed -n '1p')"
|
||||||
|
inferred_part="$(printf '%s\n' "$inferred" | sed -n '2p')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
DISK_DEV="$inferred_disk"
|
||||||
|
PART_NUM="$inferred_part"
|
||||||
|
|
||||||
|
if [ -z "$DISK_DEV" ]; then
|
||||||
|
local disk_parent
|
||||||
|
disk_parent="$(lsblk_attr "$PV_NAME" PKNAME)"
|
||||||
|
if [ -n "$disk_parent" ]; then
|
||||||
|
DISK_DEV="/dev/${disk_parent}"
|
||||||
|
else
|
||||||
|
DISK_DEV="$(lsblk -nro PATH,TYPE -s "$PV_NAME" 2>/dev/null | awk '$2=="disk" {print $1; exit}' | xargs || true)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$PART_NUM" ]; then
|
||||||
|
PART_NUM="$(lsblk_attr "$PV_NAME" PARTNUM)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$DISK_DEV" ] || [ ! -b "$DISK_DEV" ] || [ -z "$PART_NUM" ] || ! [[ "$PART_NUM" =~ ^[0-9]+$ ]]; then
|
||||||
|
log_warn "Unable to detect disk device or partition number."
|
||||||
|
log_warn "Detected values: PV_NAME=${PV_NAME:-<empty>} DISK_DEV=${DISK_DEV:-<empty>} PART_NUM=${PART_NUM:-<empty>}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
STORAGE_DETECTED=1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_lvm() {
|
||||||
|
if [ "$STORAGE_DETECTED" -ne 1 ]; then
|
||||||
|
log_warn "Storage layout not detected; skipping resize."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_cmd parted || return 0
|
||||||
|
require_cmd blockdev || return 0
|
||||||
|
require_cmd pvresize || return 0
|
||||||
|
require_cmd lvextend || return 0
|
||||||
|
|
||||||
|
log_info "Root LV: ${ROOT_SOURCE}"
|
||||||
|
log_info "VG: ${VG_NAME} | LV: ${LV_NAME}"
|
||||||
|
log_info "LVM PV: ${PV_NAME}"
|
||||||
|
log_info "Disk: ${DISK_DEV} | Partition number: ${PART_NUM}"
|
||||||
|
|
||||||
|
if ! repair_gpt_backup_header "$DISK_DEV"; then
|
||||||
|
log_warn "Unable to repair or verify GPT backup header on ${DISK_DEV}; resize may fail."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! is_last_partition_on_disk "$DISK_DEV" "$PART_NUM"; then
|
||||||
|
log_warn "Partition ${PART_NUM} is not the last partition on ${DISK_DEV}. Automatic growth is skipped."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local part_size_before
|
||||||
|
local free_bytes
|
||||||
|
|
||||||
|
part_size_before="$(blockdev --getsize64 "$PV_NAME" 2>/dev/null || echo 0)"
|
||||||
|
free_bytes="$(get_trailing_free_bytes "$DISK_DEV" "$PART_NUM" || true)"
|
||||||
|
if [ -z "$free_bytes" ]; then
|
||||||
|
log_warn "Unable to determine free disk space."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$free_bytes" -lt $((1024 * 1024)) ]; then
|
||||||
|
log_ok "No significant free space detected after the root partition."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Unallocated space available: $(human_bytes "$free_bytes")"
|
||||||
|
show_disk_layout "$DISK_DEV"
|
||||||
|
if ! confirm "Extend partition, VG, and root LV now?" "yes"; then
|
||||||
|
log_warn "Skipped resize."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Extending partition ${PV_NAME} to 100% of disk..."
|
||||||
|
if ! parted -s "$DISK_DEV" resizepart "$PART_NUM" 100%; then
|
||||||
|
log_warn "Partition resize failed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
refresh_partition_table "$DISK_DEV"
|
||||||
|
if [ "$part_size_before" -gt 0 ] && ! wait_for_partition_growth "$PV_NAME" "$part_size_before"; then
|
||||||
|
log_warn "Kernel has not reported the new partition size yet; continuing anyway."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Resizing LVM physical volume..."
|
||||||
|
if ! pvresize "$PV_NAME"; then
|
||||||
|
log_warn "pvresize failed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Extending root LV to use all free space..."
|
||||||
|
if ! lvextend -l +100%FREE -r "$ROOT_SOURCE"; then
|
||||||
|
log_warn "lvextend failed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_ok "Resize complete."
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_size_to_mib() {
|
||||||
|
local input="$1"
|
||||||
|
local normalized
|
||||||
|
normalized="$(echo "$input" | tr '[:upper:]' '[:lower:]' | xargs)"
|
||||||
|
if [[ "$normalized" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "$normalized"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ "$normalized" =~ ^([0-9]+)(g|gb)$ ]]; then
|
||||||
|
echo $((BASH_REMATCH[1] * 1024))
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ "$normalized" =~ ^([0-9]+)(m|mb)$ ]]; then
|
||||||
|
echo "${BASH_REMATCH[1]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_swap() {
|
||||||
|
require_cmd awk || return 0
|
||||||
|
require_cmd fallocate || return 0
|
||||||
|
require_cmd mkswap || return 0
|
||||||
|
require_cmd swapon || return 0
|
||||||
|
|
||||||
|
local mem_kib
|
||||||
|
local mem_mib
|
||||||
|
local swap_mib
|
||||||
|
|
||||||
|
mem_kib="$(awk '/MemTotal/ {print $2}' /proc/meminfo)"
|
||||||
|
mem_mib=$((mem_kib / 1024))
|
||||||
|
|
||||||
|
if [ "$mem_mib" -lt 2048 ]; then
|
||||||
|
swap_mib=$((mem_mib * 2))
|
||||||
|
elif [ "$mem_mib" -lt 4096 ]; then
|
||||||
|
swap_mib=$mem_mib
|
||||||
|
else
|
||||||
|
swap_mib=$((mem_mib / 5))
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Detected RAM: $(mib_to_human "$mem_mib")"
|
||||||
|
log_info "Recommended swap size: $(mib_to_human "$swap_mib")"
|
||||||
|
|
||||||
|
if ! confirm "Use recommended swap size?" "yes"; then
|
||||||
|
local custom
|
||||||
|
while true; do
|
||||||
|
custom="$(prompt_input "Enter custom swap size (MiB or GiB, e.g. 2048 or 4G)")"
|
||||||
|
if swap_mib="$(parse_size_to_mib "$custom")"; then
|
||||||
|
if [ "$swap_mib" -gt 0 ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
log_warn "Invalid size. Try again."
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
local swapfile="/swapfile"
|
||||||
|
if [ -e "$swapfile" ]; then
|
||||||
|
log_warn "Swap file already exists at ${swapfile}."
|
||||||
|
if ! confirm "Replace existing swap file?" "no"; then
|
||||||
|
log_warn "Skipped swap setup."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if swapon --show=NAME --noheadings | grep -qx "$swapfile"; then
|
||||||
|
swapoff "$swapfile" || true
|
||||||
|
fi
|
||||||
|
rm -f "$swapfile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Creating swap file (${swap_mib} MiB) at ${swapfile}..."
|
||||||
|
fallocate -l "${swap_mib}M" "$swapfile"
|
||||||
|
chmod 600 "$swapfile"
|
||||||
|
mkswap "$swapfile" >/dev/null
|
||||||
|
swapon "$swapfile"
|
||||||
|
|
||||||
|
if ! grep -qE "^[[:space:]]*${swapfile}[[:space:]]" /etc/fstab; then
|
||||||
|
echo "${swapfile} none swap sw 0 0" >> /etc/fstab
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_ok "Swap enabled."
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_tailscale() {
|
||||||
|
if ! require_cmd tailscale; then
|
||||||
|
log_warn "Tailscale is not installed; skipping."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! confirm "Set up Tailscale now?" "yes"; then
|
||||||
|
log_warn "Skipped Tailscale setup."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local server
|
||||||
|
local tags
|
||||||
|
local key
|
||||||
|
local tag_list=""
|
||||||
|
local t
|
||||||
|
|
||||||
|
server="$(prompt_input "Tailscale/Headscale server URL" "https://vpn.s1q.dev")"
|
||||||
|
tags="$(prompt_input "Client tags (comma-separated)" "server")"
|
||||||
|
key="$(prompt_secret "Pre-authentication key")"
|
||||||
|
|
||||||
|
if [ -n "$tags" ]; then
|
||||||
|
IFS=',' read -r -a tag_array <<<"$tags"
|
||||||
|
for t in "${tag_array[@]:-}"; do
|
||||||
|
t="$(echo "$t" | xargs)"
|
||||||
|
if [ -n "$t" ]; then
|
||||||
|
if [ -n "$tag_list" ]; then
|
||||||
|
tag_list+=","
|
||||||
|
fi
|
||||||
|
tag_list+="tag:${t}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Bringing up Tailscale..."
|
||||||
|
if [ -n "$tag_list" ]; then
|
||||||
|
tailscale up --login-server "$server" --authkey "$key" --ssh --advertise-tags "$tag_list"
|
||||||
|
else
|
||||||
|
tailscale up --login-server "$server" --authkey "$key" --ssh
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_ok "Tailscale setup complete."
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_crowdsec() {
|
||||||
|
if ! require_cmd cscli; then
|
||||||
|
log_warn "CrowdSec (cscli) not installed; skipping."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! confirm "Set up CrowdSec now?" "yes"; then
|
||||||
|
log_warn "Skipped CrowdSec setup."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local key
|
||||||
|
key="$(prompt_secret "Enrollment key")"
|
||||||
|
|
||||||
|
log_info "Enrolling CrowdSec..."
|
||||||
|
if cscli console enroll -e "$key"; then
|
||||||
|
log_info "Restarting CrowdSec service..."
|
||||||
|
systemctl restart crowdsec || log_warn "Failed to restart crowdsec service."
|
||||||
|
log_ok "CrowdSec enrollment complete."
|
||||||
|
else
|
||||||
|
log_warn "CrowdSec enrollment failed."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_reboot() {
|
||||||
|
log_warn "A reboot is strongly recommended after partition or swap changes."
|
||||||
|
if confirm "Reboot now?" "yes"; then
|
||||||
|
log_info "Rebooting..."
|
||||||
|
reboot
|
||||||
|
else
|
||||||
|
log_info "Please reboot later to ensure changes take effect."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
welcome() {
|
||||||
|
section "Initial VM Setup"
|
||||||
|
log_info "This setup runs once and is fully interactive."
|
||||||
|
log_info "Hostname: $(hostname)"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
ensure_tty
|
||||||
|
ensure_root "$@"
|
||||||
|
welcome
|
||||||
|
|
||||||
|
if detect_storage_stack; then
|
||||||
|
log_ok "Detected LVM storage layout."
|
||||||
|
else
|
||||||
|
log_warn "Storage layout detection incomplete; some steps may be skipped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
TASK_TITLES=()
|
||||||
|
TASK_FUNCS=()
|
||||||
|
|
||||||
|
add_task "Resize LVM (if free space exists)" resize_lvm
|
||||||
|
add_task "Configure swap file" setup_swap
|
||||||
|
add_task "Configure Tailscale" setup_tailscale
|
||||||
|
add_task "Configure CrowdSec" setup_crowdsec
|
||||||
|
add_task "Reboot recommendation" prompt_reboot
|
||||||
|
|
||||||
|
run_tasks
|
||||||
|
log_ok "Initial setup finished."
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
161
debian/13-trixie/http/preseed.cfg
vendored
Normal file
161
debian/13-trixie/http/preseed.cfg
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
#_preseed_V1
|
||||||
|
|
||||||
|
### Localization
|
||||||
|
d-i debian-installer/locale string en_US.UTF-8
|
||||||
|
d-i keyboard-configuration/xkb-keymap select us
|
||||||
|
|
||||||
|
### Unattended
|
||||||
|
d-i auto-install/enable boolean true
|
||||||
|
d-i debconf/priority select critical
|
||||||
|
d-i debian-installer/framebuffer boolean false
|
||||||
|
|
||||||
|
### Network
|
||||||
|
d-i netcfg/choose_interface select ens18
|
||||||
|
d-i netcfg/get_hostname string debian-13-template
|
||||||
|
d-i netcfg/get_domain string
|
||||||
|
d-i netcfg/wireless_wep string
|
||||||
|
d-i netcfg/disable_dhcp boolean false
|
||||||
|
|
||||||
|
### Root Password (no user)
|
||||||
|
d-i passwd/make-user boolean false
|
||||||
|
# Root password is set via kernel cmdline in debian-trixie.pkr.hcl; these lines are ignored but left here for reference:
|
||||||
|
# d-i passwd/root-password password "$PACKER_ROOT_PASS"
|
||||||
|
# d-i passwd/root-password-again password "$PACKER_ROOT_PASS"
|
||||||
|
|
||||||
|
### Mirror / APT
|
||||||
|
d-i apt-setup/cdrom/set-first boolean false
|
||||||
|
d-i apt-setup/cdrom/set-next boolean false
|
||||||
|
d-i apt-setup/cdrom/set-failed boolean false
|
||||||
|
|
||||||
|
d-i mirror/country string manual
|
||||||
|
d-i mirror/http/hostname string ftp.de.debian.org
|
||||||
|
d-i mirror/http/directory string /debian
|
||||||
|
d-i mirror/http/proxy string
|
||||||
|
|
||||||
|
# If you want an explicit suite:
|
||||||
|
# d-i mirror/suite string trixie
|
||||||
|
|
||||||
|
# Your extra repo line (updated to also include non-free-firmware for trixie)
|
||||||
|
d-i apt-setup/local0/repository string http://ftp.de.debian.org/debian/ trixie main contrib non-free non-free-firmware
|
||||||
|
popularity-contest popularity-contest/participate boolean false
|
||||||
|
|
||||||
|
d-i apt-setup/contrib boolean true
|
||||||
|
d-i apt-setup/non-free boolean true
|
||||||
|
d-i apt-setup/non-free-firmware boolean true
|
||||||
|
d-i apt-setup/security_host string security.debian.org
|
||||||
|
d-i apt-setup/services-select multiselect security, updates
|
||||||
|
|
||||||
|
### Timezone
|
||||||
|
d-i clock-setup/utc boolean true
|
||||||
|
d-i time/zone string UTC
|
||||||
|
d-i clock-setup/ntp boolean true
|
||||||
|
|
||||||
|
### Storage (UEFI + /boot + LUKS/LVM)
|
||||||
|
# Pick first detected disk automatically
|
||||||
|
d-i preseed/early_command string \
|
||||||
|
DISK="$(list-devices disk | head -n1)"; \
|
||||||
|
debconf-set partman-auto/disk "$DISK";
|
||||||
|
|
||||||
|
# "crypto" = LVM within an encrypted partition [oai_citation:3‡Debian](https://www.debian.org/releases/stable/amd64/apbs04.en.html)
|
||||||
|
# "lvm" = LVM without encryption
|
||||||
|
d-i partman-auto/method string lvm
|
||||||
|
d-i partman-auto-lvm/guided_size string max
|
||||||
|
d-i partman-auto-lvm/new_vg_name string vg0
|
||||||
|
|
||||||
|
# Cleanup old metadata if present
|
||||||
|
d-i partman-lvm/device_remove_lvm boolean true
|
||||||
|
d-i partman-md/device_remove_md boolean true
|
||||||
|
|
||||||
|
# Confirmations
|
||||||
|
d-i partman-lvm/confirm boolean true
|
||||||
|
d-i partman-lvm/confirm_nooverwrite boolean true
|
||||||
|
d-i partman-md/confirm boolean true
|
||||||
|
d-i partman-md/confirm_nooverwrite boolean true
|
||||||
|
|
||||||
|
# # LUKS password
|
||||||
|
# # LUKS passphrase is set via kernel cmdline in debian-trixie.pkr.hcl; these lines are ignored but left here for reference:
|
||||||
|
# # d-i partman-crypto/passphrase password "$PACKER_LUKS_PASS"
|
||||||
|
# # d-i partman-crypto/passphrase-again password "$PACKER_LUKS_PASS"
|
||||||
|
# d-i partman-crypto/weak_passphrase boolean true
|
||||||
|
# d-i partman-crypto/confirm boolean true
|
||||||
|
# d-i partman-auto-crypto/erase_disks boolean false
|
||||||
|
|
||||||
|
# Ensure GPT
|
||||||
|
d-i partman-partitioning/choose_label select gpt
|
||||||
|
d-i partman-partitioning/default_label string gpt
|
||||||
|
|
||||||
|
# Force UEFI (if needed in your environment)
|
||||||
|
d-i partman-efi/non_efi_system boolean true
|
||||||
|
|
||||||
|
# Do NOT go back to partitioning menu if a partition/LV has no filesystem
|
||||||
|
d-i partman-basicmethods/method_only boolean false
|
||||||
|
|
||||||
|
# Accept installing without swap (answer "No" to the warning)
|
||||||
|
d-i partman-basicfilesystems/no_swap boolean false
|
||||||
|
d-i partman-basicfilesystems/no_swap seen true
|
||||||
|
|
||||||
|
# Custom recipe
|
||||||
|
# NOTE: Avoid putting comments inside this expert_recipe block; d-i can ignore it. [oai_citation:4‡Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/796185/debian-preseed-install-auto-creates-swap)
|
||||||
|
d-i partman-auto/choose_recipe select luks-lvm
|
||||||
|
d-i partman-auto/expert_recipe string \
|
||||||
|
luks-lvm :: \
|
||||||
|
1075 1075 1075 fat32 \
|
||||||
|
$primary{ } \
|
||||||
|
$iflabel{ gpt } \
|
||||||
|
$reusemethod{ } \
|
||||||
|
method{ efi } \
|
||||||
|
format{ } \
|
||||||
|
filesystem{ fat32 } \
|
||||||
|
mountpoint{ /boot/efi } \
|
||||||
|
. \
|
||||||
|
1075 1075 1075 ext4 \
|
||||||
|
$primary{ } \
|
||||||
|
$defaultignore{ } \
|
||||||
|
method{ format } \
|
||||||
|
format{ } \
|
||||||
|
use_filesystem{ } \
|
||||||
|
filesystem{ ext4 } \
|
||||||
|
mountpoint{ /boot } \
|
||||||
|
. \
|
||||||
|
25770 25770 -1 ext4 \
|
||||||
|
$lvmok{ } \
|
||||||
|
lv_name{ root } \
|
||||||
|
method{ format } \
|
||||||
|
format{ } \
|
||||||
|
use_filesystem{ } \
|
||||||
|
filesystem{ ext4 } \
|
||||||
|
mountpoint{ / } \
|
||||||
|
.
|
||||||
|
|
||||||
|
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||||
|
d-i partman/choose_partition select finish
|
||||||
|
d-i partman/confirm boolean true
|
||||||
|
d-i partman/confirm_nooverwrite boolean true
|
||||||
|
|
||||||
|
### Software
|
||||||
|
d-i debconf/frontend select noninteractive
|
||||||
|
tasksel tasksel/first multiselect standard, ssh-server
|
||||||
|
|
||||||
|
d-i pkgsel/include string cloud-init curl qemu-guest-agent sudo vim
|
||||||
|
d-i pkgsel/upgrade select full-upgrade
|
||||||
|
d-i pkgsel/update-policy select none
|
||||||
|
d-i pkgsel/updatedb boolean true
|
||||||
|
|
||||||
|
### Bootloader
|
||||||
|
d-i grub-installer/only_debian boolean true
|
||||||
|
d-i grub-installer/with_other_os boolean true
|
||||||
|
d-i grub-installer/bootdev string default
|
||||||
|
|
||||||
|
### Late command (single declaration; multiple commands chained)
|
||||||
|
# 1) Remove filler LV so vg0 has free space after install
|
||||||
|
# 2) Enable root ssh login (same intent as your original)
|
||||||
|
d-i preseed/late_command string \
|
||||||
|
lvremove -f /dev/vg0/reserved || true; \
|
||||||
|
in-target sed -i 's/^#PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config || true
|
||||||
|
|
||||||
|
# Eject the installation media before rebooting
|
||||||
|
d-i cdrom-detect/eject boolean true
|
||||||
|
d-i cdrom-detect/eject seen true
|
||||||
|
|
||||||
|
### Finish
|
||||||
|
d-i finish-install/reboot_in_progress note
|
||||||
8
debian/13-trixie/scripts/crowdsec-configuration.sh
vendored
Normal file
8
debian/13-trixie/scripts/crowdsec-configuration.sh
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euf -o pipefail
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Enable write-ahead-logging (wal -- allowing more concurrency in SQLite that will improve performances in most scenarios.)
|
||||||
|
sed -i -E '/^db_config:/,/^[^[:space:]]/{s/^([[:space:]]*)type:[[:space:]]*sqlite$/&\
|
||||||
|
\1use_wal: true/}' /etc/crowdsec/config.yaml
|
||||||
370
debian/13-trixie/scripts/crowdsec-repo-setup.sh
vendored
Normal file
370
debian/13-trixie/scripts/crowdsec-repo-setup.sh
vendored
Normal file
|
|
@ -0,0 +1,370 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Inspired from packagecloud installation scripts
|
||||||
|
#
|
||||||
|
# #MIT License
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
#
|
||||||
|
# Crowdsec repositories installation script
|
||||||
|
#
|
||||||
|
# This script:
|
||||||
|
# - Requires `root` or `sudo` privileges to run
|
||||||
|
# - Attempts to detect your Linux distribution and version and configure your
|
||||||
|
# package management system for you.
|
||||||
|
# - Installs dependencies and recommendations without asking for confirmation.
|
||||||
|
# - Is POSIX compliant and can be run using bash or any POSIX-compliant shell
|
||||||
|
|
||||||
|
|
||||||
|
unknown_os() {
|
||||||
|
echo "Unfortunately, your operating system distribution and version are not supported by this script."
|
||||||
|
echo
|
||||||
|
echo "You can override the OS detection by setting os= and dist= prior to running this script."
|
||||||
|
echo "You can find a list of supported OSes and distributions on our website: https://packagecloud.io/docs#os_distro_version"
|
||||||
|
echo
|
||||||
|
echo "For example, to force Ubuntu Trusty: os=ubuntu dist=trusty ./script.sh"
|
||||||
|
echo
|
||||||
|
echo "Please file an issue at https://github.com/crowdsecurity/crowdsec"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_os() {
|
||||||
|
if [ -z "$os" ] && [ -z "$dist" ]; then
|
||||||
|
if [ -e /etc/os-release ]; then
|
||||||
|
. /etc/os-release
|
||||||
|
os=$ID
|
||||||
|
if [ "$os" = "poky" ]; then
|
||||||
|
dist="$VERSION_ID"
|
||||||
|
elif [ "$os" = "sles" ]; then
|
||||||
|
dist="$VERSION_ID"
|
||||||
|
os=opensuse
|
||||||
|
elif [ "$os" = "opensuse" ]; then
|
||||||
|
dist="$VERSION_ID"
|
||||||
|
elif [ "$os" = "opensuse-leap" ]; then
|
||||||
|
os=opensuse
|
||||||
|
dist="$VERSION_ID"
|
||||||
|
elif [ "$os" = "amzn" ]; then
|
||||||
|
dist="$VERSION_ID"
|
||||||
|
else
|
||||||
|
dist=$(echo "$VERSION_ID" | awk -F '.' '{ print $1 }')
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif command -v lsb_release >/dev/null; then
|
||||||
|
# get major version (e.g. '5' or '6')
|
||||||
|
dist=$(lsb_release -r | cut -f2 | awk -F '.' '{ print $1 }')
|
||||||
|
|
||||||
|
# get os (e.g. 'centos', 'redhatenterpriseserver', etc)
|
||||||
|
os=$(lsb_release -i | cut -f2 | awk '{ print tolower($1) }')
|
||||||
|
|
||||||
|
elif [ -e /etc/oracle-release ]; then
|
||||||
|
dist=$(cut -f5 --delimiter=' ' /etc/oracle-release | awk -F '.' '{ print $1 }')
|
||||||
|
os='ol'
|
||||||
|
|
||||||
|
elif [ -e /etc/fedora-release ]; then
|
||||||
|
dist=$(cut -f3 --delimiter=' ' /etc/fedora-release)
|
||||||
|
os='fedora'
|
||||||
|
|
||||||
|
elif [ -e /etc/redhat-release ]; then
|
||||||
|
os_hint=$(awk '{ print tolower($1) }' /etc/redhat-release)
|
||||||
|
if [ "$os_hint" = "centos" ]; then
|
||||||
|
dist=$(awk '{ print $3 }' /etc/redhat-release | awk -F '.' '{ print $1 }')
|
||||||
|
os='centos'
|
||||||
|
elif [ "$os_hint" = "scientific" ]; then
|
||||||
|
dist=$(awk '{ print $4 }' /etc/redhat-release | awk -F '.' '{ print $1 }')
|
||||||
|
os='scientific'
|
||||||
|
else
|
||||||
|
dist=$(awk '{ print tolower($7) }' /etc/redhat-release | cut -f1 --delimiter='.')
|
||||||
|
os='redhatenterpriseserver'
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif grep -q Amazon /etc/issue; then
|
||||||
|
dist='6'
|
||||||
|
os='aws'
|
||||||
|
else
|
||||||
|
unknown_os
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# remove whitespace from OS and dist name and transform to lowercase
|
||||||
|
os=$(echo "$os" | tr -d ' ' | tr '[:upper:]' '[:lower:]')
|
||||||
|
dist=$(echo "$dist" | tr -d ' ' | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
if [ -z "$dist" ]; then
|
||||||
|
echo "Detected operating system as $os."
|
||||||
|
else
|
||||||
|
echo "Detected operating system as $os/$dist."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$os" = "ol" ] || [ "$os" = "el" ] && [ "$dist" -gt 7 ]; then
|
||||||
|
_skip_pygpgme=1
|
||||||
|
else
|
||||||
|
_skip_pygpgme=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
gpg_check_deb() {
|
||||||
|
echo "Checking for gpg..."
|
||||||
|
if command -v gpg >/dev/null; then
|
||||||
|
echo "Detected gpg..."
|
||||||
|
else
|
||||||
|
echo "Installing gnupg for GPG verification..."
|
||||||
|
if ! apt-get install -y gnupg; then
|
||||||
|
echo "Unable to install GPG! Your base system has a problem; please check your default OS's package repositories because GPG should work."
|
||||||
|
echo "Repository installation aborted."
|
||||||
|
echo
|
||||||
|
echo "Please file an issue at https://github.com/crowdsecurity/crowdsec"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_check_deb() {
|
||||||
|
echo "Checking for curl..."
|
||||||
|
if command -v curl >/dev/null; then
|
||||||
|
echo "Detected curl..."
|
||||||
|
else
|
||||||
|
echo "Installing curl..."
|
||||||
|
|
||||||
|
if apt-get install -q -y curl; then
|
||||||
|
echo "Unable to install curl! Your base system has a problem; please check your default OS's package repositories because curl should work."
|
||||||
|
echo "Repository installation aborted."
|
||||||
|
echo
|
||||||
|
echo "Please file an issue at https://github.com/crowdsecurity/crowdsec"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_check_rpm() {
|
||||||
|
echo "Checking for curl..."
|
||||||
|
if command -v curl >/dev/null; then
|
||||||
|
echo "Detected curl..."
|
||||||
|
else
|
||||||
|
echo "Installing curl..."
|
||||||
|
yum install -d0 -e0 -y curl
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_check_zypper() {
|
||||||
|
echo "Checking for curl..."
|
||||||
|
if command -v curl >/dev/null; then
|
||||||
|
echo "Detected curl..."
|
||||||
|
else
|
||||||
|
echo "Installing curl..."
|
||||||
|
zypper install curl
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize_yum_repo() {
|
||||||
|
if [ "$_skip_pygpgme" = 0 ]; then
|
||||||
|
echo "Installing pygpgme to verify GPG signatures..."
|
||||||
|
yum install -y pygpgme --disablerepo="crowdsec_${repo}"
|
||||||
|
if ! rpm -qa | grep -qw pygpgme; then
|
||||||
|
echo
|
||||||
|
echo "WARNING: "
|
||||||
|
echo "The pygpgme package could not be installed. This means GPG verification is not possible for any RPM installed on your system. "
|
||||||
|
echo "To fix this, add a repository with pygpgme. Usually, the EPEL repository for your system will have this. "
|
||||||
|
echo "More information: https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# set the repo_gpgcheck option to 0
|
||||||
|
sed -i'' 's/repo_gpgcheck=1/repo_gpgcheck=0/' "/etc/yum.repos.d/crowdsec_${repo}.repo"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing yum-utils..."
|
||||||
|
yum install -y yum-utils --disablerepo="crowdsec_${repo}"
|
||||||
|
if ! rpm -qa | grep -qw yum-utils; then
|
||||||
|
echo
|
||||||
|
echo "WARNING: "
|
||||||
|
echo "The yum-utils package could not be installed. This means you may not be able to install source RPMs or use other yum features."
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Generating yum cache for crowdsec..."
|
||||||
|
yum -q makecache -y --disablerepo='*' --enablerepo="crowdsec_${repo}"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_debian_keyring() {
|
||||||
|
if [ "$os" = "debian" ]; then
|
||||||
|
echo "Installing debian-archive-keyring which is needed for installing "
|
||||||
|
echo "apt-transport-https on many Debian systems."
|
||||||
|
apt-get install -y debian-archive-keyring >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_apt_version() {
|
||||||
|
apt_version_full=$(apt-get -v | head -1 | awk '{ print $2 }')
|
||||||
|
apt_version_major=$(echo "$apt_version_full" | cut -d. -f1)
|
||||||
|
apt_version_minor=$(echo "$apt_version_full" | cut -d. -f2)
|
||||||
|
apt_version_modified="${apt_version_major}${apt_version_minor}0"
|
||||||
|
|
||||||
|
echo "Detected apt version as $apt_version_full"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if [ -z "$repo" ]; then
|
||||||
|
repo="crowdsec"
|
||||||
|
fi
|
||||||
|
|
||||||
|
detect_os
|
||||||
|
case $os in
|
||||||
|
ubuntu | debian | raspbian | linuxmint)
|
||||||
|
detect_apt_version
|
||||||
|
gpg_check_deb
|
||||||
|
curl_check_deb
|
||||||
|
apt_source_path="/etc/apt/sources.list.d/crowdsec_${repo}.list"
|
||||||
|
pre_reqs="apt-transport-https ca-certificates curl"
|
||||||
|
if [ -f "$apt_source_path" ]; then
|
||||||
|
echo
|
||||||
|
echo "The file $apt_source_path already exists: overwriting it."
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
# needed dependencies
|
||||||
|
apt-get update -qq >/dev/null
|
||||||
|
#shellcheck disable=SC2086
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq $pre_reqs >/dev/null
|
||||||
|
# gpg keys
|
||||||
|
gpg_key_url="https://packagecloud.io/crowdsec/${repo}/gpgkey"
|
||||||
|
apt_keyrings_dir="/etc/apt/keyrings"
|
||||||
|
gpg_keyring_path="$apt_keyrings_dir/crowdsec_${repo}-archive-keyring.gpg"
|
||||||
|
gpg_key_path_old="/etc/apt/trusted.gpg.d/crowdsec_${repo}.gpg"
|
||||||
|
echo
|
||||||
|
echo "Importing packagecloud gpg key... "
|
||||||
|
echo
|
||||||
|
|
||||||
|
# move gpg key to old path if apt version is older than 1.1
|
||||||
|
if [ "$apt_version_modified" -lt 110 ]; then
|
||||||
|
curl -fsSL "$gpg_key_url" | gpg --dearmor >"$gpg_key_path_old"
|
||||||
|
# grant 644 permisions to gpg key path old
|
||||||
|
chmod 0644 "$gpg_key_path_old"
|
||||||
|
|
||||||
|
# deletes the keyrings directory if it is empty
|
||||||
|
echo "Packagecloud gpg key imported to $gpg_key_path_old"
|
||||||
|
else
|
||||||
|
if [ ! -d "$apt_keyrings_dir" ]; then
|
||||||
|
install -d -m 0755 "$apt_keyrings_dir"
|
||||||
|
fi
|
||||||
|
# import the gpg key
|
||||||
|
curl -fsSL "$gpg_key_url" | gpg --dearmor >"$gpg_keyring_path"
|
||||||
|
# grant 644 permisions to gpg keyring path
|
||||||
|
chmod 0644 "$gpg_keyring_path"
|
||||||
|
|
||||||
|
echo "Packagecloud gpg key imported to $gpg_keyring_path"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "Installing ${apt_source_path}..."
|
||||||
|
echo
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/crowdsec_${repo}-archive-keyring.gpg] https://packagecloud.io/crowdsec/${repo}/any/ any main" >"$apt_source_path"
|
||||||
|
echo "deb-src [signed-by=/etc/apt/keyrings/crowdsec_${repo}-archive-keyring.gpg] https://packagecloud.io/crowdsec/${repo}/any/ any main" >>"$apt_source_path"
|
||||||
|
apt-get update -qq >/dev/null
|
||||||
|
|
||||||
|
;;
|
||||||
|
centos | rhel | fedora | redhatentrepriseserver | amzn | cloudlinux | almalinux | rocky | opensuse | ol)
|
||||||
|
if [ "$os" = "ol" ] && [ "$dist" = "7" ] || [ "$os" = "amzn" ] && [ "$dist" = "2" ]; then
|
||||||
|
rpm_repo_config_url="https://packagecloud.io/install/repositories/crowdsec/${repo}/config_file.repo?os=${os}&dist=${dist}&source=script"
|
||||||
|
else
|
||||||
|
rpm_repo_config_url="https://packagecloud.io/install/repositories/crowdsec/${repo}/config_file.repo?os=rpm_any&dist=rpm_any&source=script"
|
||||||
|
fi
|
||||||
|
if [ "$os" = "opensuse" ]; then
|
||||||
|
curl_check_zypper
|
||||||
|
rpm_repo_path=/etc/zypp/repos.d/crowdsec_${repo}.repo
|
||||||
|
else
|
||||||
|
curl_check_rpm
|
||||||
|
rpm_repo_path=/etc/yum.repos.d/crowdsec_${repo}.repo
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading repository file: $rpm_repo_config_url"
|
||||||
|
|
||||||
|
curl -sSf "$rpm_repo_config_url" >"$rpm_repo_path"
|
||||||
|
curl_exit_code=$?
|
||||||
|
if [ "$curl_exit_code" = "22" ]; then
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo "Unable to download repo config from: "
|
||||||
|
echo "$rpm_repo_config_url"
|
||||||
|
echo
|
||||||
|
echo "This usually happens if your operating system is not supported by "
|
||||||
|
echo "packagecloud.io, or this script's OS detection failed."
|
||||||
|
echo
|
||||||
|
echo "You can override the OS detection by setting os= and dist= prior to running this script."
|
||||||
|
echo "You can find a list of supported OSes and distributions on our website: https://packagecloud.io/docs#os_distro_version"
|
||||||
|
echo
|
||||||
|
echo "For example, to force CentOS 6: os=el dist=6 ./script.sh"
|
||||||
|
echo
|
||||||
|
echo "If you are running a supported OS, please file an issue at https://github.com/crowdsecurity/crowdsec."
|
||||||
|
[ -e "$rpm_repo_path" ] && rm "$rpm_repo_path"
|
||||||
|
exit 1
|
||||||
|
elif [ "$curl_exit_code" = "35" ] || [ "$curl_exit_code" = "60" ]; then
|
||||||
|
echo
|
||||||
|
echo "curl is unable to connect to packagecloud.io over TLS when running: "
|
||||||
|
echo " curl $rpm_repo_config_url"
|
||||||
|
echo
|
||||||
|
echo "This is usually due to one of two things:"
|
||||||
|
echo
|
||||||
|
echo " 1.) Missing CA root certificates (make sure the ca-certificates package is installed)"
|
||||||
|
echo " 2.) An old version of libssl. Try upgrading libssl on your system to a more recent version"
|
||||||
|
echo
|
||||||
|
echo "Contact support@crowdsec.net with information about your system for help."
|
||||||
|
[ -e "$rpm_repo_path" ] && rm "$rpm_repo_path"
|
||||||
|
exit 1
|
||||||
|
elif [ "$curl_exit_code" -gt "0" ]; then
|
||||||
|
echo
|
||||||
|
echo "Unable to run: "
|
||||||
|
echo " curl $rpm_repo_config_url"
|
||||||
|
echo
|
||||||
|
echo "Double check your curl installation and try again."
|
||||||
|
echo
|
||||||
|
echo "Please file an issue at https://github.com/crowdsecurity/crowdsec if you think the behavior is not intended"
|
||||||
|
[ -e "$rpm_repo_path" ] && rm "$rpm_repo_path"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "done."
|
||||||
|
fi
|
||||||
|
if [ "$os" = "opensuse" ]; then
|
||||||
|
zypper --gpg-auto-import-keys refresh "crowdsec_${repo}"
|
||||||
|
zypper --gpg-auto-import-keys refresh "crowdsec_${repo}-source"
|
||||||
|
else
|
||||||
|
echo "$os"
|
||||||
|
finalize_yum_repo
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Error This system is not supported (yet) by this script."
|
||||||
|
echo "Please have a look at documentation https://docs.crowdsec.net/ or"
|
||||||
|
echo "file an issue at https://github.com/crowdsecurity/crowdsec if you think"
|
||||||
|
echo "the behavior is not intended"
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "This script must be run as root"
|
||||||
|
echo
|
||||||
|
echo "file an issue at https://github.com/crowdsecurity/crowdsec if you think"
|
||||||
|
echo "the behavior is not intended"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
main
|
||||||
726
debian/13-trixie/scripts/tailscale.sh
vendored
Normal file
726
debian/13-trixie/scripts/tailscale.sh
vendored
Normal file
|
|
@ -0,0 +1,726 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) Tailscale Inc & contributors
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
# This script detects the current operating system, and installs
|
||||||
|
# Tailscale according to that OS's conventions.
|
||||||
|
#
|
||||||
|
# Environment variables:
|
||||||
|
# TRACK: Set to "stable" or "unstable" (default: stable)
|
||||||
|
# TAILSCALE_VERSION: Pin to a specific version (e.g., "1.88.4")
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# curl -fsSL https://tailscale.com/install.sh | sh
|
||||||
|
# curl -fsSL https://tailscale.com/install.sh | TAILSCALE_VERSION=1.88.4 sh
|
||||||
|
# curl -fsSL https://tailscale.com/install.sh | TRACK=unstable sh
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
# All the code is wrapped in a main function that gets called at the
|
||||||
|
# bottom of the file, so that a truncated partial download doesn't end
|
||||||
|
# up executing half a script.
|
||||||
|
main() {
|
||||||
|
# Step 1: detect the current linux distro, version, and packaging system.
|
||||||
|
#
|
||||||
|
# We rely on a combination of 'uname' and /etc/os-release to find
|
||||||
|
# an OS name and version, and from there work out what
|
||||||
|
# installation method we should be using.
|
||||||
|
#
|
||||||
|
# The end result of this step is that the following three
|
||||||
|
# variables are populated, if detection was successful.
|
||||||
|
OS=""
|
||||||
|
VERSION=""
|
||||||
|
PACKAGETYPE=""
|
||||||
|
APT_KEY_TYPE="" # Only for apt-based distros
|
||||||
|
APT_SYSTEMCTL_START=false # Only needs to be true for Kali
|
||||||
|
TRACK="${TRACK:-stable}"
|
||||||
|
TAILSCALE_VERSION="${TAILSCALE_VERSION:-}"
|
||||||
|
|
||||||
|
case "$TRACK" in
|
||||||
|
stable|unstable)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unsupported track $TRACK"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -f /etc/os-release ]; then
|
||||||
|
# /etc/os-release populates a number of shell variables. We care about the following:
|
||||||
|
# - ID: the short name of the OS (e.g. "debian", "freebsd")
|
||||||
|
# - VERSION_ID: the numeric release version for the OS, if any (e.g. "18.04")
|
||||||
|
# - VERSION_CODENAME: the codename of the OS release, if any (e.g. "buster")
|
||||||
|
# - UBUNTU_CODENAME: if it exists, use instead of VERSION_CODENAME
|
||||||
|
. /etc/os-release
|
||||||
|
VERSION_MAJOR="${VERSION_ID:-}"
|
||||||
|
VERSION_MAJOR="${VERSION_MAJOR%%.*}"
|
||||||
|
case "$ID" in
|
||||||
|
ubuntu|pop|neon|zorin|tuxedo)
|
||||||
|
OS="ubuntu"
|
||||||
|
if [ "${UBUNTU_CODENAME:-}" != "" ]; then
|
||||||
|
VERSION="$UBUNTU_CODENAME"
|
||||||
|
else
|
||||||
|
VERSION="$VERSION_CODENAME"
|
||||||
|
fi
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
# Third-party keyrings became the preferred method of
|
||||||
|
# installation in Ubuntu 20.04.
|
||||||
|
if [ "$VERSION_MAJOR" -lt 20 ]; then
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
debian)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="$VERSION_CODENAME"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
# Third-party keyrings became the preferred method of
|
||||||
|
# installation in Debian 11 (Bullseye).
|
||||||
|
if [ -z "${VERSION_ID:-}" ]; then
|
||||||
|
# rolling release. If you haven't kept current, that's on you.
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
# Parrot Security is a special case that uses ID=debian
|
||||||
|
elif [ "$NAME" = "Parrot Security" ]; then
|
||||||
|
# All versions new enough to have this behaviour prefer keyring
|
||||||
|
# and their VERSION_ID is not consistent with Debian.
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
# They don't specify the Debian version they're based off in os-release
|
||||||
|
# but Parrot 6 is based on Debian 12 Bookworm.
|
||||||
|
VERSION=bookworm
|
||||||
|
elif [ "$VERSION_MAJOR" -lt 11 ]; then
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
linuxmint)
|
||||||
|
if [ "${UBUNTU_CODENAME:-}" != "" ]; then
|
||||||
|
OS="ubuntu"
|
||||||
|
VERSION="$UBUNTU_CODENAME"
|
||||||
|
elif [ "${DEBIAN_CODENAME:-}" != "" ]; then
|
||||||
|
OS="debian"
|
||||||
|
VERSION="$DEBIAN_CODENAME"
|
||||||
|
else
|
||||||
|
OS="ubuntu"
|
||||||
|
VERSION="$VERSION_CODENAME"
|
||||||
|
fi
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
if [ "$VERSION_MAJOR" -lt 5 ]; then
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
elementary)
|
||||||
|
OS="ubuntu"
|
||||||
|
VERSION="$UBUNTU_CODENAME"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
if [ "$VERSION_MAJOR" -lt 6 ]; then
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
industrial-os)
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
if [ "$VERSION_MAJOR" -lt 5 ]; then
|
||||||
|
VERSION="buster"
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
VERSION="bullseye"
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
parrot|mendel)
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
if [ "$VERSION_MAJOR" -lt 5 ]; then
|
||||||
|
VERSION="buster"
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
VERSION="bullseye"
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
galliumos)
|
||||||
|
OS="ubuntu"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
VERSION="bionic"
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
;;
|
||||||
|
pureos|kaisen)
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
VERSION="bullseye"
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
;;
|
||||||
|
raspbian)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="$VERSION_CODENAME"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
# Third-party keyrings became the preferred method of
|
||||||
|
# installation in Raspbian 11 (Bullseye).
|
||||||
|
if [ "$VERSION_MAJOR" -lt 11 ]; then
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
kali)
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
APT_SYSTEMCTL_START=true
|
||||||
|
# Third-party keyrings became the preferred method of
|
||||||
|
# installation in Debian 11 (Bullseye), which Kali switched
|
||||||
|
# to in roughly 2021.x releases
|
||||||
|
if [ "$VERSION_MAJOR" -lt 2021 ]; then
|
||||||
|
# Kali VERSION_ID is "kali-rolling", which isn't distinguishing
|
||||||
|
VERSION="buster"
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
else
|
||||||
|
VERSION="bullseye"
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
Deepin|deepin) # https://github.com/tailscale/tailscale/issues/7862
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
if [ "$VERSION_MAJOR" -lt 20 ]; then
|
||||||
|
APT_KEY_TYPE="legacy"
|
||||||
|
VERSION="buster"
|
||||||
|
else
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
VERSION="bullseye"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
pika)
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
# All versions of PikaOS are new enough to prefer keyring
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
# Older versions of PikaOS are based on Ubuntu rather than Debian
|
||||||
|
if [ "$VERSION_MAJOR" -lt 4 ]; then
|
||||||
|
OS="ubuntu"
|
||||||
|
VERSION="$UBUNTU_CODENAME"
|
||||||
|
else
|
||||||
|
OS="debian"
|
||||||
|
VERSION="$DEBIAN_CODENAME"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
sparky)
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
VERSION="$DEBIAN_CODENAME"
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
;;
|
||||||
|
centos)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="$VERSION_MAJOR"
|
||||||
|
PACKAGETYPE="dnf"
|
||||||
|
if [ "$VERSION" = "7" ]; then
|
||||||
|
PACKAGETYPE="yum"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
ol)
|
||||||
|
OS="oracle"
|
||||||
|
VERSION="$VERSION_MAJOR"
|
||||||
|
PACKAGETYPE="dnf"
|
||||||
|
if [ "$VERSION" = "7" ]; then
|
||||||
|
PACKAGETYPE="yum"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
rhel|miraclelinux)
|
||||||
|
OS="$ID"
|
||||||
|
if [ "$ID" = "miraclelinux" ]; then
|
||||||
|
OS="rhel"
|
||||||
|
fi
|
||||||
|
VERSION="$VERSION_MAJOR"
|
||||||
|
PACKAGETYPE="dnf"
|
||||||
|
if [ "$VERSION" = "7" ]; then
|
||||||
|
PACKAGETYPE="yum"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
fedora)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION=""
|
||||||
|
PACKAGETYPE="dnf"
|
||||||
|
;;
|
||||||
|
rocky|almalinux|nobara|openmandriva|sangoma|risios|cloudlinux|alinux|fedora-asahi-remix|ultramarine)
|
||||||
|
OS="fedora"
|
||||||
|
VERSION=""
|
||||||
|
PACKAGETYPE="dnf"
|
||||||
|
;;
|
||||||
|
amzn)
|
||||||
|
OS="amazon-linux"
|
||||||
|
VERSION="$VERSION_ID"
|
||||||
|
PACKAGETYPE="yum"
|
||||||
|
;;
|
||||||
|
xenenterprise)
|
||||||
|
OS="centos"
|
||||||
|
VERSION="$VERSION_MAJOR"
|
||||||
|
PACKAGETYPE="yum"
|
||||||
|
;;
|
||||||
|
opensuse-leap|sles)
|
||||||
|
OS="opensuse"
|
||||||
|
VERSION="leap/$VERSION_ID"
|
||||||
|
PACKAGETYPE="zypper"
|
||||||
|
;;
|
||||||
|
opensuse-tumbleweed)
|
||||||
|
OS="opensuse"
|
||||||
|
VERSION="tumbleweed"
|
||||||
|
PACKAGETYPE="zypper"
|
||||||
|
;;
|
||||||
|
sle-micro-rancher)
|
||||||
|
OS="opensuse"
|
||||||
|
VERSION="leap/15.4"
|
||||||
|
PACKAGETYPE="zypper"
|
||||||
|
;;
|
||||||
|
arch|archarm|endeavouros|blendos|garuda|archcraft|cachyos)
|
||||||
|
OS="arch"
|
||||||
|
VERSION="" # rolling release
|
||||||
|
PACKAGETYPE="pacman"
|
||||||
|
;;
|
||||||
|
manjaro|manjaro-arm|biglinux)
|
||||||
|
OS="manjaro"
|
||||||
|
VERSION="" # rolling release
|
||||||
|
PACKAGETYPE="pacman"
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="$VERSION_ID"
|
||||||
|
PACKAGETYPE="apk"
|
||||||
|
;;
|
||||||
|
postmarketos)
|
||||||
|
OS="alpine"
|
||||||
|
VERSION="$VERSION_ID"
|
||||||
|
PACKAGETYPE="apk"
|
||||||
|
;;
|
||||||
|
nixos)
|
||||||
|
echo "Please add Tailscale to your NixOS configuration directly:"
|
||||||
|
echo
|
||||||
|
echo "services.tailscale.enable = true;"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
bazzite)
|
||||||
|
echo "Bazzite comes with Tailscale installed by default."
|
||||||
|
echo "Please enable Tailscale by running the following commands as root:"
|
||||||
|
echo
|
||||||
|
echo "ujust enable-tailscale"
|
||||||
|
echo "tailscale up"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
void)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="" # rolling release
|
||||||
|
PACKAGETYPE="xbps"
|
||||||
|
;;
|
||||||
|
gentoo)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="" # rolling release
|
||||||
|
PACKAGETYPE="emerge"
|
||||||
|
;;
|
||||||
|
freebsd)
|
||||||
|
OS="$ID"
|
||||||
|
VERSION="$VERSION_MAJOR"
|
||||||
|
PACKAGETYPE="pkg"
|
||||||
|
;;
|
||||||
|
osmc)
|
||||||
|
OS="debian"
|
||||||
|
PACKAGETYPE="apt"
|
||||||
|
VERSION="bullseye"
|
||||||
|
APT_KEY_TYPE="keyring"
|
||||||
|
;;
|
||||||
|
photon)
|
||||||
|
OS="photon"
|
||||||
|
VERSION="$VERSION_MAJOR"
|
||||||
|
PACKAGETYPE="tdnf"
|
||||||
|
;;
|
||||||
|
steamos)
|
||||||
|
echo "To install Tailscale on SteamOS, please follow the instructions here:"
|
||||||
|
echo "https://github.com/tailscale-dev/deck-tailscale"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
# TODO: wsl?
|
||||||
|
# TODO: synology? qnap?
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we failed to detect something through os-release, consult
|
||||||
|
# uname and try to infer things from that.
|
||||||
|
if [ -z "$OS" ]; then
|
||||||
|
if type uname >/dev/null 2>&1; then
|
||||||
|
case "$(uname)" in
|
||||||
|
FreeBSD)
|
||||||
|
# FreeBSD before 12.2 doesn't have
|
||||||
|
# /etc/os-release, so we wouldn't have found it in
|
||||||
|
# the os-release probing above.
|
||||||
|
OS="freebsd"
|
||||||
|
VERSION="$(freebsd-version | cut -f1 -d.)"
|
||||||
|
PACKAGETYPE="pkg"
|
||||||
|
;;
|
||||||
|
OpenBSD)
|
||||||
|
OS="openbsd"
|
||||||
|
VERSION="$(uname -r)"
|
||||||
|
PACKAGETYPE=""
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
OS="macos"
|
||||||
|
VERSION="$(sw_vers -productVersion | cut -f1-2 -d.)"
|
||||||
|
PACKAGETYPE="appstore"
|
||||||
|
;;
|
||||||
|
Linux)
|
||||||
|
OS="other-linux"
|
||||||
|
VERSION=""
|
||||||
|
PACKAGETYPE=""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ideally we want to use curl, but on some installs we
|
||||||
|
# only have wget. Detect and use what's available.
|
||||||
|
CURL=
|
||||||
|
if type curl >/dev/null; then
|
||||||
|
CURL="curl -fsSL"
|
||||||
|
elif type wget >/dev/null; then
|
||||||
|
CURL="wget -q -O-"
|
||||||
|
fi
|
||||||
|
if [ -z "$CURL" ]; then
|
||||||
|
echo "The installer needs either curl or wget to download files."
|
||||||
|
echo "Please install either curl or wget to proceed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEST_URL="https://pkgs.tailscale.com/"
|
||||||
|
RC=0
|
||||||
|
TEST_OUT=$($CURL "$TEST_URL" 2>&1) || RC=$?
|
||||||
|
if [ $RC != 0 ]; then
|
||||||
|
echo "The installer cannot reach $TEST_URL"
|
||||||
|
echo "Please make sure that your machine has internet access."
|
||||||
|
echo "Test output:"
|
||||||
|
echo $TEST_OUT
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 2: having detected an OS we support, is it one of the
|
||||||
|
# versions we support?
|
||||||
|
OS_UNSUPPORTED=
|
||||||
|
case "$OS" in
|
||||||
|
ubuntu|debian|raspbian|centos|oracle|rhel|amazon-linux|opensuse|photon)
|
||||||
|
# Check with the package server whether a given version is supported.
|
||||||
|
URL="https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/installer-supported"
|
||||||
|
$CURL "$URL" 2> /dev/null | grep -q OK || OS_UNSUPPORTED=1
|
||||||
|
;;
|
||||||
|
fedora)
|
||||||
|
# All versions supported, no version checking required.
|
||||||
|
;;
|
||||||
|
arch)
|
||||||
|
# Rolling release, no version checking needed.
|
||||||
|
;;
|
||||||
|
manjaro)
|
||||||
|
# Rolling release, no version checking needed.
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
# All versions supported, no version checking needed.
|
||||||
|
# TODO: is that true? When was tailscale packaged?
|
||||||
|
;;
|
||||||
|
void)
|
||||||
|
# Rolling release, no version checking needed.
|
||||||
|
;;
|
||||||
|
gentoo)
|
||||||
|
# Rolling release, no version checking needed.
|
||||||
|
;;
|
||||||
|
freebsd)
|
||||||
|
if [ "$VERSION" != "12" ] && \
|
||||||
|
[ "$VERSION" != "13" ] && \
|
||||||
|
[ "$VERSION" != "14" ] && \
|
||||||
|
[ "$VERSION" != "15" ]
|
||||||
|
then
|
||||||
|
OS_UNSUPPORTED=1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
openbsd)
|
||||||
|
OS_UNSUPPORTED=1
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
# We delegate macOS installation to the app store, it will
|
||||||
|
# perform version checks for us.
|
||||||
|
;;
|
||||||
|
other-linux)
|
||||||
|
OS_UNSUPPORTED=1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
OS_UNSUPPORTED=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [ "$OS_UNSUPPORTED" = "1" ]; then
|
||||||
|
case "$OS" in
|
||||||
|
other-linux)
|
||||||
|
echo "Couldn't determine what kind of Linux is running."
|
||||||
|
echo "You could try the static binaries at:"
|
||||||
|
echo "https://pkgs.tailscale.com/$TRACK/#static"
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
echo "Couldn't determine what operating system you're running."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "$OS $VERSION isn't supported by this script yet."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo
|
||||||
|
echo "If you'd like us to support your system better, please email support@tailscale.com"
|
||||||
|
echo "and tell us what OS you're running."
|
||||||
|
echo
|
||||||
|
echo "Please include the following information we gathered from your system:"
|
||||||
|
echo
|
||||||
|
echo "OS=$OS"
|
||||||
|
echo "VERSION=$VERSION"
|
||||||
|
echo "PACKAGETYPE=$PACKAGETYPE"
|
||||||
|
if type uname >/dev/null 2>&1; then
|
||||||
|
echo "UNAME=$(uname -a)"
|
||||||
|
else
|
||||||
|
echo "UNAME="
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
if [ -f /etc/os-release ]; then
|
||||||
|
cat /etc/os-release
|
||||||
|
else
|
||||||
|
echo "No /etc/os-release"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 3: work out if we can run privileged commands, and if so,
|
||||||
|
# how.
|
||||||
|
CAN_ROOT=
|
||||||
|
SUDO=
|
||||||
|
if [ "$(id -u)" = 0 ]; then
|
||||||
|
CAN_ROOT=1
|
||||||
|
SUDO=""
|
||||||
|
elif type sudo >/dev/null; then
|
||||||
|
CAN_ROOT=1
|
||||||
|
SUDO="sudo"
|
||||||
|
elif type doas >/dev/null; then
|
||||||
|
CAN_ROOT=1
|
||||||
|
SUDO="doas"
|
||||||
|
fi
|
||||||
|
if [ "$CAN_ROOT" != "1" ]; then
|
||||||
|
echo "This installer needs to run commands as root."
|
||||||
|
echo "We tried looking for 'sudo' and 'doas', but couldn't find them."
|
||||||
|
echo "Either re-run this script as root, or set up sudo/doas."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Step 4: run the installation.
|
||||||
|
OSVERSION="$OS"
|
||||||
|
[ "$VERSION" != "" ] && OSVERSION="$OSVERSION $VERSION"
|
||||||
|
|
||||||
|
# Prepare package name with optional version
|
||||||
|
PACKAGE_NAME="tailscale"
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
echo "Installing Tailscale $TAILSCALE_VERSION for $OSVERSION, using method $PACKAGETYPE"
|
||||||
|
else
|
||||||
|
echo "Installing Tailscale for $OSVERSION, using method $PACKAGETYPE"
|
||||||
|
fi
|
||||||
|
case "$PACKAGETYPE" in
|
||||||
|
apt)
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
if [ "$APT_KEY_TYPE" = "legacy" ] && ! type gpg >/dev/null; then
|
||||||
|
$SUDO apt-get update
|
||||||
|
$SUDO apt-get install -y gnupg
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -x
|
||||||
|
$SUDO mkdir -p --mode=0755 /usr/share/keyrings
|
||||||
|
case "$APT_KEY_TYPE" in
|
||||||
|
legacy)
|
||||||
|
$CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.asc" | $SUDO apt-key add -
|
||||||
|
$CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.list" | $SUDO tee /etc/apt/sources.list.d/tailscale.list
|
||||||
|
$SUDO chmod 0644 /etc/apt/sources.list.d/tailscale.list
|
||||||
|
;;
|
||||||
|
keyring)
|
||||||
|
$CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.noarmor.gpg" | $SUDO tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
|
||||||
|
$SUDO chmod 0644 /usr/share/keyrings/tailscale-archive-keyring.gpg
|
||||||
|
$CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.tailscale-keyring.list" | $SUDO tee /etc/apt/sources.list.d/tailscale.list
|
||||||
|
$SUDO chmod 0644 /etc/apt/sources.list.d/tailscale.list
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
$SUDO apt-get update
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
$SUDO apt-get install -y "tailscale=$TAILSCALE_VERSION" tailscale-archive-keyring
|
||||||
|
else
|
||||||
|
$SUDO apt-get install -y tailscale tailscale-archive-keyring
|
||||||
|
fi
|
||||||
|
if [ "$APT_SYSTEMCTL_START" = "true" ]; then
|
||||||
|
$SUDO systemctl enable --now tailscaled
|
||||||
|
$SUDO systemctl start tailscaled
|
||||||
|
fi
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
yum)
|
||||||
|
set -x
|
||||||
|
$SUDO yum install yum-utils -y
|
||||||
|
$SUDO yum-config-manager -y --add-repo "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
$SUDO yum install "tailscale-$TAILSCALE_VERSION" -y
|
||||||
|
else
|
||||||
|
$SUDO yum install tailscale -y
|
||||||
|
fi
|
||||||
|
$SUDO systemctl enable --now tailscaled
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
dnf)
|
||||||
|
# DNF 5 has a different argument format; determine which one we have.
|
||||||
|
DNF_VERSION="3"
|
||||||
|
if LANG=C.UTF-8 dnf --version | grep -q '^dnf5 version'; then
|
||||||
|
DNF_VERSION="5"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The 'config-manager' plugin wasn't implemented when
|
||||||
|
# DNF5 was released; detect that and use the old
|
||||||
|
# version if necessary.
|
||||||
|
if [ "$DNF_VERSION" = "5" ]; then
|
||||||
|
set -x
|
||||||
|
$SUDO dnf install -y 'dnf-command(config-manager)' && DNF_HAVE_CONFIG_MANAGER=1 || DNF_HAVE_CONFIG_MANAGER=0
|
||||||
|
set +x
|
||||||
|
|
||||||
|
if [ "$DNF_HAVE_CONFIG_MANAGER" != "1" ]; then
|
||||||
|
if type dnf-3 >/dev/null; then
|
||||||
|
DNF_VERSION="3"
|
||||||
|
else
|
||||||
|
echo "dnf 5 detected, but 'dnf-command(config-manager)' not available and dnf-3 not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -x
|
||||||
|
if [ "$DNF_VERSION" = "3" ]; then
|
||||||
|
$SUDO dnf install -y 'dnf-command(config-manager)'
|
||||||
|
$SUDO dnf config-manager --add-repo "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
|
||||||
|
elif [ "$DNF_VERSION" = "5" ]; then
|
||||||
|
# Already installed config-manager, above.
|
||||||
|
$SUDO dnf config-manager addrepo --overwrite --from-repofile="https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
|
||||||
|
else
|
||||||
|
echo "unexpected: unknown dnf version $DNF_VERSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
$SUDO dnf install -y "tailscale-$TAILSCALE_VERSION"
|
||||||
|
else
|
||||||
|
$SUDO dnf install -y tailscale
|
||||||
|
fi
|
||||||
|
$SUDO systemctl enable --now tailscaled
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
tdnf)
|
||||||
|
set -x
|
||||||
|
curl -fsSL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo" > /etc/yum.repos.d/tailscale.repo
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
$SUDO tdnf install -y "tailscale-$TAILSCALE_VERSION"
|
||||||
|
else
|
||||||
|
$SUDO tdnf install -y tailscale
|
||||||
|
fi
|
||||||
|
$SUDO systemctl enable --now tailscaled
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
zypper)
|
||||||
|
set -x
|
||||||
|
$SUDO rpm --import "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/repo.gpg"
|
||||||
|
$SUDO zypper --non-interactive ar -g -r "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
|
||||||
|
$SUDO zypper --non-interactive --gpg-auto-import-keys refresh
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
$SUDO zypper --non-interactive install "tailscale=$TAILSCALE_VERSION"
|
||||||
|
else
|
||||||
|
$SUDO zypper --non-interactive install tailscale
|
||||||
|
fi
|
||||||
|
$SUDO systemctl enable --now tailscaled
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
pacman)
|
||||||
|
set -x
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
echo "Warning: Arch Linux maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
|
||||||
|
$SUDO pacman -S "tailscale=$TAILSCALE_VERSION" --noconfirm
|
||||||
|
else
|
||||||
|
$SUDO pacman -S tailscale --noconfirm
|
||||||
|
fi
|
||||||
|
$SUDO systemctl enable --now tailscaled
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
pkg)
|
||||||
|
set -x
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
echo "Warning: FreeBSD maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
|
||||||
|
$SUDO pkg install --yes "tailscale-$TAILSCALE_VERSION"
|
||||||
|
else
|
||||||
|
$SUDO pkg install --yes tailscale
|
||||||
|
fi
|
||||||
|
$SUDO service tailscaled enable
|
||||||
|
$SUDO service tailscaled start
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
apk)
|
||||||
|
set -x
|
||||||
|
if ! grep -Eq '^http.*/community$' /etc/apk/repositories; then
|
||||||
|
if type setup-apkrepos >/dev/null; then
|
||||||
|
$SUDO setup-apkrepos -c -1
|
||||||
|
else
|
||||||
|
echo "installing tailscale requires the community repo to be enabled in /etc/apk/repositories"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
echo "Warning: Alpine Linux maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
|
||||||
|
$SUDO apk add "tailscale=$TAILSCALE_VERSION"
|
||||||
|
else
|
||||||
|
$SUDO apk add tailscale
|
||||||
|
fi
|
||||||
|
$SUDO rc-update add tailscale
|
||||||
|
$SUDO rc-service tailscale start
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
xbps)
|
||||||
|
set -x
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
echo "Warning: Void Linux maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
|
||||||
|
$SUDO xbps-install "tailscale-$TAILSCALE_VERSION" -y
|
||||||
|
else
|
||||||
|
$SUDO xbps-install tailscale -y
|
||||||
|
fi
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
emerge)
|
||||||
|
set -x
|
||||||
|
if [ -n "$TAILSCALE_VERSION" ]; then
|
||||||
|
echo "Warning: Gentoo maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
|
||||||
|
$SUDO emerge --ask=n "=net-vpn/tailscale-$TAILSCALE_VERSION"
|
||||||
|
else
|
||||||
|
$SUDO emerge --ask=n net-vpn/tailscale
|
||||||
|
fi
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
appstore)
|
||||||
|
set -x
|
||||||
|
open "https://apps.apple.com/us/app/tailscale/id1475387142"
|
||||||
|
set +x
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unexpected: unknown package type $PACKAGETYPE"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Installation complete! Log in to start using Tailscale by running:"
|
||||||
|
echo
|
||||||
|
if [ -z "$SUDO" ]; then
|
||||||
|
echo "tailscale up"
|
||||||
|
else
|
||||||
|
echo "$SUDO tailscale up"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
1
debian/13-trixie/variables-common.pkr.hcl
vendored
Symbolic link
1
debian/13-trixie/variables-common.pkr.hcl
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../variables-common.pkr.hcl
|
||||||
67
debian/13-trixie/variables.pkr.hcl
vendored
Normal file
67
debian/13-trixie/variables.pkr.hcl
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Variables
|
||||||
|
variable "template_vm_id" {
|
||||||
|
type = string
|
||||||
|
default = "65000"
|
||||||
|
description = "The VM ID of the Proxmox template to use for building the image"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "mac_address" {
|
||||||
|
type = string
|
||||||
|
default = "BC:24:11:00:13:37"
|
||||||
|
description = "The MAC address to assign to the VM's network adapter"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "iso_url" {
|
||||||
|
type = string
|
||||||
|
default = "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.4.0-amd64-netinst.iso"
|
||||||
|
description = "The URL to download the Debian 13 Trixie ISO"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "iso_checksum" {
|
||||||
|
type = string
|
||||||
|
default = "file:https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS"
|
||||||
|
description = "ISO checksum (SHA256 or checksum file URL)"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_storage_pool" {
|
||||||
|
type = string
|
||||||
|
default = "ceph-pool"
|
||||||
|
description = "The Proxmox storage pool to use for the VM disk"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "iso_storage_pool" {
|
||||||
|
type = string
|
||||||
|
default = "cephfs"
|
||||||
|
description = "The Proxmox storage pool to use for the ISO"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "template_cpu_type" {
|
||||||
|
type = string
|
||||||
|
default = "host"
|
||||||
|
description = "The CPU type for the Proxmox template"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "network_bridge" {
|
||||||
|
type = string
|
||||||
|
default = "vmbr108"
|
||||||
|
description = "The network bridge to attach the VM to"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_node" {
|
||||||
|
type = string
|
||||||
|
default = "pve1"
|
||||||
|
description = "The Proxmox node to use for building the image"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "install_finished_inform_port" {
|
||||||
|
type = string
|
||||||
|
default = "10000"
|
||||||
|
description = "The server port to inform when installation is finished"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# local values
|
||||||
|
local "timestamp" {
|
||||||
|
expression = formatdate("YYYYMMDD-hhMMss-ZZZ", timestamp())
|
||||||
|
}
|
||||||
1
favicon.svg
Normal file
1
favicon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><path d="m99.5 62.4 165 95.4V512l-165-95.4zm247 41.1L167.2 0v72.3l122.2 71.4v216.8l58 33c35.7 20.5 65.1 8.9 65.1-27.7V206c-.8-35.6-30.3-82-66-102.5" style="fill-rule:evenodd;clip-rule:evenodd;fill:#02a8ef"/></svg>
|
||||||
|
After Width: | Height: | Size: 296 B |
|
|
@ -21,10 +21,10 @@ flag "-i --install-finished-inform-port <port>" help="Server port to inform when
|
||||||
'''
|
'''
|
||||||
run = '''
|
run = '''
|
||||||
mise run lint ${usage_dir?}
|
mise run lint ${usage_dir?}
|
||||||
[[ -z "${usage_install_finished_inform_port}" ]] && packer build ${usage_dir?}
|
[[ -z "${usage_install_finished_inform_port}" ]] && packer build ${usage_dir?} || true
|
||||||
[[ -n "${usage_install_finished_inform_port}" ]] && packer build \
|
[[ -n "${usage_install_finished_inform_port}" ]] && packer build \
|
||||||
-var "install_finished_inform_port=${usage_install_finished_inform_port?}" \
|
-var "install_finished_inform_port=${usage_install_finished_inform_port?}" \
|
||||||
${usage_dir?}
|
${usage_dir?} || true
|
||||||
'''
|
'''
|
||||||
|
|
||||||
[tasks.build-luks]
|
[tasks.build-luks]
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ variable "proxmox_skip_tls_verify" {
|
||||||
|
|
||||||
variable "source_proxmox_http_interface" {
|
variable "source_proxmox_http_interface" {
|
||||||
type = string
|
type = string
|
||||||
default = "en18"
|
default = "en17"
|
||||||
description = "The network interface to use for the Proxmox HTTP source"
|
description = "The network interface to use for the Proxmox HTTP source"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue