Skip to content

Instantly share code, notes, and snippets.

@gosuri
Created June 3, 2025 14:42
Show Gist options
  • Save gosuri/80758d73fb53768b52ad143e4ab695ec to your computer and use it in GitHub Desktop.
Save gosuri/80758d73fb53768b52ad143e4ab695ec to your computer and use it in GitHub Desktop.
Hardening GPD Micro PC with Ubuntu

Hardening GPD Micro PC with Ubuntu

Below is a step-by-step hardening checklist that keeps your GPD Micro PC (Ubuntu Desktop 24.04.2 LTS, Ubuntu Pro enabled)

Replace Windows with Ubuntu

This guide assumes your primary workstation runs MacOS

Grab and check the ISO

Run the below from the terminal

curl -LO https://releases.ubuntu.com/24.04/ubuntu-24.04-desktop-amd64.iso
curl -LO https://releases.ubuntu.com/24.04/SHA256SUMS
shasum -a 256 ubuntu-24.04-desktop-amd64.iso

Compare the hash to the publisher’s list. (Skip if you’re in a hurry.)

Flash the card

diskutil list                          # find your card, e.g. /dev/disk3
diskutil unmountDisk /dev/disk3
sudo dd if=ubuntu-24.04-desktop-amd64.iso of=/dev/rdisk3 bs=4m status=progress
diskutil eject /dev/disk3

Boot on the GPD MicroPC

  1. Insert the card in the micro-SD slot (left side).
  2. Hold Fn + F7 while pressing the power button → pick UEFI: SD/MMC … from the blue list.
  3. The Linux installer appears (likely rotated 90°—normal on the MicroPC).
  4. Install to the internal SSD or run live; remove the card when done.

Quick fixes after install

  • Portrait screen? xrandr --output eDP-1 --rotate normal (add to ~/.xprofile).
  • Wi-Fi firmware (Debian only): sudo apt install firmware-iwlwifi.
  • Want persistence on the card? Use Ventoy + persistence plugin or mkusb.

That’s it—flash, Fn + F7, and you’re rolling Linux on your pocket-size powerhouse.

Secure the firmware & boot chain

What How
Set a BIOS/UEFI password Prevents evil-maid attacks.
Enable Secure Boot Works with Ubuntu 24.04 by default.
Disable external boot devices Turn off “USB boot” and “PXE” in firmware.
Update system firmware sudo fwupdmgr get-updates && sudo fwupdmgr update

Install (or reinstall) Ubuntu with full-disk encryption

  • During the installer pick “Erase disk → Encrypt Ubuntu for security”.
  • Use a strong, memorizable passphrase; store it in your password manager.

Baseline updates & Ubuntu Pro services

sudo apt update && sudo apt full-upgrade     # bring everything current
sudo pro attach <YOUR-TOKEN>
sudo pro enable livepatch           # kernel patching without reboots
sudo pro enable usg                 # turns on the Ubuntu Security Guide (USG)
sudo apt install usg                # installs the CLI if it isn’t pulled in automatically 

Automate CIS-Level 1 hardening with USG

sudo usg generate-tailoring cis_level1_workstation my_cis.xml
sudo usg audit  --tailoring-file my_cis.xml   # see what would change
sudo usg fix    --tailoring-file my_cis.xml   # apply the remediations

USG for 24.04 ships with the official CIS benchmark, so the bulk of permissions, kernel parameters, and file-system flags are adjusted for you. 

Remove non-essential apps

Make a throw away list

# One-liner that captures every package installed today
today="$(date +%Y-%m-%d)"
dpkg -l | awk '$1=="ii"{print $2}' > ~/pkglist-$today.txt

See what’s installed (and mark “keepers”)

apt-mark showmanual 

Below is a traffic-light guide to the packages on your manual list.

🔴 RED is core to booting, logging-in or keeping the disk encrypted—leave it alone. 🟢 Everything in GREEN is non-essential for a “browser + Ledger” box and can be purged if you’re sure you won’t miss the feature. 🟡 YELLOW items are technically optional but keep them if you rely on the function they provide.

