Blog

  • Headless Sunshine Game Streaming Setup on Ubuntu 24.04 (Xorg)

    This guide outlines the definitive setup for running the LizardByte Sunshine game streaming server on a headless Ubuntu 24.04 system.

    It specifically solves the common “race condition” boot failures and the “Unable to open display” app launch crashes (commonly seen with Steam) by utilizing a supervised, custom systemd user service mapped explicitly to the Xorg session.

    Phase 1: Force Auto-Login (The Headless Fix)

    Because there is no physical monitor, Ubuntu will not launch a graphical environment (xdg-desktop-autostart.target) until a user logs in. We must force GDM3 to auto-login the primary user so the Xorg server starts rendering the desktop in the background.

    1. Open the display manager config:

    sudo nano /etc/gdm3/custom.conf

    2. Under the [daemon] section, uncomment and set the following (replace YOUR_USERNAME with your actual Linux user):

    [daemon]
    AutomaticLoginEnable=true
    AutomaticLogin=YOUR_USERNAME

    3. Save, exit, and reboot the system:

    sudo reboot

    Phase 2: Clean Installation

    Always install the .deb package. Avoid the Flatpak version, as its heavy sandboxing completely breaks the ability to run local master scripts or trigger host applications natively.

    1. Download the latest .deb for Ubuntu 24.04 from the LizardByte GitHub Releases page.

    2. Install the package and force dependency resolution:

    sudo apt install -f ./sunshine-ubuntu-24.04-amd64.deb

    Phase 3: Nuke the Default Services

    The default system-level and user-level systemd hooks provided by the package are notoriously fragile on headless setups. We must kill them to prevent port conflicts (Address already in use) and permission denials (like PulseAudio access).

    Run these commands to strip out the default hooks:

    sudo systemctl stop sunshine
    sudo systemctl disable sunshine
    systemctl --user stop sunshine
    systemctl --user disable sunshine

    Phase 4: Create the Bulletproof Custom Service

    To ensure Sunshine survives crashes, waits for the user login rather than the buggy graphical targets, and has the proper permissions to launch UI apps like Steam, we build a custom user-level service.

    1. Create the user systemd directory:

    mkdir -p ~/.config/systemd/user

    2. Create the custom service file:

    nano ~/.config/systemd/user/sunshine.service

    3. Paste the following configuration. (Note: The Environment variables are critical. They inject the exact display coordinates into Sunshine. Without them, apps launched from Moonlight will crash with a segmentation fault/assertion failed error because they cannot find the headless display).

    [Unit]
    Description=Sunshine Game Stream Server (Supervised)
    After=network.target
    
    [Service]
    # Explicitly pass the display coordinates to fix "Unable to open display" crashes
    # Note: UID 1000 is standard for the primary user. Change if yours differs.
    Environment="DISPLAY=:0"
    Environment="XAUTHORITY=/run/user/1000/gdm/Xauthority"
    
    ExecStart=/usr/bin/sunshine
    
    # Aggressive restart logic if the stream crashes or boots faster than the GPU initializes
    Restart=always
    RestartSec=5
    
    [Install]
    # Bind to the user login, ignoring the traditional graphical boot targets
    WantedBy=default.target

    Phase 5: Enable, Start, and Linger

    Finally, we lock the new service in place and tell Linux to keep this user’s services running even if the desktop session is backgrounded.

    # Reload systemd to recognize the custom file
    systemctl --user daemon-reload
    
    # Enable and start the service
    systemctl --user enable sunshine
    systemctl --user start sunshine
    
    # Force the user's services to survive reboots unattended
    loginctl enable-linger $USER

    Verification

    1. Check the service status to ensure it is active (running):

    systemctl --user status sunshine

    2. Navigate to https://<server-ip>:47990 from another machine to access the Web UI and begin adding applications.

  • Using a 5TB Drive for Ubuntu Server on Raspberry Pi 5 (With MBR Partition Limits)

    Challenge: When flashing Ubuntu Server onto a drive larger than 2TB using Raspberry Pi Imager, the resulting root partition is limited to only ~3.2GB. Additionally, drives using the MBR (msdos) partition table cannot support partitions larger than ~2TB due to technical limits (maximum of 232 sectors).

    This guide shows how to:

    • Flash Ubuntu Server onto a large HDD (5TB)
    • Resize the root partition to 250GB (safe under MBR limits)
    • Use the remaining unallocated space (~4.2TB) for general storage

    Step 1: Flash Ubuntu Server Image onto the 5TB Drive

    1. Download the official Ubuntu Server image for Raspberry Pi from ubuntu.com.
    2. Use Raspberry Pi Imager to write the image to your 5TB drive:
      • Select the Ubuntu Server image.
      • Choose your 5TB drive as the target.
      • Click “Write” to flash the image.
    3. After flashing, the drive contains:
      • /dev/sda1 – 512MB FAT32 boot partition
      • /dev/sda2 – ~3.2GB ext4 root partition

    Step 2: Resize Root Partition to 250GB

    This avoids MBR’s partition size limits and allows for practical use without converting to GPT.

    1. Connect the drive to a Linux system.
    2. Run lsblk to verify the partitions:
      lsblk
    3. Unmount the partitions if mounted:
      sudo umount /dev/sda1
      sudo umount /dev/sda2
    4. Open parted:
      sudo parted /dev/sda
    5. Inside parted, run:
      rm 2
      mkpart primary ext4 512MB 250GB
      print
      quit
    6. Format the new root partition:
      sudo mkfs.ext4 /dev/sda2
    7. Run filesystem check and resize:
      sudo e2fsck -f /dev/sda2
      sudo resize2fs /dev/sda2

    Step 3: Boot the Raspberry Pi 5

    1. Connect the 5TB HDD to your Raspberry Pi 5.
    2. Boot the Pi — it should use the resized 250GB root partition.
    3. Use lsblk or df -h to confirm partitions.

    Step 4: Format and Mount the Remaining ~4.2TB Space

    1. Back on the Pi (or another Linux system), open parted again:
      sudo parted /dev/sda
    2. Create a new partition in remaining space:
      mkpart primary ext4 250GB 100%
      print
      quit
    3. Format the new partition:
      sudo mkfs.ext4 /dev/sda3
    4. Create a mount point:
      sudo mkdir -p /mnt/data
    5. Get the UUID of the new partition:
      sudo blkid /dev/sda3

      Example output:

      /dev/sda3: UUID="abcd-1234" TYPE="ext4"
    6. Edit /etc/fstab to auto-mount on boot:
      sudo nano /etc/fstab

      Add this line (replace UUID with yours):

      UUID=abcd-1234 /mnt/data ext4 defaults 0 2
    7. Mount immediately and verify:
      sudo mount -a
      df -h /mnt/data
    8. (Optional) Set ownership:
      sudo chown -R $USER:$USER /mnt/data
      sudo chmod 755 /mnt/data

    ✅ Result:

    • /dev/sda2 is a 250GB root partition
    • /dev/sda3 is a ~4.2TB data partition, mounted at /mnt/data

    You now have a fully bootable Ubuntu Server system on your Raspberry Pi 5 with proper partitioning for large drives under MBR.

  • Setting Up Ubuntu Server on a 5TB HDD for Raspberry Pi 5 to bypass 2TB limit

    Flash Ubuntu Server to a 5TB HDD for Raspberry Pi 5, then resize the root partition to 250GB within MBR partition table limits.


    Step 1: Flash Ubuntu Server Image onto the 5TB Drive

    1. Download the official Ubuntu Server image for Raspberry Pi from the Ubuntu website.
    2. Use Raspberry Pi Imager to write the image to your 5TB HDD:
      • Select the downloaded Ubuntu Server image.
      • Select your 5TB drive as the target.
      • Flash the image.
    3. After flashing, the image creates two partitions by default:
      • sda1 — FAT32 boot partition (~512MB)
      • sda2 — ext4 root partition (~3.2GB)

    Step 2: Resize the Root Partition (/dev/sda2) to 250GB on the Host Linux System you imaged with

    Note: Do not connect this to the Pi! These actions need to be performed on a linux PC where this is an external device.

    Note: The 5TB disk uses an MBR (msdos) partition table, which limits partitions to a maximum of ~2TB. To avoid partition size errors, resize root to 250GB.

    1. Check disk and partition layout:
      lsblk
    2. Unmount partitions if mounted:
      sudo umount /dev/sda1 sudo umount /dev/sda2
    3. Launch parted to modify partitions:
      sudo parted /dev/sda
    4. Inside parted:
      • Delete existing root partition:bashCopyEditrm 2
      • Create a new root partition sized at 250GB:
        mkpart primary ext4 512MB 250GB
      • Verify partitions:arduinoCopyEditprint
      • Exit parted:nginxCopyEditquit
    5. Format the new root partition as ext4:
      sudo mkfs.ext4 /dev/sda2
    6. Run filesystem check on the new partition:
      sudo e2fsck -f /dev/sda2
    7. Resize filesystem to fill the new partition size:
      sudo resize2fs /dev/sda2

    Step 3: Boot Raspberry Pi 5 with the Resized 5TB HDD

    1. Connect the 5TB HDD to the Raspberry Pi 5.
    2. Power on and boot from the drive.
    3. On first boot, the system will use the 250GB root partition.
    4. (Optional) Once booted, you can create additional partitions in the remaining space or consider migrating to GPT to use full disk size later.

    Step 4: Verify Partition and Filesystem Size on Pi

    After boot, verify sizes with:

    bashCopyEditlsblk
    df -h /
    

    Notes

    • MBR Limit: The MBR partition table restricts partition sizes; for disks over 2TB, GPT is preferred.
    • Future Expansion: For full 5TB usage as a single partition, convert the disk to GPT and reinstall Ubuntu Server.
    • Data Partitions: You can use remaining unallocated space for data partitions formatted separately.