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 pressCtrl Xto 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-networkdinstead of Network Manager, an example of a netplan YAML file20-br0.yamlwith 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-serversystemctl enable ssh
- create public key in
~/.ssh/authorized_keys - configure SSHd
- ensure the “main”
/etc/ssh/sshd_confighas theInclude /etc/ssh/sshd_config.d/*.confdirective at the very first active/non-commented line - create
/etc/ssh/sshd_config.d/00-default.confwith 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
- ensure the “main”
Window Manager and GUI
- install a GUI/desktop for Ubuntu server
apt install lightdm
Yes, I know
lightdmruns as root, vs.gdm3which only runs the “greeter”/login manager but passes ownership to the current logged-in user, but to makex11vncwork (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
lightdmhas 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
x11vncwould runs aslightdm(by service configuration below), create a directory to store the password file then secure it:mkdir /etc/x11vnc.d touch /etc/x11vnc.d/vncpasswd
- as
- create the
/etc/systemd/system/x11vnc.serviceservice 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
systemdconfiguration:systemctl daemon-reload
- enable
x11vncservice:systemctl enable x11vnc
- disable Wayland
- edit
/etc/gdm3/custom.confand remove the comment mark (“#” character) from the line#WaylandEnable=false
- edit
- reboot
2025/09/06 Update: If you are wanting to copy-paste bidirectionally across VNC client and
x11vnchost 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.servicesudo systemctl mask systemd-networkd-wait-online.service
- also mark all unneeded interfaces as optional e.g. in
/etc/netplan/nn-whatever.yaml:

- 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.confmay get overwritten (or to be technically correct, regenerated) and the correct/recommended practice should be to either edit/etc/systemd/resolved.confor 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
ifupdownof ‘ye ol days, or even just advanced configuration like turning off offloading in/etc/network/interfaces,netplanjust made it unnecessarily more complicated- create
/etc/99-disable-network-offloading.shscript:#!/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 IFLIST="br0" 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
- create
-
- if using
NetworkManagerrenderer,networkd-dispatcheruses/usr/lib/networkd-dispatcher/*, butnetworkdrenderer uses/etc/networkd-dispatcher/*directories instead
- if using
- if, somehow none of the scripts are being triggered, an alternative is to create a custom
systemdservice:- create a
/etc/systemd/system/disable-network-offloading.servicefile:[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-reloadsystemctl start disable-network-offloading
- the only issue is that this does not work on “
vnetN” devices created when guest VMs are started
- create a
Repository Maintenance
- upgrading from old versions may have “remnant” repositories lurking around
- show the what is in the encoded
/etc/apt/trusted.gpgfile: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"
- show what is in
- show the what is in the encoded
- purging removed packages with “
residual-config” (e.g. configuration files): - 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 -asudo 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:
- 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/gruband 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
--portargument is usually replaced with--unit; I only document this parameter here in reference with another page – check the manual for more information
- note that the
- update grub (
sudo update-grub), and after step #2 below, reboot!
- make a backup before doing anything:
- getting Ubuntu to stick to the baud rate for a specific serial port (the “generic” agetty’s
--keep-bauddoes not seem to work!)- create a copy of the
serial-getty@tty.servicefile specific to the serial port (which in my example, isttyS4):sudo cp /lib/systemd/system/serial-getty\@.service /lib/systemd/system/serial-getty\@ttyS4.service
sudo vi /lib/systemd/system/serial-getty\@ttyS4.serviceand edit theagettycommand 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
- changing:
- create a copy of the
- getting GRUB to redirect everything (although tooling to do an install outright from console-only is out of scope here):
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
systemctland start the service:systemctl daemon-reloadsystemctl start serial-getty@ttyS4.service
- link the new service file:
-
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
- check capabilities:
- 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 defaultsudo virsh net-undefine default # needed to avoid errors belowsudo virsh net-define /tmp/default.xml
- restart
libvirt‘s NAT interfacesudo virsh net-start default
- clean up
rm /tmp/default.xml
- copy the XML file and edit
Dual/Multi-Booting with Other OS
- refer here for more instructions


