Skip to content

Instantly share code, notes, and snippets.

@pbrilius
Last active March 14, 2026 12:38
Show Gist options
  • Select an option

  • Save pbrilius/c522110b588927071a166dc255aa3d5e to your computer and use it in GitHub Desktop.

Select an option

Save pbrilius/c522110b588927071a166dc255aa3d5e to your computer and use it in GitHub Desktop.
Kubuntu!
#!/usr/bin/env bash
# =============================================================================
# Kubuntu 24.04 LTS — Post-Install Script
# Target: CHUWI GemiBook Plus / Intel N150 (Twin Lake) / 16GB LPDDR5
# Author: prototype.in
# =============================================================================
set -euo pipefail
LOGFILE="$HOME/postinstall.log"
exec > >(tee -a "$LOGFILE") 2>&1
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
section() { echo -e "\n${GREEN}═══ $* ═══${NC}\n"; }
[[ $EUID -eq 0 ]] && { warn "Run as regular user (not root). Script uses sudo internally."; exit 1; }
# =============================================================================
# 1. BASE SYSTEM UPDATE
# =============================================================================
section "1. System update"
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y \
curl wget git unzip zip build-essential software-properties-common \
apt-transport-https ca-certificates gnupg lsb-release \
htop btop nvtop powertop neofetch inxi \
xclip xdotool \
zsh zsh-autosuggestions zsh-syntax-highlighting
# =============================================================================
# 2. INTEL N150 — CPU MICROCODE + THERMAL THROTTLE GUARD
# =============================================================================
section "2. Intel microcode + thermal"
sudo apt install -y intel-microcode thermald cpufrequtils i7z
# N150 = efficiency-only (no P-cores) — max TDP 6W design
# thermald keeps Tj under control without bios tuning
sudo systemctl enable --now thermald
# powercap: optional hard TDP limit via RAPL (uncomment if overheating)
# sudo apt install -y linux-tools-common linux-tools-generic
# echo 6000000 | sudo tee /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw
# cpufreq: conservative governor for sustained workloads (vs performance spikes)
sudo tee /etc/systemd/system/cpufreq-governor.service > /dev/null <<'EOF'
[Unit]
Description=Set CPU governor to ondemand
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo ondemand > $cpu; done'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable cpufreq-governor.service
# =============================================================================
# 3. INTEL GRAPHICS — N150 UHD (24EU)
# =============================================================================
section "3. Intel UHD drivers + media"
sudo apt install -y \
intel-gpu-tools vainfo \
libva-intel-driver intel-media-va-driver-non-free \
i965-va-driver-shaders \
mesa-vulkan-drivers mesa-utils \
ffmpeg gstreamer1.0-vaapi
# VA-API env (add to ~/.profile)
grep -qxF 'export LIBVA_DRIVER_NAME=iHD' "$HOME/.profile" || \
echo 'export LIBVA_DRIVER_NAME=iHD' >> "$HOME/.profile"
# =============================================================================
# 4. TLP — POWER MANAGEMENT (N150 battery life tuning)
# =============================================================================
section "4. TLP power management"
sudo apt install -y tlp tlp-rdw
sudo systemctl enable tlp
sudo tee /etc/tlp.d/01-n150-gemibook.conf > /dev/null <<'EOF'
# N150 GemiBook Plus TLP profile — prototype.in
CPU_SCALING_GOVERNOR_ON_AC=performance
CPU_SCALING_GOVERNOR_ON_BAT=powersave
CPU_ENERGY_PERF_POLICY_ON_AC=balance_performance
CPU_ENERGY_PERF_POLICY_ON_BAT=power
CPU_BOOST_ON_AC=1
CPU_BOOST_ON_BAT=0
NMI_WATCHDOG=0
WIFI_PWR_ON_BAT=off
RUNTIME_PM_ON_AC=on
RUNTIME_PM_ON_BAT=auto
# GemiBook has 38Wh — protect cells
START_CHARGE_THRESH_BAT0=40
STOP_CHARGE_THRESH_BAT0=80
EOF
sudo tlp start
# =============================================================================
# 5. KDE PLASMA — WAYLAND + X11 TWEAKS
# =============================================================================
section "5. KDE Plasma Wayland optimization"
sudo apt install -y \
plasma-workspace-wayland \
kwin-wayland-backend-drm \
xwayland \
qt6-wayland \
libqt6waylandclient6
# KDE env vars for Wayland
KENV="$HOME/.config/plasma-workspace/env/wayland.sh"
mkdir -p "$(dirname $KENV)"
cat > "$KENV" <<'EOF'
export QT_QPA_PLATFORM=wayland
export GDK_BACKEND=wayland
export CLUTTER_BACKEND=wayland
export SDL_VIDEODRIVER=wayland
export MOZ_ENABLE_WAYLAND=1
export ELECTRON_OZONE_PLATFORM_HINT=auto
EOF
chmod +x "$KENV"
# KDE performance: disable compositing animations on battery
kwriteconfig5 --file kwinrc --group Compositing --key AnimationSpeed 2
kwriteconfig5 --file kwinrc --group Compositing --key Enabled true
# =============================================================================
# 6. LAMP STACK — Apache + MariaDB + PHP 8.3 (native, no Docker)
# =============================================================================
section "6. LAMP stack"
# --- Apache 2.4 ---
sudo apt install -y apache2
sudo systemctl enable apache2
# Enable useful modules
for mod in rewrite headers deflate expires ssl http2 proxy_fcgi; do
sudo a2enmod $mod
done
# vhost.d drop-in directory (prototype.in style)
sudo mkdir -p /etc/apache2/vhost.d
sudo tee /etc/apache2/conf-available/vhost-dropin.conf > /dev/null <<'EOF'
IncludeOptional /etc/apache2/vhost.d/*.conf
EOF
sudo a2enconf vhost-dropin
# Apache MPM event tuned for 16GB / N150
sudo tee /etc/apache2/conf-available/mpm-n150.conf > /dev/null <<'EOF'
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 100
MaxConnectionsPerChild 1000
</IfModule>
EOF
sudo a2enconf mpm-n150
sudo a2enmod mpm_event 2>/dev/null || true
# --- MariaDB ---
sudo apt install -y mariadb-server mariadb-client
sudo systemctl enable mariadb
sudo mysql_secure_installation <<'MYSQL' || true
y
n
y
y
y
MYSQL
# InnoDB tuning for 16GB RAM
sudo tee /etc/mysql/mariadb.conf.d/99-n150.cnf > /dev/null <<'EOF'
[mysqld]
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
query_cache_type = 0
tmp_table_size = 64M
max_heap_table_size = 64M
max_connections = 100
thread_cache_size = 8
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
EOF
sudo systemctl restart mariadb
# --- PHP 8.3 + PHP-FPM ---
sudo add-apt-repository -y ppa:ondrej/php
sudo apt update
sudo apt install -y \
php8.3 php8.3-fpm php8.3-cli \
php8.3-mysql php8.3-xml php8.3-curl php8.3-mbstring \
php8.3-zip php8.3-gd php8.3-intl php8.3-bcmath \
php8.3-soap php8.3-redis php8.3-xdebug php8.3-opcache \
php8.3-imagick php8.3-sqlite3 \
composer
# PHP-FPM pool tuning for N150 (4 cores, 6W TDP — be conservative)
PHP_POOL=/etc/php/8.3/fpm/pool.d/www.conf
sudo sed -i 's/^pm = .*/pm = dynamic/' $PHP_POOL
sudo sed -i 's/^pm.max_children = .*/pm.max_children = 20/' $PHP_POOL
sudo sed -i 's/^pm.start_servers = .*/pm.start_servers = 4/' $PHP_POOL
sudo sed -i 's/^pm.min_spare_servers = .*/pm.min_spare_servers = 2/' $PHP_POOL
sudo sed -i 's/^pm.max_spare_servers = .*/pm.max_spare_servers = 8/' $PHP_POOL
# OPcache for dev
sudo tee /etc/php/8.3/mods-available/opcache-dev.ini > /dev/null <<'EOF'
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=1
opcache.validate_timestamps=1
opcache.jit=1255
opcache.jit_buffer_size=128M
EOF
sudo phpenmod opcache-dev
# Xdebug 3 config
sudo tee /etc/php/8.3/mods-available/xdebug.ini > /dev/null <<'EOF'
zend_extension=xdebug.so
xdebug.mode=debug,coverage
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
xdebug.idekey=PHPSTORM
xdebug.discover_client_host=0
xdebug.start_with_request=yes
EOF
sudo systemctl enable php8.3-fpm
sudo systemctl restart php8.3-fpm
# Wire Apache → PHP-FPM
sudo tee /etc/apache2/conf-available/php83-fpm.conf > /dev/null <<'EOF'
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>
EOF
sudo a2enconf php83-fpm
sudo systemctl restart apache2
# =============================================================================
# 7. NODE / BUN
# =============================================================================
section "7. Node.js LTS + Bun"
# Node via nvm (user-space)
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
export NVM_DIR="$HOME/.nvm"
# shellcheck source=/dev/null
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install --lts
nvm use --lts
nvm alias default node
# Bun
curl -fsSL https://bun.sh/install | bash
# Global npm tools
npm install -g \
pm2 \
@anthropic-ai/sdk \
typescript \
tsx \
prettier
# =============================================================================
# 8. GIT + SSH AGENT
# =============================================================================
section "8. Git + SSH"
sudo apt install -y git openssh-server openssh-client
sudo systemctl enable ssh
git config --global core.autocrlf input
git config --global pull.rebase true
git config --global init.defaultBranch main
# SSH agent autostart via KDE
mkdir -p "$HOME/.config/autostart-scripts"
tee "$HOME/.config/autostart-scripts/ssh-agent.sh" > /dev/null <<'EOF'
#!/bin/bash
[ -z "$SSH_AUTH_SOCK" ] && eval "$(ssh-agent -s)" && ssh-add
EOF
chmod +x "$HOME/.config/autostart-scripts/ssh-agent.sh"
# SSH hardening
sudo tee /etc/ssh/sshd_config.d/99-hardened.conf > /dev/null <<'EOF'
PasswordAuthentication yes
PubkeyAuthentication yes
PermitRootLogin no
MaxAuthTries 3
ClientAliveInterval 120
ClientAliveCountMax 2
EOF
sudo systemctl restart ssh
# =============================================================================
# 9. NETWORK — WiFi 6 + RJ45 OPTIMIZATION
# =============================================================================
section "9. Network"
sudo apt install -y net-tools nmap iperf3 ethtool
# WiFi power save OFF (N150 iwlwifi)
sudo tee /etc/NetworkManager/conf.d/wifi-powersave-off.conf > /dev/null <<'EOF'
[connection]
wifi.powersave = 2
EOF
# iwlwifi options — disable 11n/buggy firmware quirks if needed
sudo tee /etc/modprobe.d/iwlwifi.conf > /dev/null <<'EOF'
options iwlwifi power_save=0
options iwlwifi uapsd_disable=1
EOF
sudo nmcli general reload
# =============================================================================
# 10. DOCKER (optional secondary — native stack primary)
# =============================================================================
section "10. Docker (secondary)"
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker "$USER"
sudo systemctl enable docker
# =============================================================================
# 11. DEV TOOLS
# =============================================================================
section "11. Dev tools"
# phpMyAdmin
sudo apt install -y phpmyadmin 2>/dev/null || true
# Redis
sudo apt install -y redis-server
sudo systemctl enable redis-server
# Mailpit (local SMTP trap, replaces MailHog)
curl -fsSL https://raw.githubusercontent.com/axllent/mailpit/develop/install.sh | bash || true
# Adminer (lightweight phpMyAdmin alt)
sudo mkdir -p /var/www/html/adminer
sudo wget -qO /var/www/html/adminer/index.php \
https://www.adminer.org/latest.php || true
# Symfony CLI
curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.deb.sh' | sudo -E bash
sudo apt install -y symfony-cli || true
# =============================================================================
# 12. ZSH + OH-MY-ZSH
# =============================================================================
section "12. ZSH"
if [ ! -d "$HOME/.oh-my-zsh" ]; then
RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
fi
# Plugins
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
[ -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ] || \
git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
[ -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ] || \
git clone https://github.com/zsh-users/zsh-syntax-highlighting "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
sed -i 's/plugins=(git)/plugins=(git composer symfony2 docker npm zsh-autosuggestions zsh-syntax-highlighting)/' "$HOME/.zshrc"
# Aliases
cat >> "$HOME/.zshrc" <<'ALIASES'
# prototype.in aliases
alias art='php artisan'
alias sf='symfony console'
alias comp='composer'
alias phpu='./vendor/bin/phpunit'
alias phpstan='./vendor/bin/phpstan'
alias fpm='sudo systemctl restart php8.3-fpm && sudo systemctl restart apache2'
alias slog='sudo tail -f /var/log/apache2/error.log'
alias mlog='sudo tail -f /var/log/mysql/error.log'
alias dlog='sudo journalctl -u docker -f'
alias ports='ss -tulnp'
alias htop='btop'
ALIASES
chsh -s "$(which zsh)" "$USER"
# =============================================================================
# 13. FLATPAK + APP ESSENTIALS
# =============================================================================
section "13. Apps"
sudo apt install -y flatpak
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
# PHPStorm (JetBrains Toolbox is the recommended install path)
info "JetBrains Toolbox — install manually from https://www.jetbrains.com/toolbox-app/"
info "Or via Flatpak:"
info " flatpak install flathub com.jetbrains.PhpStorm"
# Firefox Wayland-native
sudo snap remove firefox 2>/dev/null || true
flatpak install -y flathub org.mozilla.firefox || true
# =============================================================================
# 14. SWAP / ZRAM (N150 thrash guard)
# =============================================================================
section "14. ZRAM (swap compression)"
sudo apt install -y zram-config || sudo apt install -y zram-tools
sudo tee /etc/default/zramswap > /dev/null <<'EOF'
ALGO=zstd
PERCENT=25
EOF
sudo systemctl restart zramswap 2>/dev/null || sudo systemctl restart zram-config 2>/dev/null || true
# Swappiness — lower for SSD/ZRAM combo
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl -p /etc/sysctl.d/99-swappiness.conf
# =============================================================================
# 15. FIREWALL
# =============================================================================
section "15. UFW"
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8025/tcp # Mailpit
sudo ufw --force enable
# =============================================================================
# DONE
# =============================================================================
section "✅ Done!"
info "Log: $LOGFILE"
info ""
info "Next steps:"
info " 1. Reboot → Wayland session"
info " 2. sudo tlp-stat -b (check battery thresholds)"
info " 3. vainfo (verify VA-API / Intel UHD)"
info " 4. Install PHPStorm via JetBrains Toolbox"
info " 5. Add vhost configs to /etc/apache2/vhost.d/"
info " 6. Clone github.com/pbrilius/orm → composer install"
info ""
warn "Docker group active after next login (newgrp docker)"
warn "Xdebug enabled by default — disable for prod: phpdismod xdebug"
neofetch

Comments are disabled for this gist.