Ubuntu LTS Set-Up

It is not every day that I have to set up a fresh install of Ubuntu, and I end up forgetting and having to repeat research on specific “tweaks”. I am now using this page as my own reference, based on an installation on x86-64 architecture hardware.

 

“Live” Ubuntu USB/CD

  • it is possible to launch a “live” Ubuntu environment, complete with graphical UI (assuming all relevant drivers to support the hardware are already included) from a “live” Ubuntu desktop (i.e. not server)
  • if setting up serial console access, either create a custom version, or edit the GRUB boot entry (i.e. press “e” to edit the boot options), add the serial port configuration e.g. console=ttySN,115200n8, then press Ctrl X to boot with the edited kernel parameters
  • if accessing via serial console, the username is “ubuntu” with an empty/no password

 

netplan

  • assuming netplan is being used and rendered using systemd-networkd instead of Network Manager, an example of a netplan YAML file 20-br0.yaml with LACP ports and VLANs is as follows:
    network:
      version: 2
      renderer: networkd
      ethernets:
        # ETH0 port at back of AMD 8845HS M/B
        enp3s0:
          dhcp4: false
          optional: true
          mtu: 9000
        # ETH1 port at back of AMD 8845HS M/B
        enp4s0:
          dhcp4: false
          optional: true
          mtu: 9000
    
      bonds:
        bond0:
          interfaces: [ enp3s0, enp4s0 ]
          mtu: 9000
          parameters:
            mode: 802.3ad
            lacp-rate: fast
            mii-monitor-interval: 100
            transmit-hash-policy: layer2+3
    
      bridges:
      # LAN interface
      br0:
        dhcp4: false
        interfaces: [ bond0 ]
        addresses: [ m.n.o.p/24 ]
        routes:
          - to: default
            via: m.n.o.1
        nameservers:
        addresses: [ m.n.o.1 ]
        mtu: 9000
    
      vlans:
        bond0.7:
          id: 7
          link: bond0
          accept-ra: no
        bond0.8:
          id: 8
          link: br0
          accept-ra: no
    
      bridges:
        br1:
          dhcp4: false
          interfaces: [ bond0.7 ]
          addresses: [ a.b.c.d/24 ]
          nameservers:
            addresses: [ a.b.c.1 ]
          mtu: 9000
        br2:
          dhcp4: false
          interfaces: [ bond0.8 ]
          addresses: [ w.x.y.z/24 ]
          nameservers:
            addresses: [ w.x.y.1 ]
          mtu: 9000

 

