How I configured my Debian linux desktop computer.
Latest update: March 28, 2021
Install the xorg
package and run startx
. With the right drivers, it should just work without any configuration.
Since I have an Nvidia GPU, I installed the nvidia-driver
package to get the closed-source drivers with hardware acceleration. To install this package, you must first add the non-free
component to your APT sources.list
:
sudo apt edit-sources
deb http://deb.debian.org/debian/ buster main contrib non-free deb-src http://deb.debian.org/debian/ buster main contrib non-free deb http://security.debian.org/debian-security buster/updates main contrib non-free deb-src http://security.debian.org/debian-security buster/updates main contrib non-free
I like my CAPSLOCK key to act like ESCAPE:
echo "setxkbmap -option caps:escape" >> ~/.xsessionrc
source ~/.xsessionrc
In xterm, typing ALT inserted a character instead of the META modifier:
echo "xterm*metaSendsEscape: true" >> ~/.Xresources
xrdb -l ~/.Xresources
My mouse cursor was too big:
echo "Xcursor.size: 16" >> ~/.Xresources
xrdb -l ~/.Xresources
For high DPI with 1.5 scaling:
~/.Xresources
Xft.dpi: 144 Xcursor.size: 32 URxvt.font: xft:Ubuntu Mono:pixelsize=24,style=regular
~/.profile
export GDK_SCALE=1.5 export QT_SCALE_FACTOR=1.5
Find the Wi-Fi adapter chipset:
lspci | grep -i wifi
04:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8822BE 802.11a/b/g/n/ac WiFi adapter
Install the appropriate firmware package for this chipset (see wiki.debian.org/WiFi for a list), in my case firmware-realtek
, and reboot.
Find the Wi-Fi network interface name:
ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s31f6: >NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether b0:6e:bf:5f:cf:e1 brd ff:ff:ff:ff:ff:ff 3: wlp4s0: >BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000 link/ether f8:28:19:a2:5f:77 brd ff:ff:ff:ff:ff:ff
iwd
(iwd.wiki.kernel.org) is a daemon for managing Wi-Fi connections that aims to be more efficient and easier to use than its precursor wpa_supplicant
. Install the iwd
package, which creates the iwd
systemd
service which launches the daemon on boot. Use the iwctl
command to interact with the daemon:
iwctl
[iwd]# device list Devices -------------------------------------------------------------------------------- Name Address Powered Adapter Mode -------------------------------------------------------------------------------- wlp4s0 f8:28:19:a2:5f:77 on phy0 station [iwd]# station wlp4s0 scan [iwd]# station wlp4s0 get-networks Available networks -------------------------------------------------------------------------------- Network name Security Signal -------------------------------------------------------------------------------- mynetwork psk **** anothernetwork open *** [iwd]# station wlp4s0 connect mynetwork Type the network passphrase for mynetwork psk. Passphrase: **********
iwd
stores network passwords in plain text at /var/lib/iwd/mynetwork.psk
, and will automatically connect on next boot.
Since version 0.19, iwd
can also perform network configuration like managing DHCP leases, but the version in Debian 10 is 0.14 so this isn't yet available without getting a newer version some other way. For now it's simple enough to get a DHCP lease manually:
sudo dhclient wlp4s0
I haven't yet figured out the best way to get a DHCP lease automatically on boot.
Install the firmware for the Realtek Bluetooth controller on my motherboard:
sudo apt install firmware-realtek
reboot
Install the bluetooth package:
sudo apt install bluetooth
Disable the "SIM Access Profile" plugin, because it doesn't work:
sudo vim /etc/systemd/system/bluetooth.target.wants/bluetooth.service
ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap
sudo systemctl daemon-reload
sudo service bluetooth reload
Use bluetoothctrl
to scan for devices:
bluetoothctl
power on scan on pair MAC connect MAC
If there are connection errors for an audio device, A2DP support may need to be installed:
sudo apt install pulseaudio-module-bluetooth
killall pulseaudio
To list paired devices:
bluetoothctl devices
To connect/disconnect to a particular device:
bluetoothctl connect MAC
bluetoothctl disconnect MAC
I use the i3 tiling window manager (i3wm.org) provided by the i3
package.
If i3 is the only window manager you install, Debian will automatically launch it with X, because it will already be configured as the x-window-manager
alternative (see the Debian Wiki). Otherwise, you can run sudo update-alternatives --config x-window-manager
to pick it manually.
Unlike some other window managers (like GNOME and KDE), i3 does not include a compositor (Wikipedia). Among other things, a compositor can prevent tearing when scrolling text or watching videos in programs like Chrome.
Install the picom
package (https://github.com/yshui/picom) for a standalone compositor that works well with i3. If you run picom
directly it will immediately start compositing, and if you CTRL-C it will stop, so it's easy to experiment with the flags. The only flag I seemed to need was --backend=glx
. The --vsync
flag didn't seem to make any difference, maybe because Nvidia G-Sync was already providing that functionality.
picom --backend=glx
Then configure i3 to launch it automatically:
echo "exec picom --backend=glx" >> ~/.config/i3/config
My monitor supports refresh rates up to 165Hz, but X was only running at 60Hz by default. The difference above 60Hz is subtle, but I can definitely tell the difference when I move the mouse cursor.
Use xrandr
to see the current resolution and refresh rate. The *
symbol to the right of the refresh rate indicates the current mode, and the +
symbol indicates the "preferred" (default) mode:
xrandr
Screen 0: minimum 8 x 8, current 2560 x 1440, maximum 32767 x 3276 DP-1 disconnected (normal left inverted right x axis y axis) HDMI-0 disconnected (normal left inverted right x axis y axis) DP-2 connected 2560x1440+0+0 (normal left inverted right x axis y axis) 598mm x 336mm 2560x1440 59.95*+ 165.00 144.00 120.00 99.95 84.98 23.97 1024x768 60.00 800x600 60.32 640x480 59.94 DP-3 disconnected (normal left inverted right x axis y axis) DP-4 disconnected (normal left inverted right x axis y axis) DP-5 disconnected (normal left inverted right x axis y axis) USB-C-0 disconnected (normal left inverted right x axis y axis)
You can change the mode live with xrandr
, and to make it persistent you can put that command in your ~/.xprofile
file (which runs every time X starts).
xrandr --output DP-2 -r 165 --mode 2560x1440
xrandr
DP-2 connected 2560x1440+0+0 (normal left inverted right x axis y axis) 598mm x 336mm 2560x1440 59.95 + 165.00* 144.00 120.00 99.95 84.98 23.97 1024x768 60.00 800x600 60.32 640x480 59.94
echo "xrandr --output DP-2 -r 165 --mode 2560x1440" >> ~/.xprofile
Find the mouse pointer device name and numeric id:
xinput --list
⎡ Virtual core pointer id=2 [master pointer (3)] ⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)] ⎜ ↳ Logitech G603 id=9 [slave pointer (2)] ⎜ ↳ Logitech USB Receiver id=10 [slave pointer (2)] ⎜ ↳ Logitech USB Receiver Consumer Control id=12 [slave pointer (2)] ⎣ Virtual core keyboard id=3 [master keyboard (2)] ↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)] ↳ Power Button id=6 [slave keyboard (3)] ...
List the available properties. You can use the device name or numeric id:
xinput --list-props 9
Device 'Logitech G603': Device Enabled (155): 1 Coordinate Transformation Matrix (157): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000 libinput Natural Scrolling Enabled (289): 0 libinput Natural Scrolling Enabled Default (290): 0 libinput Scroll Methods Available (291): 0, 0, 1 libinput Scroll Method Enabled (292): 0, 0, 0 libinput Scroll Method Enabled Default (293): 0, 0, 0 libinput Button Scrolling Button (294): 2 libinput Button Scrolling Button Default (295): 2 libinput Button Scrolling Button Lock Enabled (296): 0 libinput Button Scrolling Button Lock Enabled Default (297): 0 libinput Middle Emulation Enabled (298): 0 libinput Middle Emulation Enabled Default (299): 0 libinput Accel Speed (300): 0.000000 libinput Accel Speed Default (301): 0.000000 libinput Accel Profiles Available (302): 1, 1 libinput Accel Profile Enabled (303): 0, 1 libinput Accel Profile Enabled Default (304): 1, 0 libinput Left Handed Enabled (305): 0 libinput Left Handed Enabled Default (306): 0 libinput Send Events Modes Available (274): 1, 0 libinput Send Events Mode Enabled (275): 0, 0 libinput Send Events Mode Enabled Default (276): 0, 0 Device Node (277): "/dev/input/event4" Device Product ID (278): 1133, 16492 libinput Drag Lock Buttons (307): <no items> libinput Horizontal Scroll Enabled (308): 1
The Accel Profile Enabled
property controls cursor acceleration.
The value is two bits, where the left bit enables "adaptive" mode (with
acceleration), and the right bit enables "flat" mode (no acceleration).
Turn on acceleration:
xinput --set-prop 9 303 1 0
Turn off acceleration:
xinput --set-prop 9 303 0 1
The Accel Speed
property controls cursor speed, a number
between -1 and 1, defaulting to 0.
Lower cursor speed:
xinput --set-prop 9 300 -0.7
To make this setting persistent, add these commands to
~/.xsessionrc
.
All of the systemctl
power-related commands worked with no configuration: poweroff
, reboot
, hibernate
, and suspend
.
However, it can be annoying that these commands require typing your password. (Note for a server you do want to require a password).
One option is to create a sudoers
file that allows you to run those specific commands without typing your password (though you will still use sudo
). Always edit sudoers files using visudo
(provided by the synonymous package), because it helps prevent you from entirely breaking your sudo access by checking that your syntax is correct before writing the file.
sudo visudo /etc/sudoers.d/power
yourusername ALL = \ NOPASSWD:/usr/bin/systemctl poweroff,\ NOPASSWD:/usr/bin/systemctl reboot,\ NOPASSWD:/usr/bin/systemctl hibernate,\ NOPASSWD:/usr/bin/systemctl suspend
You probably don't want to put much else in your sudoers file, since it could allow a malicious program running as your user to execute any of these commands without your permission or knowledge, plus typing your password makes it harder to accidentally to do bad things yourself. The best explanation of the sudoers file syntax I've found is toroid.org/sudoers-syntax.
Google maintains an official APT repository for Chrome. Chrome is not in the official Debian APT repositories (though Chromium is).
Download the .deb
package from google.com/chrome. This will both install Chrome, and configure your APT sources and GPG keys to receive updates when you apt update/upgrade.
Microsoft maintains an official APT repository for VSCode. VSCode is not in the official Debian APT repositories.
Download the.deb
package from code.visualstudio.com/download. This will both install VSCode, and configure your APT sources and GPG keys to receive updates when you apt update/upgrade.
The version of Node.js provided by the nodejs
package in the official Debian APT repositories is a Long Term Support (LTS) version. This is usually fine, but I like to have the latest version because I sometimes experiment with new features. See nodejs.org/en/about/releases for the release schedule.
I get the latest version of Node.js by downloading the .tar.xz
binary release archive from nodejs.org/dist/latest, unpacking it to $HOME/node
, and adding $HOME/node/bin
to my $PATH
.
To check if there's a new version to download, I use this script:
~/bin/check-node-version.sh
#!/usr/bin/env bash set -e NODE_INSTALLED=$(node --version) NODE_LATEST=$(curl --silent --show-error --fail \ https://nodejs.org/dist/latest/SHASUMS256.txt \ | grep linux-x64.tar.xz | grep -Eo "v[0-9]+\.[0-9]+\.[0-9]+") if [[ "$NODE_INSTALLED" == "$NODE_LATEST" ]] then echo "Node.js is current ($NODE_INSTALLED)" else echo "Node.js is outdated ($NODE_INSTALLED installed, $NODE_LATEST latest)"; exit 1 fi
Note that a company called NodeSource maintains Debian APT repositories for the latest versions, as mentioned at nodejs.org/en/download/package-manager. There's also a program called NVM (github.com/nvm-sh/nvm) which automatically downloads Node.js versions for you. Since neither of these options are managed by the Node.js maintainers, though, I prefer to manage installation myself.
Render emojis in Chrome and other applications by installing an emoji font like Noto Color Emoji:
apt install fonts-noto
I use this script to check for any available updates to system APT packages, Node.js, and globally installed npm packages.
~/bin/check-updates.sh
#!/usr/bin/env bash sudo apt update | tee /dev/stderr | grep -q "All packages are up to date" APT_CODE=$? apt list --upgradable echo check-node-version.sh NODE_CODE=$? echo npm --global outdated NPM_CODE=$? echo RED="\u001b[31m" GREEN="\u001b[32m" RESET="\u001b[0m" EXITCODE=0 if [[ $APT_CODE == 0 ]] then echo -e "[${GREEN}OK${RESET}] APT" else echo -e "[${RED}!!${RESET}] APT (sudo apt upgrade)"; EXITCODE=1 fi if [[ $NODE_CODE == 0 ]] then echo -e "[${GREEN}OK${RESET}] Node.js" else echo -e "[${RED}!!${RESET}] Node.js (https://nodejs.org/dist/latest/)"; EXITCODE=1 fi if [[ $NPM_CODE == 0 ]] then echo -e "[${GREEN}OK${RESET}] NPM" else echo -e "[${RED}!!${RESET}] NPM (npm --global update)"; EXITCODE=1 fi exit $EXITCODE