Keep / Remove? Package(s) Why it’s here Action
🔴 MANDATORY bsdutils dash diffutils findutils grep gzip hostname init login ncurses-* shim-signed grub-* efibootmgr linux-generic-hwe-24.04 ubuntu-minimal ubuntu-standard ubuntu-desktop-minimal ubuntu-advantage-tools cryptsetup lvm2 ubuntu-wallpapers ubuntu-restricted-addons Shell, coreutils, bootloader, kernel meta, LUKS, UA-Pro hooks, GNOME meta packages. Removing any of these = unbootable or upgrade-broken system. KEEP
🟡 Depends on your workflow openssh-server – remote shell; net-tools – old ifconfig/netstat; usbguard usg – we deliberately installed these; aide – file-integrity scanner; ubuntu-wallpapers – cosmetic If you never SSH in, drop openssh-server. net-tools is superseded by iproute2. aide, usbguard, usg are useful for hardening—keep unless you have an alternative. Remove only what you truly don’t use
🟢 Safe to purge Input-method & locale clutter ibus-table-cangjie-* libchewing3* libpinyin* libopencc* libm17n-0 libmarisa0 libotf1 m17n-db language-pack-en* language-pack-gnome-en* wbritish (the English language packs are optional on an English system—GNOME falls back to built-in C.UTF-8) Bluetooth / file-push extras blueman obexfs Chinese/Cangjie, Chewing, Pinyin, OpenCC are totally redundant for an English-only signing station. blueman & obexfs handle Bluetooth file transfers—turned off in your threat model PURGE if you don’t need Chinese input or Bluetooth

Nuke the green group

sudo apt purge --autoremove \
  blueman obexfs \
  ibus-table-cangjie-big ibus-table-cangjie3 ibus-table-cangjie5 \
  libchewing3 libchewing3-data libpinyin-data libpinyin15 \
  libopencc-data libopencc1.1 libm17n-0 libmarisa0 libotf1 m17n-db \
  wbritish

(Skip any package the system says is “not installed”.)

Batch-purge common desktop extras

sudo apt purge --autoremove \
  aisleriot cheese evolution gnome-{calculator,calendar,characters,clocks,contacts,disk-utility,logs,maps,photos,sudoku,mahjongg,mines,music,tour,weather} \
  libreoffice-*  shotwell simple-scan remmina rhythmbox \
  thunderbird totem transmission-gtk

These are the apps that ship in a default (not “Full”) Noble install, according to Ubuntu’s manifest and community docs.  --autoremove tidies up any orphan libraries those programs dragged in.

After the purge

sudo apt autoremove --purge   # sweep orphaned libs
sudo apt update && sudo apt full-upgrade

Reboot and confirm everything still works: encrypted drive unlocks, Xorg/Wayland starts, browser + Ledger Live operate, and UFW / USBGuard / USG are still live.

That’s it—your GPD Micro PC is now lean with zero language packs you don’t speak, no Bluetooth surface, and only the hardening tools you intentionally installed.

Scrub the Snap side

# list snaps, remove anything you don't need
snap list

# typical desktop snaps you can live without:
sudo snap remove snap-store gnome-characters gnome-clocks gnome-calculator
sudo snap remove gnome-logs gnome-system-monitor       # if not needed

Shrink the base system

If you really want to match the “Minimal” ISO you can replace the standard meta-package:

# 1. Prevent accidental "Suggested" packages
echo 'APT::Install-Recommends "0";' | sudo tee -a /etc/apt/apt.conf.d/99no-recommends
echo 'APT::Install-Suggests   "0";' | sudo tee -a /etc/apt/apt.conf.d/99no-recommends

# 2. Make newly-added snaps ask first
sudo snap set system refresh.hold="$(date --date='today + 30 days' +%Y-%m-%d)"

Lock future bloat out

# 1. Prevent accidental "Suggested" packages
echo 'APT::Install-Recommends "0";' | sudo tee -a /etc/apt/apt.conf.d/99no-recommends
echo 'APT::Install-Suggests   "0";' | sudo tee -a /etc/apt/apt.conf.d/99no-recommends

# 2. Make newly-added snaps ask first
sudo snap set system refresh.hold="$(date -u -d '30 days' +%Y-%m-%dT%H:%M:%SZ)"

Run sudo snap get system refresh.hold to check the hold value is set to today.

Final sweep

sudo apt update && sudo apt full-upgrade
sudo apt autoremove --purge

Lock the network surface (UFW)

sudo ufw default deny incoming
sudo ufw default allow outgoing

Allow SSH (Optional)

If you're accessing the PC with SSH, make sure to allow SSH

sudo ufw allow ssh

Rate-limit brute-force attempts (5 conn / 30 s):

sudo ufw limit 22/tcp

Optionally, restrict to a single trusted IP or subnet (safer):