SSHd

  • install ssh
    • apt install openssh-server
    • systemctl enable ssh
  • create public key in ~/.ssh/authorized_keys
  • configure SSHd
    • ensure the “main” /etc/ssh/sshd_config has the Include /etc/ssh/sshd_config.d/*.conf directive at the very first active/non-commented line
    • create /etc/ssh/sshd_config.d/00-default.conf with the following:
      # enable tunnelled password authentication
      PasswordAuthentication yes
      ChallengeResponseAuthentication yes
      
      # enable public key authentication w/possible less secure RSA keys
      PubkeyAuthentication yes
      PubkeyAcceptedKeyTypes=+ssh-rsa
      AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
      
      # use local PAM
      UsePAM yes
      
      # disable root login
      PermitRootLogin no
      PermitEmptyPasswords no
      
      # enforce pubkey THEN password requirement:
      AuthenticationMethods publickey,password
      
      X11Forwarding yes
      AllowAgentForwarding no
      AllowTcpForwarding no
      PrintMotd no
    • ensure existing ‘root’ SSH session/alternate root access in case of required rollback
    • restart SSHd – any configuration issues would prevent service from restarting:
      • systemctl restart ssh
    • test SSH log in with authorized public key then password

 

Window Manager and GUI

  • install a GUI/desktop for Ubuntu server
    • apt install lightdm

      Yes, I know lightdm runs as root, vs. gdm3 which only runs the “greeter”/login manager but passes ownership to the current logged-in user, but to make x11vnc work (instructions below), ends up requiring a whole litany of complex work-arounds (like here and/or here)…

    • apt install ubuntu-desktop dbus-x11

 

x11vnc

  • assuming lightdm has been installed (as above)
  • install x11vnc:
    • apt install x11vnc
  • create the password file for VNC access (past initial “one-password-for-all” authentication, the VNC window appears and OS credentials are then required):
    • as x11vnc would runs as lightdm (by service configuration below), create a directory to store the password file then secure it:
      mkdir /etc/x11vnc.d
      touch /etc/x11vnc.d/vncpasswd
      
    • run x11vnc -storepasswd /etc/x11vnc.d/vncpasswd then enter the password on the masked prompt
    • then ensure the proper ownership and permissions are set:
      chmod u+rw-x,g+r-wx,o-rwx /etc/x11vnc.d/vncpasswd
      chown root:lightdm /etc/x11vnc.d/vncpasswd
  • create the /etc/systemd/system/x11vnc.service service file:
    [Unit]
    Description=Start x11vnc at startup.
    After=multi-user.target display-manager.service
    
    [Service]
    Type=simple
    User=lightdm
    ExecStart=/usr/bin/x11vnc -auth guess -forever -loop -noxdamage -repeat -rfbauth /etc/x11vnc.d/vncpasswd -rfbport 5900 -shared -display :0
    ExecStop=killall x11vnc
    Restart=always
    RestartSec=3
    
    [Install]
    WantedBy=multi-user.target graphical.target
  • reload systemd configuration:
    • systemctl daemon-reload
  • enable x11vnc service:
    • systemctl enable x11vnc
  • disable Wayland
    • edit /etc/gdm3/custom.conf and remove the comment mark (“#” character) from the line
      #WaylandEnable=false
  • reboot

2025/09/06 Update: If you are wanting to copy-paste bidirectionally across VNC client and x11vnc host environments, please look here.

 

Resetting/Overwriting the X11vnc Password

  • if you forget the password, you could simply overwrite the password, remembering to (re)set the correct permissions:
    x11vnc -storepasswd /etc/x11vnc.d/vncpasswd
    chmod u+rw-x,g+r-wx,o-rwx /etc/x11vnc.d/vncpasswd
    chown root:lightdm /etc/x11vnc.d/vncpasswd

 

Decrypting the x11vnc Password

  • if want to retrieve the x11vnc password instead of just overwriting it, here’s vncpwd to the rescue!

 

Truly Headless with Dummy Monitor

  • to be truly headless, create a “dummy” video card and monitor
    • WARNING: if after implementing this, an actual display is plugged in/used, it would be part of a multi-monitor setup – I tend to prefer HDMI EDID emulators with pass-through ports (more on that here)
    • w.r.t. this Stack Exchange answer, create the following sections in /etc/X11/xorg.conf:
      Section "Device"
         Identifier "Configured Video Device"
         Driver     "dummy"
         VideoRam   40000
      EndSection
      Section "Monitor"
         Identifier "Configured Monitor"
         HorizSync 22-83
         VertRefresh 50-70
         Modeline     "1920x1200_60.00" 193.16 1920 2048 2256 2592 1200 1201 1204 1242 -HSync +Vsync
      EndSection
      Section "Screen"
         Identifier "DefaultScreen"
         Monitor    "Configured Monitor"
         Device     "Configured Video Device"
         DefaultDepth 24
         SubSection "Display"
             Depth 24
             Modes "1920x1200"
         EndSubSection
      EndSection

 

systemd-networkd

boot delays

  • tired of those 120s boot delays while the network waits for DHCP (and there isn’t a DHCPd or a even a network link)?
  • follow this fix:
    • sudo systemctl disable systemd-networkd-wait-online.service
    • sudo systemctl mask systemd-networkd-wait-online.service
  • also mark all unneeded interfaces as optional e.g. in /etc/netplan/nn-whatever.yaml:
    Netplan
  • to find out which services are impacted:
    • sudo systemctl show -p WantedBy network-online.target

 

resolv.conf and DNS Resolution

  • if using systemd-networkd, /etc/resolv.conf may get overwritten (or to be technically correct, regenerated) and the correct/recommended practice should be to either edit /etc/systemd/resolved.conf or add some file in /etc/systemd/resolved.conf.d/ (e.g. /etc/systemd/resolved.conf.d/00-default.conf):
    [Resolve]
    DNS=8.8.8.8
  • to check, run systemd-analyze cat-config systemd/resolved.conf

 

networkd-dispatcher

  • if you need to run “hook” scripts ala ifupdown of ‘ye ol days, or even just advanced configuration like turning off offloading in /etc/network/interfaces, netplan just made it unnecessarily more complicated
    • create /etc/99-disable-network-offloading.sh script:
      #!/bin/bash
      
      #troubleshooting logging
      rm /tmp/disable-offloading-systemd-cat-pipe-info
      info=/tmp/disable-offloading-systemd-cat-pipe-info
      mkfifo "$info"
      trap "exec 3>&-; rm $info" EXIT
      systemd-cat -p info < "$info" &
      exec 3>"$info"
      
      DATESTAMP=`date +"%Y-%m-%d"`
      
      
      #enp1s0f0, enp1s0f1, enp1s0f2, enp1s0f3
      IFLIST="enp1s0f0 enp1s0f1 enp1s0f2 enp1s0f3"
      unset RUNx710da4
      for IFCHECK in $IFLIST; do
      	if [ "$IFACE" == "$IFCHECK" ]; then
      		RUNx710da4=true
      	fi
      done
      if [ "$RUNx710da4" == "true" ]; then
      	LOGFILE=/tmp/disable-offloading_$IFACE\_$DATESTAMP.log
              echo "Running from: $0">>$LOGFILE
      
      	TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash ntuple-filters tx-gre-segmentation tx-gre-csum-segmentation tx-ipxip4-segmentation tx-ipxip6-segmentation tx-udp_tnl-segmentation tx-udp_tnl-csum-segmentation tx-gso-partial tx-udp-segmentation rx-udp_tunnel-port-offload"
      	CMDLINE=""
      	for TOE_OPTION in $TOE_OPTIONS; do
      		CMDLINE+=" $TOE_OPTION off"
      	done
      	echo -n "$IFACE: $CMDLINE">>$LOGFILE &&	/sbin/ethtool -K $IFACE $CMDLINE>>$LOGFILE 2>&1 && echo "">>$LOGFILE
      	unset RUNx710da4
      fi
      
      
      #enp2s0, enp3s0, enp4s0, enp6s0
      unset RUNi226v
      IFLIST="enp2s0 enp3s0 enp4s0 enp6s0"
      for IFCHECK in $IFLIST; do
              if [ "$IFACE" == "$IFCHECK" ]; then
                      RUNi226v=true
              fi
      done
      if [ "$RUNi226v" == "true" ]; then
      	LOGFILE=/tmp/disable-offloading_$IFACE\_$DATESTAMP.log
              echo "Running from: $0">>$LOGFILE
      
              TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash ntuple-filters tx-gre-segmentation tx-gre-csum-segmentation tx-ipxip4-segmentation tx-ipxip6-segmentation tx-udp_tnl-segmentation tx-udp_tnl-csum-segmentation tx-gso-partial tx-udp-segmentation rx-udp_tunnel-port-offload hw-tc-offload"
              CMDLINE=""
              for TOE_OPTION in $TOE_OPTIONS; do
                      CMDLINE+=" $TOE_OPTION off"
              done
              echo -n "$IFACE: $CMDLINE">>$LOGFILE && /sbin/ethtool -K $IFACE $CMDLINE>>$LOGFILE 2>&1 && echo "">>$LOGFILE
      	unset RUNi226v
      fi
      
      
      #br0, br1, br2, br0.1 etc....
      IFLIST="br0 br1 br2 br0.1 br0.2 br0.3 br0.4 br0.5 br0.6 br0.7 br0.8 br0.9 br1.1 br1.2 br1.3 br1.4 br1.5 br1.6 br1.7 br1.8 br1.9 br2.1 br2.2 br2.3 br2.4 br2.5 br2.6 br2.7 br2.8 br2.9"
      unset RUNbridges
      for IFCHECK in $IFLIST; do
              if [ "$IFACE" == "$IFCHECK" ]; then
                      RUNbridges=true
              fi
      done
      if [ "$RUNbridges" == "true" ]; then
              LOGFILE=/tmp/disable-offloading_$IFACE\_$DATESTAMP.log
      	echo "Running from: $0">>$LOGFILE
      
              TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash ntuple-filters tx-gre-segmentation tx-gre-csum-segmentation tx-ipxip4-segmentation tx-ipxip6-segmentation tx-udp_tnl-segmentation tx-udp_tnl-csum-segmentation tx-gso-partial tx-udp-segmentation rx-udp_tunnel-port-offload hw-tc-offload"
              CMDLINE=""
              for TOE_OPTION in $TOE_OPTIONS; do
                      CMDLINE+=" $TOE_OPTION off"
              done
              echo -n "$IFACE: $CMDLINE">>$LOGFILE && /sbin/ethtool -K $IFACE $CMDLINE>>$LOGFILE 2>&1 && echo "">>$LOGFILE
              unset RUNbridges
      fi
      
      
      #bond0, bond1 etc....
      IFLIST="bond0 bond1"
      unset RUNbonds
      for IFCHECK in $IFLIST; do
              if [ "$IFACE" == "$IFCHECK" ]; then
                      RUNbonds=true
              fi
      done
      if [ "$RUNbonds" == "true" ]; then
              LOGFILE=/tmp/disable-offloading_$IFACE\_$DATESTAMP.log
      	echo "Running from: $0">>$LOGFILE
      
              TOE_OPTIONS="rx-checksumming tx-checksumming tx-checksum-ip-generic scatter-gather tx-scatter-gather tcp-segmentation-offload tx-tcp-segmentation tx-tcp-mangleid-segmentation tx-tcp6-segmentation generic-segmentation-offload generic-receive-offload large-receive-offload rx-vlan-offload tx-vlan-offload ntuple-filters receive-hashing rx-vlan-filter tx-gso-partial tx-udp-segmentation tx-nocache-copy hw-tc-offload rx-gro-list rx-udp-gro-forwarding tx-gre-segmentation tx-gre-csum-segmentation tx-ipxip4-segmentation tx-ipxip6-segmentation tx-udp_tnl-segmentation tx-udp_tnl-csum-segmentation tx-gso-partial tx-vlan-stag-hw-insert rx-vlan-stag-hw-parse rx-vlan-stag-filter"
              CMDLINE=""
              for TOE_OPTION in $TOE_OPTIONS; do
                      CMDLINE+=" $TOE_OPTION off"
              done
              echo -n "$IFACE: $CMDLINE">>$LOGFILE && /sbin/ethtool -K $IFACE $CMDLINE>>$LOGFILE 2>&1 && echo "">>$LOGFILE
              unset RUNbonds
      fi
    • if using NetworkManager renderer, networkd-dispatcher uses /usr/lib/networkd-dispatcher/* , but networkd renderer uses /etc/networkd-dispatcher/* directories instead
  • if, somehow none of the scripts are being triggered, an alternative is to create a custom systemd service:
    • create a /etc/systemd/system/disable-network-offloading.service file:
      [Unit]
      Description=Runs script system post network start up.
      Wants=network-online.target
      After=network.target network-online.target
      
      [Service]
      Type=simple
      User=root
      ExecStart=/etc/99-disable-network-offloading.sh
      
      [Install]
      WantedBy=multi-user.target
    • register the service then start it
      • systemctl daemon-reload
      • systemctl start disable-network-offloading
    • the only issue is that this does not work on “vnetN” devices created when guest VMs are started

 

Repository Maintenance

  • upgrading from old versions may have “remnant” repositories lurking around
    • show the what is in the encoded /etc/apt/trusted.gpg file:
      • apt-key --list
    • manually remove individual entries (using the fingerprint):
      • apt-key del "xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx"
    • check the sources in /etc/apt/sources.list.d
    • check the trusted sources in /etc/apt/trusted.gpg.d
    • check sources in /etc/apt/sources.list:
      • show what is in /etc/apt/sources.list:
        • add-apt-repository --list
      • manually remove individual entries (using entire line):
        • add-apt-repository --remove "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main"
  • purging removed packages with “residual-config” (e.g. configuration files):
    • apt list | grep residual-config | cut -d'/' -f1 | sudo xargs apt -y purge
  • accidentally gave “apt install” on an existing package and then apt set the package to “manually installed”? revert the change easily:
    • apt-mark [manual|auto] <package>

 

Fix Broken/Partial/Stuck Package Installs

  • try any of the following in order:
    • sudo dpkg --configure -a
    • sudo apt-get install -f
    • delete pending actions:
      • sudo rm -fr /var/lib/dpkg/updates/*

 

Serial Console

  • trying to get Ubuntu to pipe everything through the serial console that may be available on your motherboard is a two-step process:
    1. getting GRUB to redirect everything (although tooling to do an install outright from console-only is out of scope here):
      • make a backup before doing anything:
        • sudo cp /etc/default/grub /etc/default/grub.bak
      • sudo vi /etc/default/grub and add/edit the following lines:
        GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS4,115200n8"
        GRUB_TERMINAL_INPUT="console serial"
        GRUB_TERMINAL_OUTPUT="console gfxterm serial"
        GRUB_SERIAL_COMMAND="serial --port=mmio,0xdf519000 --speed=115200 --word=8 --parity=no --stop=1"
        • note that the --port argument is usually replaced with --unit; I only document this parameter here in reference with another page – check the manual for more information
      • update grub (sudo update-grub), and after step #2 below, reboot!
    2. getting Ubuntu to stick to the baud rate for a specific serial port (the “generic” agetty’s --keep-baud does not seem to work!)
      • create a copy of the serial-getty@tty.service file specific to the serial port (which in my example, is ttyS4):
        • sudo cp /lib/systemd/system/serial-getty\@.service /lib/systemd/system/serial-getty\@ttyS4.service
      • sudo vi /lib/systemd/system/serial-getty\@ttyS4.service and edit the agetty command line to force the baud rate, e.g.:
        • changing:
          • ExecStart=-/sbin/agetty -o '-p -- \\u' --keep-baud 115200,57600,38400,9600 - $TERM
        • to:
          • ExecStart=-/sbin/agetty --8bits ttyS4 115200 vt102

2025/11/30 Update: Unfortunately, try as I might, I am simply unable to force the system to “stick” with the settings – sometime after start up, some component/service simply screws over the ttyS4 and I end up with corrupted garbage on screen. Things only get fixed after trying to change the baud rate (to 57600, 38400, 9600, etc.) and repeatedly pressing Enter and and CTRL-C – after some point of this (and yes, I confirmed it was due to user input since I once tried leaving it for an hour without it “getting fixed”), changing back to 115200 baud “miraculously” works.

      • link the new service file:
        • ln -s /lib/systemd/system/serial-getty@ttyS4.service /etc/systemd/system/getty.target.wants/
      • then reload systemctl and start the service:
        • systemctl daemon-reload
        • systemctl start serial-getty@ttyS4.service

 

QEMU and KVM

  • ensure virtualization settings have been enabled in BIOS (e.g. Intel’s VT-x or AMD’s AMD-V)
  • run the following:
    • apt install qemu-kvm libvirt-daemon-system libvirt-clients virt-manager
  • add specific users to the kvm group to enable them to control VMs without using sudo:
    • adduser <user> kvm
  • reboot

Disabling NIC Hardware Acceleration

  • sometimes, NIC hardware acceleration breaks software network processing, like software routers, and so need to have certain features disabled – YMMV with the specific feature names below:
    • check capabilities:
      • ethtool -k <device>
    • disable specific capabilities:
      • ethtool -K <device> segmentation off tx-esp-segmentation off tx-vlan-stag-hw-insert off tx-vlan-offload off rx-vlan-stag-hw-parse off rx-vlan-stag-filter off tx-gso-list off tx-gso-robust off tx-fcoe-segmentation off tx-sctp-segmentation off tx-checksumming off tx-checksum-ip-generic off scatter-gather off tx-scatter-gather off tcp-segmentation-offload off tx-tcp-segmentation off tx-tcp-ecn-segmentation off tx-tcp-mangleid-segmentation off tx-tcp6-segmentation off generic-segmentation-offload off generic-receive-offload off netns-local off
  • to “permanently” set this (or automatically set this at boot) check here.

 

Disabling/Changing libvirt‘s virbr0 NAT Interface

  • in case the libvirt-installed NAT virtual NIC interferes with anything, run the following commands to temporarily nuke the virtual NIC:
    • sudo virsh net-destroy default
  • to bring it back to life:
    • sudo virsh net-start default
  • in case you need to change some settings (e.g. IP address), simply:
    • copy the XML file and edit
      • cp /usr/share/libvirt/networks/default.xml /tmp/default.xml
    • set libvirt to use new definition
      • sudo virsh net-destroy default
      • sudo virsh net-undefine default # needed to avoid errors below
      • sudo virsh net-define /tmp/default.xml
    • restart libvirt‘s NAT interface
      • sudo virsh net-start default
    • clean up
      • rm /tmp/default.xml

 

Dual/Multi-Booting with Other OS

  • refer here for more instructions