├── README.md ├── screenshot.png ├── sysctl.conf ├── void-infect.sh └── void-install.sh /README.md: -------------------------------------------------------------------------------- 1 | # Void Linux VPS Installer 2 | 3 | Script for replacing existing Linux system with Void Linux on VPS servers. 4 | 5 | Tested with Debian, Ubuntu and CentOS 6 | 7 | Tested on VDSina.com, FirstByte.pro 8 | 9 | ![screenshot](https://github.com/user-attachments/assets/bbab2376-2e5d-4bce-95bd-fe478c8b1bbc) 10 | 11 | ## Prerequisites 12 | - Root access 13 | - SSH keys in `/root/.ssh/authorized_keys` 14 | - Installation time: ~2 minutes 15 | 16 | ## Usage 17 | ```bash 18 | wget https://raw.githubusercontent.com/Jipok/void-infect/refs/heads/master/void-infect.sh 19 | chmod +x void-infect.sh 20 | ./void-infect.sh 21 | ``` 22 | 23 | The script automatically: 24 | - Downloads and configures Void Linux rootfs 25 | - Installs essential packages and [Cute-bash](https://github.com/Jipok/Cute-bash) 26 | - Tune sysctl 27 | - Replaces existing OS and reboots 28 | 29 | No manual intervention required. Just run and wait for the reboot. 30 | 31 | # Home Server Edition 32 | 33 | For installing Void Linux on a physical home server, use the alternative script: 34 | 35 | ```bash 36 | wget https://raw.githubusercontent.com/Jipok/void-infect/refs/heads/master/void-install.sh 37 | chmod +x void-install.sh 38 | nano void-install.sh # Change settings in file header 39 | ./void-install.sh /dev/sdX # Replace with your target disk 40 | ``` 41 | **Note: This script must be run from a LiveUSB environment or when installing to a secondary disk that's not currently hosting the running system.** 42 | 43 | ![IMG_20250303_205030_651](https://github.com/user-attachments/assets/706f4e09-6054-4ca3-ad30-4d8585498f6f) 44 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jipok/void-infect/2efa5c8d8d7830b4937f90dfdbb353fdc854a356/screenshot.png -------------------------------------------------------------------------------- /sysctl.conf: -------------------------------------------------------------------------------- 1 | # Installed by https://github.com/Jipok/void-infect 2 | 3 | ############################################################################## 4 | ## Basic Security Settings 5 | ############################################################################## 6 | 7 | kernel.sysrq = 0 # Disable SysRq keys to prevent unauthorized emergency commands in production 8 | kernel.core_uses_pid = 1 # Append process ID to core dump filenames to ensure uniqueness 9 | kernel.pid_max = 65535 # Increase maximum process ID count 10 | 11 | kernel.randomize_va_space = 2 # Enable full address space randomization (usually default) 12 | fs.suid_dumpable = 0 # Disable core dumps for setuid programs 13 | kernel.kptr_restrict = 1 # Restrict exposure of kernel pointers to non-root users (enhances security) 14 | kernel.yama.ptrace_scope = 1 # Restrict ptrace scope to descendant processes only (enhances security) 15 | 16 | ############################################################################## 17 | ## Memory and Performance Tuning 18 | ############################################################################## 19 | 20 | fs.file-max = 209708 # Maximum number of open file handles 21 | 22 | vm.swappiness = 10 # Lower swappiness to favor RAM usage over swap 23 | vm.overcommit_memory = 0 # Use heuristic memory overcommit handling 24 | vm.overcommit_ratio = 50 # Set memory overcommit ratio to 50% 25 | 26 | vm.min_free_kbytes = 65535 # Reserve minimum free memory in kB 27 | 28 | # Tuning dirty pages behavior – adjust based on workload 29 | vm.dirty_ratio = 20 30 | vm.dirty_background_ratio = 5 31 | 32 | # I/O and cache tuning 33 | fs.aio-max-nr = 1048576 # Increase maximum concurrent asynchronous I/O operations 34 | vm.vfs_cache_pressure = 50 # Reduce pressure on VFS cache to favor inode/dentry caching 35 | 36 | ############################################################################## 37 | ## Network Security (IPv4 and IPv6) 38 | ############################################################################## 39 | 40 | # Enable SYN cookies to mitigate SYN flood attacks 41 | net.ipv4.tcp_syncookies = 1 42 | 43 | # Enable IP forwarding for Docker, LXC, routers, etc 44 | net.ipv4.ip_forward = 1 45 | net.ipv4.conf.all.forwarding = 1 46 | net.ipv4.conf.default.forwarding = 1 47 | net.ipv6.conf.all.forwarding = 1 48 | net.ipv6.conf.default.forwarding = 1 49 | 50 | # Disable source routing to prevent IP spoofing and routing manipulation 51 | net.ipv4.conf.all.accept_source_route = 0 52 | net.ipv4.conf.default.accept_source_route = 0 53 | net.ipv4.conf.all.accept_redirects = 0 54 | net.ipv4.conf.default.accept_redirects = 0 55 | net.ipv4.conf.all.secure_redirects = 0 56 | net.ipv4.conf.default.secure_redirects = 0 57 | 58 | # Enable Reverse Path Filtering against IP spoofing 59 | net.ipv4.conf.all.rp_filter = 1 60 | net.ipv4.conf.default.rp_filter = 1 61 | 62 | # Log suspicious ("martian") packets 63 | net.ipv4.conf.all.log_martians = 1 64 | net.ipv4.conf.default.log_martians = 1 65 | 66 | # Additional ICMP tweaks for security 67 | net.ipv4.icmp_echo_ignore_broadcasts = 1 # Drop ICMP echo requests sent to broadcast addresses to thwart smurf attacks 68 | net.ipv4.icmp_ignore_bogus_error_responses = 1 # Ignore bogus ICMP error responses 69 | 70 | # Enable temporary IPv6 addresses to enhance privacy and limit tracking 71 | net.ipv6.conf.all.use_tempaddr = 2 72 | net.ipv6.conf.default.use_tempaddr = 2 73 | 74 | ############################################################################## 75 | ## Network Performance Tuning (TCP) 76 | ############################################################################## 77 | 78 | net.ipv4.tcp_window_scaling = 1 # Enable TCP window scaling 79 | 80 | # TCP buffer sizes: min, default, max – tweak these values under heavy network load 81 | net.ipv4.tcp_rmem = 4096 87380 16777216 82 | net.ipv4.tcp_wmem = 4096 65536 16777216 83 | net.core.rmem_max = 16777216 # Maximum OS receive buffer size 84 | net.core.wmem_max = 16777216 # Maximum OS send buffer size 85 | 86 | # Set default queuing discipline – 'fq' is a balanced choice; you may choose fq_codel if bufferbloat is an issue 87 | net.core.default_qdisc = fq 88 | 89 | # Congestion control – BBR can improve performance on high-latency links (requires kernel ≥ 4.9 and tcp_bbr module) 90 | net.ipv4.tcp_congestion_control = bbr 91 | 92 | # Increase maximum number of queued connection requests 93 | net.core.somaxconn = 1024 94 | 95 | # Enable TCP Fast Open to reduce latency on subsequent connections (verify compatibility with your firewall) 96 | net.ipv4.tcp_fastopen = 3 97 | 98 | ## TCP Connection Handling 99 | net.ipv4.tcp_max_syn_backlog = 4096 # Increase max queued SYN packets for high connection rates 100 | net.core.netdev_max_backlog = 5000 # Expand device input queue to handle burst network traffic 101 | net.ipv4.tcp_max_tw_buckets = 65536 # Increase max number of sockets in TIME_WAIT for many short-lived connections 102 | net.ipv4.tcp_tw_reuse = 1 # Enable reuse of sockets in TIME_WAIT for new connections 103 | net.ipv4.tcp_fin_timeout = 30 # Reduce FIN_WAIT timeout to free closed connection resources faster 104 | net.ipv4.tcp_slow_start_after_idle = 0 # Disable TCP slow start after idle periods for immediate full bandwidth utilization 105 | 106 | ## TCP Keepalive and MTU Probing 107 | net.ipv4.tcp_keepalive_time = 300 # Reduced from default (7200s) to quickly detect idle/dead connections 108 | net.ipv4.tcp_keepalive_intvl = 30 # Set TCP keepalive probe interval to 30 seconds 109 | net.ipv4.tcp_keepalive_probes = 5 # Set number of keepalive probes before declaring the connection dead 110 | net.ipv4.tcp_mtu_probing = 1 # Enable TCP MTU probing (useful in VPN environments or when PMTU issues occur) 111 | 112 | # Ephemeral port range and network options 113 | net.ipv4.ip_local_port_range = 15000 65535 # Expand ephemeral port range for outgoing connections 114 | net.core.optmem_max = 65536 # Increase memory buffer for networking options 115 | 116 | 117 | ############################################################################## 118 | ## Custom Additions and Routing Flush 119 | ############################################################################## 120 | 121 | # Increase the maximum number of open file descriptors 122 | fs.nr_open = 1000000 123 | 124 | # Rate limit ICMP (e.g., ping) responses to mitigate potential flood attacks 125 | net.ipv4.icmp_ratelimit = 100 126 | net.ipv4.icmp_ratemask = 88089 127 | 128 | # Flush routing cache when settings are changed (may not be executed automatically on all systems) 129 | net.ipv4.route.flush = 1 130 | net.ipv6.route.flush = 1 131 | 132 | # --- BEGIN MEM_1GB 133 | ############################################################################## 134 | ## Section for 1 GB RAM or less. Optimized for low-memory environments 135 | ############################################################################## 136 | 137 | # Reduce minimum memory reserve 138 | vm.min_free_kbytes = 16384 # ~16 MB 139 | 140 | # Minimize swap usage to prefer RAM 141 | vm.swappiness = 1 142 | 143 | # Reduce TCP buffer sizes for lower memory usage 144 | net.ipv4.tcp_rmem = 4096 65536 4194304 145 | net.ipv4.tcp_wmem = 4096 65536 4194304 146 | net.core.rmem_max = 4194304 147 | net.core.wmem_max = 4194304 148 | 149 | # Lower file descriptor limits (still higher than default) 150 | fs.file-max = 100000 151 | fs.nr_open = 500000 152 | net.core.somaxconn = 512 153 | 154 | # --- END MEM_1GB 155 | # --- BEGIN MEM_2GB 156 | ############################################################################## 157 | ## Section for 2 GB RAM. Balanced for small VPS and low-end servers 158 | ############################################################################## 159 | 160 | # Optimal memory reserve for 2 GB systems 161 | vm.min_free_kbytes = 24576 # ~24 MB 162 | 163 | # Low swappiness value to prefer RAM over swap 164 | vm.swappiness = 5 165 | 166 | # Optimized TCP buffers for 2 GB systems 167 | net.ipv4.tcp_rmem = 4096 65536 6291456 168 | net.ipv4.tcp_wmem = 4096 65536 6291456 169 | net.core.rmem_max = 6291456 170 | net.core.wmem_max = 6291456 171 | 172 | # Balanced file descriptor limits 173 | fs.file-max = 150000 174 | fs.nr_open = 750000 175 | net.core.somaxconn = 768 176 | 177 | # --- END MEM_2GB 178 | # --- BEGIN MEM_3-4GB 179 | ############################################################################## 180 | ## Section for 3-4 GB RAM. Suitable for medium VPS and standard servers 181 | ############################################################################## 182 | 183 | # Balanced memory reserve 184 | vm.min_free_kbytes = 32768 # ~32 MB 185 | 186 | # Standard swappiness for this memory size 187 | vm.swappiness = 10 188 | 189 | # Moderate TCP buffer sizes 190 | net.ipv4.tcp_rmem = 4096 87380 8388608 191 | net.ipv4.tcp_wmem = 4096 65536 8388608 192 | net.core.rmem_max = 8388608 193 | net.core.wmem_max = 8388608 194 | 195 | # Standard file descriptor limits 196 | fs.file-max = 209708 197 | net.core.somaxconn = 1024 198 | 199 | # --- END MEM_3-4GB 200 | # --- BEGIN MEM_5-8GB 201 | ############################################################################## 202 | ## Section for 5-8 GB RAM. Good for standard production servers 203 | ############################################################################## 204 | 205 | # Standard memory reserve 206 | vm.min_free_kbytes = 65536 # ~64 MB 207 | 208 | # Default swappiness setting 209 | vm.swappiness = 10 210 | 211 | # Standard TCP buffer settings 212 | net.ipv4.tcp_rmem = 4096 87380 16777216 213 | net.ipv4.tcp_wmem = 4096 65536 16777216 214 | net.core.rmem_max = 16777216 215 | net.core.wmem_max = 16777216 216 | 217 | # Standard connection settings 218 | net.core.somaxconn = 1024 219 | fs.file-max = 209708 220 | 221 | # --- END MEM_5-8GB 222 | # --- BEGIN MEM_16+GB 223 | ############################################################################## 224 | ## Section for 16+ GB RAM. Optimized for high-performance servers 225 | ############################################################################## 226 | 227 | # Increased memory reserve for larger systems 228 | vm.min_free_kbytes = 131072 # ~128 MB 229 | 230 | # Standard swappiness for high-memory systems 231 | vm.swappiness = 10 232 | 233 | # Larger TCP buffers for high-performance applications 234 | net.ipv4.tcp_rmem = 4096 87380 33554432 235 | net.ipv4.tcp_wmem = 4096 65536 33554432 236 | net.core.rmem_max = 33554432 237 | net.core.wmem_max = 33554432 238 | 239 | # Increased limits for high-connection servers 240 | net.core.somaxconn = 4096 241 | fs.file-max = 800000 242 | # --- END MEM_16+GB -------------------------------------------------------------------------------- /void-infect.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # void-infect: Install Void linux over the existing OS on VPS 3 | # Inspired by nixos-infect (https://github.com/elitak/nixos-infect) 4 | set -e # Exit on any error 5 | 6 | 7 | VOID_LINK="https://repo-default.voidlinux.org/live/current/void-x86_64-ROOTFS-20250202.tar.xz" 8 | VOID_HASH="3f48e6673ac5907a897d913c97eb96edbfb230162731b4016562c51b3b8f1876" 9 | 10 | ADD_LOCALE="ru_RU.UTF-8" # Optional 11 | ADD_PKG="fuzzypkg vsv tmux dte nano gotop fd ncdu git tree neofetch" 12 | SET_HOSTNAME=void-vps 13 | 14 | 15 | # Colors for pretty output 16 | RED='\033[0;31m' 17 | GREEN='\033[0;32m' 18 | BLUE='\033[0;34m' 19 | NC='\033[0m' 20 | 21 | log() { 22 | echo -e "${GREEN}[+]${NC} $1" 23 | } 24 | 25 | error() { 26 | echo -e "${RED}[!]${NC} $1" 27 | handle_error 28 | } 29 | 30 | try() { 31 | local log_file=$(mktemp) 32 | 33 | if ! eval "$@" &> "$log_file"; then 34 | echo -e "${RED}[!]${NC} Failed: $*" 35 | cat "$log_file" 36 | handle_error 37 | fi 38 | rm -f "$log_file" 39 | } 40 | 41 | export POINT_OF_NO_RETURN=false 42 | export SCRIPT_STARTED=false 43 | handle_error() { 44 | [ "$SCRIPT_STARTED" = false ] && exit 1 45 | if [ "$POINT_OF_NO_RETURN" = false ]; then 46 | echo -e " 47 | 48 | ╔════════════════════════════════════════════════════════════════════╗ 49 | ║ INSTALLATION ABORTED ║ 50 | ╠════════════════════════════════════════════════════════════════════╣ 51 | ║ ${GREEN}The system has NOT been broken. ${NC} ║ 52 | ║ You can safely: ║ 53 | ║ 1. Reboot the system ║ 54 | ║ 2. rm -rf /void ║ 55 | ╚════════════════════════════════════════════════════════════════════╝ 56 | " 57 | else 58 | echo -e " 59 | 60 | ╔════════════════════════════════════════════════════════════════════╗ 61 | ║ ${RED}CRITICAL ERROR${NC} ║ 62 | ╠════════════════════════════════════════════════════════════════════╣ 63 | ║ Installation failed during system replacement. ║ 64 | ║ ║ 65 | ║ You can: ║ 66 | ║ 1. Try to complete Void installation manually: ║ 67 | ║ - You are now in chroot environment ║ 68 | ║ - Check error message above ║ 69 | ║ - Continue with remaining installation steps ║ 70 | ║ ║ 71 | ║ 2. If unsure, just reinstall your system using VPS panel ║ 72 | ╚════════════════════════════════════════════════════════════════════╝ 73 | " 74 | bash 75 | fi 76 | exit 1 77 | } 78 | 79 | trap handle_error ERR INT TERM 80 | 81 | ############################################################################### 82 | 83 | # First stage, before chroot 84 | 85 | if [ -z $VOID_INFECT_STAGE_2 ]; then 86 | [[ $(id -u) == 0 ]] || error "This script must be run as root" 87 | [ -s /root/.ssh/authorized_keys ] || error "At least one SSH key required in root's authorized_keys" 88 | [[ -d /void ]] && error "Remove /void before start" 89 | command -v findmnt >/dev/null 2>&1 || error "findmnt not found. Install util-linux" 90 | export SCRIPT_STARTED=true 91 | 92 | echo " 93 | _______ _________ ______ _________ _ _______ _______ _______ _________ 94 | |\ /|( ___ )\__ __/( __ \ \__ __/( ( /|( ____ \( ____ \( ____ \\__ __/ 95 | | ) ( || ( ) | ) ( | ( \ ) ) ( | \ ( || ( \/| ( \/| ( \/ ) ( 96 | | | | || | | | | | | | ) | | | | \ | || (__ | (__ | | | | 97 | ( ( ) )| | | | | | | | | | | | | (\ \) || __) | __) | | | | 98 | \ \_/ / | | | | | | | | ) | | | | | \ || ( | ( | | | | 99 | \ / | (___) |___) (___| (__/ ) ___) (___| ) \ || ) | (____/\| (____/\ | | 100 | \_/ (_______)\_______/(______/ \_______/|/ )_)|/ (_______/(_______/ )_( 101 | " 102 | 103 | log "Creating /void directory..." 104 | SCRIPT_PATH=$(readlink -f "$0") 105 | try mkdir -p /void 106 | try mkdir -p /void/{proc,sys,dev,run,oldroot} 107 | 108 | log "Downloading $(basename "$VOID_LINK" .tar.xz)..." 109 | if command -v curl >/dev/null 2>&1; then 110 | try curl -fL "$VOID_LINK" -o "/void/rootfs.tar.xz" 111 | elif command -v wget >/dev/null 2>&1; then 112 | try wget -O "/void/rootfs.tar.xz" "$VOID_LINK" 113 | else 114 | echo "Error: Neither curl nor wget is available" 115 | exit 1 116 | fi 117 | 118 | log "Verifying SHA256 checksum..." 119 | CALCULATED_HASH=$(sha256sum "/void/rootfs.tar.xz" | cut -d' ' -f1) 120 | if [ "$CALCULATED_HASH" != "$VOID_HASH" ]; then 121 | error "SHA256 checksum verification failed!" 122 | fi 123 | 124 | log "Extracting rootfs..." 125 | try tar xf "/void/rootfs.tar.xz" -C "/void" 126 | try rm "/void/rootfs.tar.xz" 127 | 128 | log "Configuring fstab..." 129 | ROOT_DEV=$(findmnt -n -o SOURCE /) 130 | ROOT_FS_TYPE=$(findmnt -n -o FSTYPE /) 131 | export ROOT_DISK=$(echo "$ROOT_DEV" | sed 's/[0-9]*$//') 132 | [[ -e "$ROOT_DISK" ]] || error "Could not determine root disk device" 133 | [[ -b "$ROOT_DISK" ]] || error "Invalid root disk device: $ROOT_DISK" 134 | # TODO Is it reely need? 135 | echo "$ROOT_DEV / $ROOT_FS_TYPE defaults 0 1" >> /void/etc/fstab 136 | 137 | log "Copying essential files..." 138 | echo "$SET_HOSTNAME" > /void/etc/hostname 139 | # self 140 | cp "$SCRIPT_PATH" /void/void-infect.sh 141 | # ssh 142 | mkdir -p /void/root/.ssh 143 | try cp -r /root/.ssh/authorized_keys /void/root/.ssh/ 144 | chmod 700 /void/root/.ssh 145 | chmod 600 /void/root/.ssh/authorized_keys 146 | # Extract DNS servers, replace localhost with 1.1.1.1 147 | grep ^nameserver /etc/resolv.conf | sed -r \ 148 | -e 's/127[0-9.]+/1.1.1.1/' \ 149 | -e 's/::1/1.1.1.1/' > /void/etc/resolv.conf 150 | 151 | log "Stopping non-essential services..." 152 | systemctl list-units --type=service --state=running | \ 153 | grep '\.service' | \ 154 | cut -d' ' -f1 | \ 155 | grep -vE '(sshd|systemd-journal|systemd-udev)' | \ 156 | xargs -r systemctl stop >> /dev/null 157 | 158 | log "Unmounting all non-essential filesystems..." 159 | swapoff -a || true 160 | awk '$2!="/" && $2!="" && $2!="/void" && $2!="/sys" && $2!="/proc" && $2!="/dev" {print $2}' /proc/mounts | sort -r | \ 161 | while read -r mount_point; do 162 | umount -f -l "$mount_point" 2>/dev/null || true 163 | done 164 | 165 | log "Mounting necessary filesystems..." 166 | try mount --bind / /void/oldroot 167 | try mount --bind /dev /void/dev 168 | try mount --bind /proc /void/proc 169 | try mount --bind /sys /void/sys 170 | 171 | log "Entering chroot..." 172 | env VOID_INFECT_STAGE_2=y chroot /void /void-infect.sh 173 | 174 | exit 0 175 | fi 176 | 177 | ############################################################################### 178 | 179 | # Second stage, inside chroot 180 | 181 | log "Updating xbps..." 182 | try xbps-install -Syu xbps 183 | 184 | log "Updating packages..." 185 | try xbps-install -Syu 186 | 187 | log "Configuring xbps..." 188 | echo 'ignorepkg=linux-firmware-amd 189 | ignorepkg=linux-firmware-intel 190 | ignorepkg=linux-firmware-nvidia 191 | ignorepkg=linux-firmware-network' >> /etc/xbps.d/ignore.conf 192 | 193 | log "Installing base system..." 194 | # Don't use `base-system` because it contains heavy and useless WiFi drivers 195 | try xbps-install -y base-minimal linux 196 | # Useful packages from base-system 197 | try xbps-install -y man-pages mdocml ncurses iproute2 iputils traceroute ethtool file kmod 198 | 199 | log "Installing necessary packages..." 200 | # Utils used by scripts 201 | try xbps-install -y bind-utils inotify-tools psmisc parallel less jq unzip bc git 202 | # We need it 203 | try xbps-install -y grub wget curl openssh bash-completion 204 | 205 | log "Installing useful packages..." 206 | try xbps-install -y $ADD_PKG 207 | 208 | log "Installing simple cron..." 209 | try xbps-install -y scron 210 | ln -sf /etc/sv/crond /etc/runit/runsvdir/default/ 211 | echo "# * (wildcard), 30 (number), */N (repeat), 1-5 (range), or 1,3,6 (list) 212 | # 213 | # .---------------- minute (0 - 59) 214 | # | .------------- hour (0 - 23) 215 | # | | .---------- day of month (1 - 31) 216 | # | | | .------- month (1 - 12) 217 | # | | | | .-- day of week (0 - 6) 218 | # | | | | | 219 | # m h dom mon dow command 220 | 221 | 0 4 * * * run-parts /etc/cron.daily &>> /var/log/cron.daily.log 222 | " > /etc/crontab 223 | 224 | log "Installing ufw..." 225 | try xbps-install -y ufw 226 | ln -sf /etc/sv/ufw /etc/runit/runsvdir/default/ 227 | sed -i 's/ENABLED=no/ENABLED=yes/' /etc/ufw/ufw.conf 228 | echo "ufw allow ssh #VOID-INFECT-STAGE-3" >> /etc/rc.local 229 | 230 | log "Disabling unused services (agetty, udev)..." 231 | xbps-remove -Oo 232 | rm /etc/runit/runsvdir/default/agetty* 233 | rm /etc/runit/runsvdir/default/udevd 234 | 235 | log "Setting up bash configuration..." 236 | try wget https://raw.githubusercontent.com/Jipok/Cute-bash/master/.bashrc -O "/etc/bash/bashrc.d/cute-bash.sh" 237 | try wget "https://raw.githubusercontent.com/trapd00r/LS_COLORS/master/LS_COLORS" -O "/etc/bash/ls_colors" 238 | try wget "https://raw.githubusercontent.com/cykerway/complete-alias/master/complete_alias" -O "/etc/bash/complete_alias" 239 | rm "/etc/skel/.bashrc" 2>/dev/null || true 240 | usermod -s /bin/bash root || error "Failed to set bash as default shell" 241 | 242 | if [[ ! -z "$ADD_LOCALE" ]]; then 243 | log "Setting locales..." 244 | sed -i "s/^# *$ADD_LOCALE/$ADD_LOCALE/" /etc/default/libc-locales 245 | try xbps-reconfigure -f glibc-locales 246 | fi 247 | 248 | log "Configuring network in /etc/rc.local..." 249 | interface=$(ip route show default | head -n1 | awk '{print $5}') 250 | [[ -z "$interface" ]] && interface=$(ip -6 route show default 2>/dev/null | head -n1 | awk '{print $5}') 251 | # 4 252 | ipv4_addr=$(ip addr show dev "$interface" | grep 'inet ' | awk '{print $2}') 253 | ipv4_gateway=$(ip route show default | head -n1 | awk '{print $3}') 254 | # 6 255 | ipv6_addr=$(ip -6 addr show dev "$interface" | grep 'inet6' | grep -v 'fe80' | awk '{print $2}') 256 | ipv6_gateway=$(ip -6 route show default | head -n1 | awk '{print $3}') 257 | # 258 | echo "" >> /etc/rc.local 259 | echo "# From void-infect.sh" >> /etc/rc.local 260 | echo "ip link set dev eth0 up" >> /etc/rc.local 261 | [ -n "$ipv4_addr" ] && echo "ip addr add $ipv4_addr dev eth0" >> /etc/rc.local 262 | [ -n "$ipv4_gateway" ] && echo "ip route add default via $ipv4_gateway" >> /etc/rc.local 263 | [ -n "$ipv6_addr" ] && echo "ip -6 addr add $ipv6_addr dev eth0" >> /etc/rc.local && \ 264 | [ -z "$ipv6_gateway" ] && echo "echo 1 > /proc/sys/net/ipv6/conf/eth0/accept_ra" >> /etc/rc.local 265 | [ -n "$ipv6_gateway" ] && echo "ip -6 route add default via $ipv6_gateway" >> /etc/rc.local 266 | echo "" >> /etc/rc.local 267 | echo "rm -rf /void #VOID-INFECT-STAGE-3" >> /etc/rc.local 268 | echo "sed -i '/#VOID-INFECT-STAGE-3/d' /etc/rc.local " >> /etc/rc.local 269 | 270 | log "Configuring SSH..." 271 | # Secure SSH configuration 272 | sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config 273 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config 274 | sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config 275 | # Generate only modern Ed25519 key (faster and more secure than RSA) 276 | try 'ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""' 277 | SSH_FP=$(ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub | awk '{print $2}') 278 | # Prevent generation of legacy keys during service start 279 | cp -r /etc/sv/sshd /etc/runit/runsvdir/default/ 280 | sed -i '/ssh-keygen -A/d' /etc/runit/runsvdir/default//sshd/run 281 | 282 | log "Disabling root password login..." 283 | try passwd -l root 284 | 285 | log "Downloading sysctl configuration..." 286 | try mkdir /etc/sysctl.d 287 | try wget "https://raw.githubusercontent.com/Jipok/void-infect/refs/heads/master/sysctl.conf" -O /etc/sysctl.d/99-default.conf 288 | 289 | # Calculate total memory (in MB) 290 | mem_total_kb=$(grep '^MemTotal:' /proc/meminfo | awk '{print $2}') 291 | TOTAL_MEM=$((mem_total_kb / 1024)) 292 | # Determine selected memory section based on total memory 293 | if [ "$TOTAL_MEM" -le 1500 ]; then 294 | SELECTED="MEM_1GB" 295 | elif [ "$TOTAL_MEM" -le 2500 ]; then 296 | SELECTED="MEM_2GB" 297 | elif [ "$TOTAL_MEM" -le 4500 ]; then 298 | SELECTED="MEM_3-4GB" 299 | elif [ "$TOTAL_MEM" -le 11000 ]; then 300 | SELECTED="MEM_5-8GB" 301 | else 302 | SELECTED="MEM_16+GB" 303 | fi 304 | 305 | # Remove the 'MEM_' prefix for pretty logging 306 | SELECTED_PRETTY=${SELECTED#MEM_} 307 | log "Applying sysctl configuration for $SELECTED_PRETTY RAM" 308 | 309 | # Remove unselected memory markers from the sysctl configuration 310 | for marker in MEM_1GB MEM_2GB MEM_3-4GB MEM_5-8GB MEM_16+GB; do 311 | if [ "$marker" != "$SELECTED" ]; then 312 | sed -i "/# --- BEGIN $marker/,/# --- END $marker/d" /etc/sysctl.d/99-default.conf 313 | else 314 | sed -i "/# --- BEGIN $marker/d" /etc/sysctl.d/99-default.conf 315 | sed -i "/# --- END $marker/d" /etc/sysctl.d/99-default.conf 316 | fi 317 | done 318 | 319 | ############################################################################### 320 | 321 | export POINT_OF_NO_RETURN=true 322 | 323 | log "Installing bootloader..." 324 | if [ -d "/sys/firmware/efi" ]; then 325 | try xbps-install -y grub-x86_64-efi efibootmgr 326 | try grub-install --target=x86_64-efi --efi-directory=/boot --removable 327 | else 328 | try grub-install "$ROOT_DISK" 329 | fi 330 | # Use traditional Linux naming scheme for interfaces 331 | sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="net.ifnames=0 /' /etc/default/grub 332 | # IPv6 support 333 | [ -n "$ipv6_addr" ] && sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=0 /' /etc/default/grub 334 | try update-grub 335 | 336 | log "Removing old system..." 337 | cd /oldroot 338 | ls -A | grep -vE '^(dev|proc|sys|mnt|void)$' | xargs rm -rf 339 | 340 | log "Copying new system..." 341 | cd / 342 | tar -cf - \ 343 | --exclude='./dev/*' \ 344 | --exclude='./proc/*' \ 345 | --exclude='./sys/*' \ 346 | --exclude='./tmp/*' \ 347 | --exclude='./run/*' \ 348 | --exclude='./media/*' \ 349 | --exclude='./lost+found' \ 350 | --exclude='./oldroot*' \ 351 | --exclude='./void-infect.sh' \ 352 | . | (cd /oldroot && tar xf -) 353 | sync 354 | 355 | log "System replacement complete. Rebooting..." 356 | 357 | IP_ADDRESS=$(ip route get 1 2>/dev/null | awk '{print $7}' | head -1) 358 | FORMATTED_IP=$(printf "%-15s" "${IP_ADDRESS}") 359 | echo -e " 360 | ╔════════════════════════════════════════════════════════════════════╗ 361 | ║ IMPORTANT INFORMATION ║ 362 | ╠════════════════════════════════════════════════════════════════════╣ 363 | ║ You will receive a warning about changed host key ║ 364 | ║ on your next SSH connection. ║ 365 | ║ ║ 366 | ║ To avoid connection errors, run this command ║ 367 | ║ on your local machine: ║ 368 | ║ ${GREEN}ssh-keygen -R ${FORMATTED_IP}${NC} ║ 369 | ║ ║ 370 | ║ New SSH host key fingerprint: ║ 371 | ║ ${BLUE}${SSH_FP}${NC} ║ 372 | ║ ║ 373 | ║ Verify the fingerprint when connecting! ║ 374 | ╚════════════════════════════════════════════════════════════════════╝ 375 | " 376 | 377 | /sbin/reboot -f -------------------------------------------------------------------------------- /void-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This is a script for installing Void on a home server 3 | set -e # Exit on any error 4 | 5 | #========================================================================= 6 | # CONFIGURATION 7 | #========================================================================= 8 | 9 | SET_HOSTNAME="void-server" 10 | ADD_LOCALE="ru_RU.UTF-8" # Optional locale 11 | 12 | WIFI=true # If true, install NetworkManager (for WiFi); if false, install dhcpcd (for wired) 13 | SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKpjScT3SXKVi36st5dpCTqacF00LJ1lKo4SXaFswC3Y Jipok" 14 | 15 | SWAPFILE_GB=AUTO # Swapfile size in GB or AUTO (based on RAM); 0 to disable 16 | # NOTE: Using swapfile is preferred over swap partition (more flexible) 17 | SWAP_GB=0 # Swap partition size in gigabytes; 0 for not creating partition 18 | 19 | ADD_PKG="fuzzypkg vsv tmux dte nano gotop fd ncdu git tree neofetch" 20 | VOID_LINK="https://repo-default.voidlinux.org/live/current/void-x86_64-ROOTFS-20250202.tar.xz" 21 | VOID_HASH="3f48e6673ac5907a897d913c97eb96edbfb230162731b4016562c51b3b8f1876" 22 | 23 | #========================================================================= 24 | # HELPER FUNCTIONS 25 | #========================================================================= 26 | 27 | # Colors for pretty output 28 | RED='\033[0;31m' 29 | GREEN='\033[0;32m' 30 | BLUE='\033[0;34m' 31 | NC='\033[0m' 32 | 33 | # Logging functions 34 | log() { 35 | echo -e "${GREEN}[+]${NC} $1" 36 | } 37 | 38 | error() { 39 | echo -e "${RED}[!]${NC} $1" 40 | handle_error 41 | } 42 | 43 | try() { 44 | local log_file 45 | log_file=$(mktemp) 46 | 47 | if ! eval "$@" &> "$log_file"; then 48 | echo -e "${RED}[!]${NC} Failed: $*" 49 | cat "$log_file" 50 | handle_error 51 | fi 52 | rm -f "$log_file" 53 | } 54 | 55 | export SCRIPT_STARTED=false 56 | handle_error() { 57 | [ "$SCRIPT_STARTED" = false ] && exit 1 58 | if [ -z "$VOID_INSTALL_STAGE_2" ]; then 59 | echo -e " 60 | 61 | ╔════════════════════════════════════════════════════════════════════╗ 62 | ║ INSTALLATION ABORTED ║ 63 | ╠════════════════════════════════════════════════════════════════════╣ 64 | ║ ${GREEN}Target disk operations failed but your LiveUSB is unaffected.${NC} ║ 65 | ║ You can safely: ║ 66 | ║ 1. Fix the reported issue ║ 67 | ║ 2. Retry the installation script ║ 68 | ║ 3. Unmount any mounted partitions if needed ║ 69 | ╚════════════════════════════════════════════════════════════════════╝ 70 | " 71 | else 72 | echo -e " 73 | 74 | ╔════════════════════════════════════════════════════════════════════╗ 75 | ║ ${RED}CRITICAL ERROR${NC} ║ 76 | ╠════════════════════════════════════════════════════════════════════╣ 77 | ║ Installation failed inside chroot environment. ║ 78 | ║ ║ 79 | ║ You can: ║ 80 | ║ 1. Try to complete Void installation manually: ║ 81 | ║ - Check error message above ║ 82 | ║ - Continue with remaining installation steps ║ 83 | ║ ║ 84 | ║ 2. Type 'exit' to leave chroot and return to LiveUSB ║ 85 | ║ Then unmount partitions and restart installation ║ 86 | ╚════════════════════════════════════════════════════════════════════╝ 87 | " 88 | bash 89 | fi 90 | exit 1 91 | } 92 | 93 | trap handle_error ERR INT TERM 94 | 95 | ############################################################################### 96 | # First Stage: Outside chroot – Partitioning disk and extracting Void rootfs 97 | ############################################################################### 98 | 99 | if [ -z "$VOID_INSTALL_STAGE_2" ]; then 100 | [[ $(id -u) == 0 ]] || error "This script must be run as root" 101 | command -v parted >/dev/null 2>&1 || error "parted not found. Install it" 102 | command -v xz >/dev/null 2>&1 || error "xz not found. Install it" 103 | command -v wget >/dev/null 2>&1 || command -v curl >/dev/null 2>&1 || error "Neither curl nor wget is available. Install something" 104 | [ -n "$1" ] || error "Usage: $0 /dev/sdX (or /dev/nvme0n1, etc)" 105 | TARGET_DISK="$1" 106 | [ -b "$TARGET_DISK" ] || error "Target disk $TARGET_DISK does not exist or is not a block device." 107 | 108 | # Check if the target disk has any existing partitions. 109 | existing_partitions=$(lsblk -n -o NAME "$TARGET_DISK" | tail -n +2) 110 | if [ -n "$existing_partitions" ]; then 111 | error "Existing partitions detected on $TARGET_DISK. Remove all partitions before proceeding: 112 | ${BLUE}parted $TARGET_DISK mklabel gpt${NC}" 113 | fi 114 | 115 | export SCRIPT_STARTED=true 116 | echo " 117 | _______ _________ ______ 118 | |\ /|( ___ )\__ __/( __ \ 119 | | ) ( || ( ) | ) ( | ( \ ) 120 | | | | || | | | | | | | ) | 121 | ( ( ) )| | | | | | | | | | 122 | \ \_/ / | | | | | | | | ) | 123 | \ / | (___) |___) (___| (__/ ) 124 | \_/ (_______)\_______/(______/ 125 | " 126 | 127 | # Determine partition naming scheme. 128 | # If disk name contains "nvme", partitions use 'p' separator (e.g. /dev/nvme0n1p1) 129 | if [[ "$TARGET_DISK" =~ nvme ]]; then 130 | PART_PREFIX="${TARGET_DISK}p" 131 | else 132 | PART_PREFIX="$TARGET_DISK" 133 | fi 134 | 135 | #------------------------------------------------------------------------- 136 | # Disk partitioning 137 | #------------------------------------------------------------------------- 138 | log "Partitioning disk $TARGET_DISK..." 139 | try parted -s "$TARGET_DISK" mklabel gpt 140 | try parted -s "$TARGET_DISK" mkpart ESP fat32 1MiB 513MiB 141 | try parted -s "$TARGET_DISK" set 1 esp on 142 | 143 | if [ "$SWAP_GB" -gt 0 ]; then 144 | SWAP_SIZE_MB=$(( SWAP_GB * 1024 )) 145 | SWAP_END=$(( 513 + SWAP_SIZE_MB )) 146 | try parted -s "$TARGET_DISK" mkpart primary linux-swap 513MiB "${SWAP_END}MiB" 147 | try parted -s "$TARGET_DISK" mkpart primary ext4 "${SWAP_END}MiB" 100% 148 | else 149 | try parted -s "$TARGET_DISK" mkpart primary ext4 513MiB 100% 150 | fi 151 | 152 | #------------------------------------------------------------------------- 153 | # Formatting partitions 154 | #------------------------------------------------------------------------- 155 | log "Formatting EFI partition (${PART_PREFIX}1)..." 156 | try mkfs.fat -F32 "${PART_PREFIX}1" 157 | 158 | if [ "$SWAP_GB" -gt 0 ]; then 159 | log "Formatting swap partition (${PART_PREFIX}2)..." 160 | try mkswap "${PART_PREFIX}2" 161 | try swapon "${PART_PREFIX}2" 162 | ROOT_PARTITION="${PART_PREFIX}3" 163 | else 164 | ROOT_PARTITION="${PART_PREFIX}2" 165 | fi 166 | 167 | log "Formatting root partition (${ROOT_PARTITION})..." 168 | try mkfs.ext4 "${ROOT_PARTITION}" 169 | 170 | #------------------------------------------------------------------------- 171 | # Mounting and setup 172 | #------------------------------------------------------------------------- 173 | log "Mounting partitions..." 174 | try mount "${ROOT_PARTITION}" /mnt 175 | try mkdir -p /mnt/boot/efi 176 | try mount "${PART_PREFIX}1" /mnt/boot/efi 177 | 178 | log "Downloading Void Linux rootfs..." 179 | if command -v curl >/dev/null 2>&1; then 180 | try curl -fL "$VOID_LINK" -o "/mnt/rootfs.tar.xz" 181 | elif command -v wget >/dev/null 2>&1; then 182 | try wget -O "/mnt/rootfs.tar.xz" "$VOID_LINK" 183 | else 184 | error "Neither curl nor wget is available." 185 | fi 186 | 187 | log "Verifying SHA256 checksum of rootfs..." 188 | CALCULATED_HASH=$(sha256sum "/mnt/rootfs.tar.xz" | awk '{print $1}') 189 | if [ "$CALCULATED_HASH" != "$VOID_HASH" ]; then 190 | error "SHA256 checksum verification failed!" 191 | fi 192 | 193 | log "Extracting rootfs to /mnt..." 194 | try tar xf "/mnt/rootfs.tar.xz" -C /mnt 195 | try rm "/mnt/rootfs.tar.xz" 196 | 197 | log "Configuring fstab..." 198 | { 199 | echo "${ROOT_PARTITION} / ext4 defaults,noatime,discard 0 1" 200 | echo "${PART_PREFIX}1 /boot/efi vfat defaults,umask=0077 0 1" 201 | if [ "$SWAP_GB" -gt 0 ]; then 202 | SWAP_UUID=$(blkid -s UUID -o value "${PART_PREFIX}2" 2>/dev/null || true) 203 | if [ -n "$SWAP_UUID" ]; then 204 | echo "UUID=${SWAP_UUID} none swap sw 0 0" 205 | else 206 | echo "${PART_PREFIX}2 none swap sw 0 0" 207 | fi 208 | fi 209 | } >> /mnt/etc/fstab 210 | 211 | log "Setting hostname..." 212 | echo "$SET_HOSTNAME" > /mnt/etc/hostname 213 | try cp /etc/resolv.conf /mnt/etc/resolv.conf # For working dns in stage 2 214 | 215 | # Copy this installer script into new system for second stage 216 | SCRIPT_PATH=$(readlink -f "$0") 217 | try cp "$SCRIPT_PATH" /mnt/void-install.sh 218 | 219 | log "Mounting necessary filesystems for chroot..." 220 | try mount --bind /dev /mnt/dev 221 | try mount --bind /proc /mnt/proc 222 | try mount --bind /sys /mnt/sys 223 | try mount --bind /run /mnt/run 224 | 225 | log "Entering chroot for second stage installation..." 226 | env VOID_INSTALL_STAGE_2=y chroot /mnt /void-install.sh 227 | 228 | exit 0 229 | fi 230 | 231 | ################################################################################## 232 | # Second Stage: Inside chroot – System configuration, package installation, GRUB 233 | ################################################################################## 234 | 235 | log "Updating xbps..." 236 | try xbps-install -Syu xbps 237 | 238 | log "Updating packages..." 239 | try xbps-install -Syu 240 | 241 | log "Installing base system..." 242 | try xbps-install -y base-system 243 | 244 | #------------------------------------------------------------------------- 245 | # Package Installation 246 | #------------------------------------------------------------------------- 247 | log "Installing necessary packages..." 248 | try xbps-install -y bind-utils inotify-tools psmisc parallel less jq unzip bc git 249 | try xbps-install -y grub wget curl openssh bash-completion 250 | 251 | log "Installing additional useful packages..." 252 | try xbps-install -y $ADD_PKG 253 | 254 | #------------------------------------------------------------------------- 255 | # Network Configuration 256 | #------------------------------------------------------------------------- 257 | if [ "$WIFI" = true ]; then 258 | log "Installing WiFi network manager (NetworkManager)..." 259 | try xbps-install -y NetworkManager 260 | ln -sf /etc/sv/dbus /etc/runit/runsvdir/default/ 261 | ln -sf /etc/sv/NetworkManager /etc/runit/runsvdir/default/ 262 | else 263 | log "Installing DHCP client (dhcpcd)..." 264 | try xbps-install -y dhcpcd 265 | ln -sf /etc/sv/dhcpcd /etc/runit/runsvdir/default/ 266 | fi 267 | 268 | #------------------------------------------------------------------------- 269 | # Cron Setup 270 | #------------------------------------------------------------------------- 271 | log "Installing simple cron (scron)..." 272 | try xbps-install -y scron 273 | ln -sf /etc/sv/crond /etc/runit/runsvdir/default/ 274 | cat > /etc/crontab <> /var/log/cron.daily.log 282 | EOF 283 | 284 | #------------------------------------------------------------------------- 285 | # Firewall Setup 286 | #------------------------------------------------------------------------- 287 | log "Installing ufw (firewall)..." 288 | try xbps-install -y ufw 289 | ln -sf /etc/sv/ufw /etc/runit/runsvdir/default/ 290 | sed -i 's/ENABLED=no/ENABLED=yes/' /etc/ufw/ufw.conf 291 | # 292 | echo "ufw allow ssh #VOID-INFECT-STAGE-3" >> /etc/rc.local 293 | echo "sed -i '/#VOID-INFECT-STAGE-3/d' /etc/rc.local " >> /etc/rc.local 294 | 295 | #------------------------------------------------------------------------- 296 | # Shell Configuration 297 | #------------------------------------------------------------------------- 298 | log "Setting up bash configuration..." 299 | try wget https://raw.githubusercontent.com/Jipok/Cute-bash/master/.bashrc -O "/etc/bash/bashrc.d/cute-bash.sh" 300 | try wget "https://raw.githubusercontent.com/trapd00r/LS_COLORS/master/LS_COLORS" -O "/etc/bash/ls_colors" 301 | try wget "https://raw.githubusercontent.com/cykerway/complete-alias/master/complete_alias" -O "/etc/bash/complete_alias" 302 | rm -f "/etc/skel/.bashrc" 2>/dev/null || true 303 | usermod -s /bin/bash root || error "Failed to set bash as default shell" 304 | 305 | #------------------------------------------------------------------------- 306 | # Locale Configuration 307 | #------------------------------------------------------------------------- 308 | if [[ -n "$ADD_LOCALE" ]]; then 309 | log "Setting locales..." 310 | sed -i "s/^# *$ADD_LOCALE/$ADD_LOCALE/" /etc/default/libc-locales 311 | try xbps-reconfigure -f glibc-locales 312 | fi 313 | 314 | #------------------------------------------------------------------------- 315 | # SSH Configuration 316 | #------------------------------------------------------------------------- 317 | log "Configuring SSH..." 318 | # Secure SSH configuration 319 | sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config 320 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config 321 | sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config 322 | # Generate only modern Ed25519 key (faster and more secure than RSA) 323 | try 'ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""' 324 | SSH_FP=$(ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub | awk '{print $2}') 325 | # Prevent generation of legacy keys during service start 326 | cp -r /etc/sv/sshd /etc/runit/runsvdir/default/ 327 | sed -i '/ssh-keygen -A/d' /etc/runit/runsvdir/default//sshd/run 328 | # Set key 329 | try mkdir -p /root/.ssh 330 | echo "${SSH_KEY:-}" > /root/.ssh/authorized_keys 331 | 332 | #------------------------------------------------------------------------- 333 | # System Tuning - RAM based sysctl 334 | #------------------------------------------------------------------------- 335 | log "Downloading sysctl configuration..." 336 | try mkdir /etc/sysctl.d 337 | try wget "https://raw.githubusercontent.com/Jipok/void-infect/refs/heads/master/sysctl.conf" -O /etc/sysctl.d/99-default.conf 338 | 339 | # Calculate total memory (in MB) 340 | mem_total_kb=$(grep '^MemTotal:' /proc/meminfo | awk '{print $2}') 341 | TOTAL_MEM=$((mem_total_kb / 1024)) 342 | 343 | # Determine selected memory section based on total memory 344 | if [ "$TOTAL_MEM" -le 1500 ]; then 345 | SELECTED="MEM_1GB" 346 | elif [ "$TOTAL_MEM" -le 2500 ]; then 347 | SELECTED="MEM_2GB" 348 | elif [ "$TOTAL_MEM" -le 4500 ]; then 349 | SELECTED="MEM_3-4GB" 350 | elif [ "$TOTAL_MEM" -le 11000 ]; then 351 | SELECTED="MEM_5-8GB" 352 | else 353 | SELECTED="MEM_16+GB" 354 | fi 355 | 356 | # Remove the 'MEM_' prefix for pretty logging 357 | SELECTED_PRETTY=${SELECTED#MEM_} 358 | log "Applying sysctl configuration for $SELECTED_PRETTY RAM" 359 | 360 | # Remove unselected memory markers from the sysctl configuration 361 | for marker in MEM_1GB MEM_2GB MEM_3-4GB MEM_5-8GB MEM_16+GB; do 362 | if [ "$marker" != "$SELECTED" ]; then 363 | sed -i "/# --- BEGIN $marker/,/# --- END $marker/d" /etc/sysctl.d/99-default.conf 364 | else 365 | sed -i "/# --- BEGIN $marker/d" /etc/sysctl.d/99-default.conf 366 | sed -i "/# --- END $marker/d" /etc/sysctl.d/99-default.conf 367 | fi 368 | done 369 | 370 | #------------------------------------------------------------------------- 371 | # SWAP Configuration 372 | #------------------------------------------------------------------------- 373 | # Auto-select swap size based on available RAM 374 | if [ "$SWAPFILE_GB" = "AUTO" ]; then 375 | if [ "$TOTAL_MEM" -le 1500 ]; then # ~ 1 GB 376 | SWAPFILE_GB=2 # 2x RAM 377 | elif [ "$TOTAL_MEM" -le 2500 ]; then # ~ 2 GB 378 | SWAPFILE_GB=2 # 1x RAM 379 | elif [ "$TOTAL_MEM" -le 4500 ]; then # 3-4 GB 380 | SWAPFILE_GB=4 # ~1x RAM 381 | elif [ "$TOTAL_MEM" -le 11000 ]; then # 5-8 GB 382 | SWAPFILE_GB=4 # ~0.5-0.8x RAM 383 | else # 16+ GB 384 | SWAPFILE_GB=8 # ~0.5x RAM 385 | fi 386 | fi 387 | 388 | # Create swapfile if needed 389 | if [ "$SWAPFILE_GB" -gt 0 ]; then 390 | log "Creating ${SWAPFILE_GB}GB swapfile..." 391 | try fallocate -l ${SWAPFILE_GB}G /swapfile 392 | try chmod 600 /swapfile 393 | try mkswap /swapfile 394 | try swapon /swapfile 395 | echo "/swapfile none swap sw 0 0" >> /etc/fstab 396 | fi 397 | 398 | #------------------------------------------------------------------------- 399 | # Bootloader Installation 400 | #------------------------------------------------------------------------- 401 | log "Installing bootloader..." 402 | if [ -d "/sys/firmware/efi" ]; then 403 | try xbps-install -y grub-x86_64-efi efibootmgr 404 | try grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable 405 | else 406 | error "No EFI support detected. BIOS installation not implemented in this script." 407 | fi 408 | 409 | # Use traditional Linux naming scheme for interfaces and enable IPv6 support if needed 410 | sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="net.ifnames=0 /' /etc/default/grub 411 | try update-grub 412 | 413 | #------------------------------------------------------------------------- 414 | # Installation Complete 415 | #------------------------------------------------------------------------- 416 | log "Installation complete" 417 | log "Change root password:" 418 | passwd 419 | read -p "Press enter to reboot..." 420 | /sbin/reboot -f 421 | --------------------------------------------------------------------------------