# Replace 203.0.113.4 with your workstation’s public IP
sudo ufw allow from 203.0.113.4 to any port 22 proto tcp

or a whole CIDR block

sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp

Enable UFW and verify

sudo ufw enable

Verify the rules

sudo ufw status verbose

You should see something like:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT IN    Anywhere
22/tcp (v6)                LIMIT IN    Anywhere (v6)
Setting Recommended value Command / note
Default incoming policy deny sudo ufw default deny incoming (already set)
Default outgoing policy allow sudo ufw default allow outgoing (already set)
SSH rule added allow 22/tcp (or scoped) see above
Log level low (helps audit) sudo ufw logging low

USB-device whitelisting with USBGuard

Install and generate an initial rule-set:

sudo apt install usbguard  
sudo usbguard generate-policy > rules.conf

The generate-policy command scans every USB device the kernel currently knows about and writes a baseline rule-set: “allow everything that’s plugged in right now; block everything else by default.” Each line it prints is an allow rule like the ones you just viewed—complete with VID:PID, serial, name, hash, parent-hash, port path, interface classes, and connect type.

Allow Ledger Devices

echo "allow id 2c97:* serial "*" hash "*" name "*" with-interface * with-connect-type *" >> rules.conf
echo "block with-interface *" >> rules.conf

Enable Rules

sudo mv rules.conf /etc/usbguard/rules.conf
sudo systemctl enable --now usbguard

Everything else (thumb-drives, malicious HID devices) is blocked unless manually approved.

You can now plugin your ledger and run sudo usbguard watch to watch it connect in realtime.

Enable Ledger Live safely (Optional)

# Fetch the signed AppImage
wget -O ~/Downloads/ledger-live.AppImage https://download.live.ledger.com/latest/linux
chmod +x ~/Downloads/ledger-live.AppImage

wget -q -O - https://raw.githubusercontent.com/LedgerHQ/udev-rules/master/add_udev_rules.sh | sudo bash

# Install libfuse2 for ledger
sudo apt update
sudo apt install libfuse2         # 280 KB, no reboot needed

# (Optional) be sure the kernel module is loaded
sudo modprobe fuse                # should return nothing

# Unpack the AppImage 
./ledger-live.AppImage --appimage-extract          # creates  ./squashfs-root

# Move it where only root can write
sudo mv squashfs-root /opt/ledger-live

# Fix the helper’s ownership & mode
sudo chown root:root /opt/ledger-live/chrome-sandbox
sudo chmod 4755      /opt/ledger-live/chrome-sandbox   # set-uid root

# Launch Ledger Live
/opt/ledger-live/ledger-live-desktop

Because the files now live on a real ext4 partition (not a FUSE nosuid mount) the set-uid bit is honored and the error disappears. This keeps Ledger Live fully sandboxed.

Harden the browser

Use Firefox Snap (already confined with AppArmor) or run any browser with Firejail for an extra seccomp + namespace cage:

sudo apt install firejail firejail-profiles  
firejail --private --dns=9.9.9.9 --seccomp firefox

Turn off automatic media & USB mounting

gsettings set org.gnome.desktop.media-handling automount false
gsettings set org.gnome.desktop.media-handling automount-open false

This complements USBGuard in case a device slips through.

AppArmor & additional kernel tweaks

Ubuntu already ships many profiles in /etc/apparmor.d/. Ensure they load:

sudo aa-enforce /etc/apparmor.d/*

Add extra hardening to /etc/sysctl.d/99-hardening.conf (example):

kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
net.ipv4.conf.all.rp_filter = 1
fs.protected_fifos = 2

Apply with sudo sysctl --system.

Replace Firefox with Chrome

sudo install -d -m 0755 /etc/apt/keyrings
wget -qO- https://dl.google.com/linux/linux_signing_key.pub |
  sudo gpg --dearmor -o /etc/apt/keyrings/google-linux-signing-keyring.gpg

# create repo defination
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google-linux-signing-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list

# update and install
sudo apt update
sudo apt install google-chrome-stable

Installing Ledger CLI

sudo apt update
# build & HID libraries
sudo apt install -y python3-pip python3-venv pipx \
                    libusb-1.0-0-dev libhidapi-libusb0 libhidapi-dev
pipx ensurepath      # adds ~/.local/bin to $PATH on next login
curl -sSL https://raw.githubusercontent.com/LedgerHQ/udev-rules/master/add_udev_rules.sh | sudo bash
sudo udevadm control --reload
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment