Inga 🏳🌈
c0d173ffee
|
2 years ago | |
---|---|---|
dotfiles/.config | 2 years ago | |
global | 2 years ago | |
LICENSE | 2 years ago | |
README.md | 2 years ago |
README.md
Table of Contents
- linux-on-desktop
- Preparing hardware
- Installing Alpine
- Postinstall
- Usable editor by default (not vi)
- Installing river
- Login manager
- Installing Waybar
- HiDPI
- Environment
- Keyring
- Sudo for GUI apps
- Launcher
- Screenshots
- Clipboard
- Emoji keyboard
- Notifications
- Other software
- Hardware
- Additional
- Development (containers)
- Unprivileged LXC with routing
- Networking (host)
- Containers support
- Creating container
- Networking (container)
- Creating an user inside container
- Alternatively: unprivileged LXC using LXD
- OpenSSH
- Webdev
- Docker
- TODO
linux-on-desktop
My journey to get Alpine + Wayland + River to work on ThinkPad T14 G3 AMD (21CF004PGE)
Preparing hardware
Disable secure boot and fn-lock in bios (so that F-keys work as F-keys by default and require Fn for their secondary multimedia functions).
Installing Alpine
Follow https://wiki.alpinelinux.org/wiki/Installation
Note that you will need to use Rufus; Ventoy does not work on this laptop (hangs after choosing the image).
Postinstall
In /etc/apk/repositories
, comment out 3.16, uncomment edge (main, community, testing),
since some of the packages we're going to install (river, element-desktop)
only exist in testing.
Then
doas apk update
doas apk upgrade
Usable editor by default (not vi)
doas apk add micro
echo "export EDITOR=micro" >>.profile
echo "permit setenv { EDITOR=\$EDITOR } nopass :wheel as root" | tee -a /etc/doas.d/doas.conf
Installing river
doas apk add eudev
doas setup-udev
doas apk add mesa-dri-gallium mesa-va-gallium
doas apk add river river-doc mandoc
doas apk add adwaita-icon-theme foot ttf-dejavu
doas rc-update add seatd
doas rc-service seatd start
doas addgroup YOURUSER audio
doas addgroup YOURUSER input
doas addgroup YOURUSER seat
doas addgroup YOURUSER video
doas addgroup YOURUSER wheel
install -Dm0755 /usr/share/doc/river/examples/init -t ~/.config/river
Also:
doas apk add xwayland
because the latest river in testing is built in a way that requires xwayland.
Try to run with
XDG_RUNTIME_DIR=/tmp river
You should see the blue screen of river. Try to open terminal with Win+Shift+Enter. Try to exit with Win+Shift+E.
Login manager
To enter username/password in GUI, get to river after that, and get back to logon screen after exiting river:
doas apk add elogind polkit-elogind
doas rc-update add elogind
doas rc-service elogind start
doas apk add greetd greetd-gtkgreet cage
doas addgroup greetd video
doas rc-update add greetd
change /etc/greetd/config.toml
command = "cage -s -- gtkgreet"
and create /etc/greetd/environments
with a single line river
and reboot.
I didn't find a way to make cage+gtkgreet handle HiDPI, the text is very tiny.
An alternative is agreety, but for some reason it seems that both greeter and standard linux login prompt run at the same time on the same terminal, making it impossible to actually login.
Installing Waybar
doas apk add waybar font-roboto
and add startup section at the end of river init file (~/.config/river/init
):
# startup
riverctl spawn "waybar"
For time to work,
doas apk add tzdata
For icons to work,
doas apk add font-roboto
(do not add font-awesome
, for some reason it looks awful, kerning is terrible, and the text is all-caps in waybar with it)
HiDPI
doas apk add kanshi
mkdir .config/kanshi
and create .config/kanshi/config
with the following:
profile {
output eDP-1 enable scale 2.5
}
(eDP-1
identifier was obtained by installing sway, running sway (by adding it to /etc/greetd/environments
,
and in terminal inside sway executing swaymsg -t get_outputs
).
HiDPI - cursors
And in order to have decently sized mouse cursors instead of the tiniest ones, add the following line to the top of .config/river/init
:
riverctl xcursor-theme Adwaita 24
This will only affect river itself, the cursor will stay tiny in waybar and firefox and maybe other applications. To solve this:
doas apk add gsettings-desktop-schemas
gsettings set org.gnome.desktop.interface cursor-theme 'Adwaita'
HiDPI - terminal
In terminal (not in terminal emulator in WM; you can always switch to the new terminal with Ctrl+Alt+F2)
doas apk add terminus font
setfont /usr/share/console-fonts/ter-132n.psf.gz
If it looks decent: change consolefont in /etc/conf.d/consolefont
to "ter-132n.psf.gz"
and doas rc-update add consolefont boot
Note that this will break your login manager for some reason
Environment
In order to not have to create wrapper scripts for all apps:
Create /usr/local/bin/inga-river
(and later chmod +x /usr/local/bin/inga-river
) with the following (found in google):
#!/bin/sh
export GDK_BACKEND=wayland,x11
export MOZ_ENABLE_WAYLAND=1
export CLUTTER_BACKEND=wayland
export QT_QPA_PLATFORM=wayland-egl
export ECORE_EVAS_ENGINE=wayland-egl
export ELM_ENGINE=wayland_egl
export SDL_VIDEODRIVER=wayland
export _JAVA_AWT_WM_NONREPARENTING=1
export NO_AT_BRIDGE=1
export BEMENU_BACKEND=wayland
river $@
and replace river
with inga-river
in /etc/greetd/environments
.
Keyring
doas apk add gnome-keyring
, and add relevant lines into /etc/pam.d/greetd
, it should look like this:
#%PAM-1.0
auth include system-local-login
auth optional pam-gnome-keyring.so
account include system-local-login
session include system-local-login
session optional pam_gnome_keyring.so auto_start
Add following lines to /usr/local/bin/inga-river
before the call to river:
eval $(gnome-keyring-daemon)
export SSH_AUTH_SOCK
Reboot, login, make sure with ps aux | grep key
that keyring daemon is running.
Sudo for GUI apps
doas apk add -s polkit-gnome
, and add riverctl spawn /usr/lib/polkit-gnome/polkit-gnome-authentication-agent
to your river config.
Launcher
doas apk add bemenu
, and then add this line into your river config:
riverctl map normal Super R spawn 'pidof bemenu-run || bemenu-run -i -n'
Screenshots
doas apk add wayshot
, then add this line to river config:
riverctl map normal None Print spawn 'wayshot --stdout | wl-copy'
Clipboard
Works by default, use Ctrl+Shift+C and Ctrl+Shift+V in foot
Emoji keyboard
doas apk add rofi-emoji rofi-emoji-wayland wtype font-noto-emoji
and add this line to your river config
riverctl map normal Super period spawn 'rofi -modi emoji -show emoji'
(For some reason it broke after reboot and only copies things to clipboard, even though wtype
continues to work without any problems)
Notifications
doas apk add dunst
dunst &
dunstify test
You should get a notification with the text "test".
Then add riverctl spawn "dunst"
to the startup section of your river config.
TODO: wired-notify instead of dunst (currently not packaged for alpine)
Other software
Firefox
doas apk add firefox
firefox
go to about:support
and make sure that Window Protocol is wayland, not xwayland.
(it should be wayland because MOZ_ENABLE_WAYLAND is set to 1 by inga-river)
For some reason, while sound in general works fine in firefox (after following the steps from Hardware section), in WebRTC pages there is crackling much louder than the actual voices, making it unusable for voice/video calls/meetings.
Chrome
doas apk add chromium
It should also be wayland by default, but you can check it by doas apk add xeyes && xeyes
.
In order for screen sharing to work, go to chrome://flags/#enable-webrtc-pipewire-capturer
and enable it.
Note though that every time you screenshare, there will be two promps from xdg-desktop-portal, one for picking a source, and another for actually sharing.
Yubikey
doas apk add yubikey-manager
doas addgroup YOUR_USER plugdev
(not sure if the two commands above are necessary)
Then:
doas rc-service pcscd start
doas rc-update add pcscd
Yubikey should work in Chrome
Archives
apk install ouch
to avoid having to remember tar
flags etc, and instead do ouch decompress archive.tar.gz
(for any archive format).
Git
doas apk install git
git config --global credential.helper --store
Telegram
doas apk install telegram-desktop
Element
doas apk install element-desktop
Hardware
Sleep
With default settings, laptop goes to sleep after some idle period. When it wakes up, the root fs is readonly, meaning that I have to restart the laptop.
Adding acpiphp.disable=1
and pcie_aspm=off
to grub config does not solve the issue.
Disabling S0ix in UEFI only made things worse: even though cat /sys/power/mem_sleep
reported that S3 (deep) is default,
after system goes to sleep it is impossible to wake it up, it does not react to key or power button presses.
What did solve the issue was:
- reenable S0ix in BIOS,
doas apk add linux-firmware-amdgpu
,- editing
GRUB_CMDLINE_LINUX_DEFAULT
in/etc/default/grub
to add the following options:acpiphp.disable=1 pcie_aspm=off acpi_osi='Windows 2020' iommu=soft
.
Now after waking up (after being suspended with doas pm-suspend
from pm-utils
package) root fs is still readwrite.
But sometimes network disappears after wakeup.
For suspend on lid close and unsuspend on open, follow https://wiki.alpinelinux.org/wiki/Suspend_on_LID_close :
doas mkdir -p /etc/acpi/LID
doas micro /etc/acpi/LID/00000080
should have the following content
#!/bin/sh
exec pm-suspend
and then
doas chmod +x /etc/acpi/LID/00000080
doas rc-service acpid restart
WiFi
At the moment Linux kernel does not support Qualcomm NFA725.
Otherwise, alpine wiki describes how to configure WiFi using iwd
.
Backlight
doas apk add light
doas micro /etc/udev/rules.d/backlight.rules
add the following lines into backlight.rules to make it possible for all users in video group (not just superusers) to control backlight:
ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="amdgpu_bl0", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness"
ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="amdgpu_bl0", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness"
and then
doas rc-service udev restart
Backlight control with Fn+F5/F6 should work now.
(amdgpu_bl0
is specific for this laptop; value for others can be obtained from /sys/class/backlight/
)
Trackpoint
Disregard this:
find /sys/devices/platform/i8042/ -name name | xargs grep -Fl TrackPoint
to find which serio corresponds to trackpoint, then
echo 70 | doas tee /sys/devices/platform/i8042/serio1/sensitivity
for reasonably low sensitivity (does not persist; for persistence TODO separate udev rule).
Instead of configuring sensitivity, it's probably better to configure pointer speed in river.
Find your trackpoint with riverctl list-inputs | grep -i trackpoint
,
it will look like 2:10:TPPS/2_Elan_TrackPoint
.
Then add the following to your river config:
riverctl input 2:10:TPPS/2_Elan_TrackPoint accel-profile adaptive
riverctl input 2:10:TPPS/2_Elan_TrackPoint pointer-accel -0.5
Sound
Based on https://wiki.alpinelinux.org/wiki/PipeWire
doas apk add dbus dbus-openrc
doas rc-service dbus start
doas apk add pipewire wireplumber rtkit alsa-utils pipewire-alsa
doas addgroup YOURUSER rtkit
doas addgroup root audio
alsamixer
In alsamixer, use F6 to find the target sound card (most likely 0 is HDMI and 1 is ordinary).
Remember its number, and in /usr/share/alsa/alsa.conf
,
replace defaults.ctl.card
and defaults.pcm.card
with the target number.
In /usr/local/bin/inga-river
, replace river $@
with dbus-run-session -- river $@
,
relogin (Ctrl+Shift+E).
Then
doas rc-service alsa start
doas rc-update add alsa
/usr/libexec/pipewire-launcher
Make sure that everything works (with wpctl status
, pw-cat -p YOURFILE.flac
or just opening YouTube in FF).
Then make pipewire start automatically: in river config, add another startup line:
riverctl spawn "/usr/libexec/pipewire-launcher"
Control microphone and volume with alsamixer
.
And change the handlers for XF86Audio (adding -repeat
and replacing the spawned command):
riverctl map -repeat $mode None XF86AudioRaiseVolume spawn 'amixer set "Master" 5%+'
riverctl map -repeat $mode None XF86AudioLowerVolume spawn 'amixer set "Master" 5%-'
riverctl map $mode None XF86AudioMute spawn 'amixer set "Master" toggle'
Note that the internal microphone does not work and is not detected by pipewire. Only external microphones work.
Mic in browser didn't work, but then it started to work at some point, without me seemingly changing anything.
Mic mute button
Create /etc/acpi/events/lenovo-mutemic
with the following content:
event=button/micmute MICMUTE 00000080 00000000 K
action=amixer --card 1 set 'Capture' toggle
where card number is the one obtained in previous section; and event could be determined by running acpi_listen
and pressing mic button.
Then, after doas rc-service acpid restart
, mic button should control internal mic capture in alsa and switch internal mic led on and off.
Webcam
Should work after following the steps for "Audio".
Can be tested in https://webrtc.github.io/test-pages
Additional
Screen sharing
doas apk add xdg-desktop-portal xdg-desktop-portal-wlr
Create /usr/local/bin/inga-xdg-desktop-portal-wlr
with the following:
#!/bin/sh
killall /usr/libexec/xdg-desktop-portal
killall /usr/libexec/xdg-desktop-portal-wlr
/usr/libexec/xdg-desktop-portal-wlr
and to your river config
riverctl spawn "inga-xdg-desktop-portal-wlr"
(for some reason xdg-desktop-portal
gets started automatically and after that newly started xdg-desktop-portal-wlr does not work;
we need to kill that xdg-desktop-portal first)
Prevent firefox sharing indicator from taking the entire tile
Add the following lines to river config (before the last exec
line):
riverctl float-filter-add title "Firefox — Sharing Indicator"
riverctl float-filter-add title 'Firefox — Sharing Indicator'
(TODO: check which kind of quotes works)
Development (containers)
Unprivileged LXC with routing
(based partially on https://linuxcontainers.org/lxc/getting-started and https://wiki.alpinelinux.org/wiki/LXC)
Networking (host)
(assuming that your internet-connected interface is eth0, and that you want to use 10.157.1.0/24 subnet for the container)
Add the following to /etc/network/interfaces
:
auto br0
iface br0 inet static
bridge-ports dummy0
bridge-stp 0
address 10.157.1.1
netmask 255.255.255.0
and do
doas apk add bridge
doas modprobe dummy
echo dummy | doas tee -a /etc/modules
echo 1 | doas tee -a /proc/sys/net/ipv4/ip_forward
doas apk add iptables
doas rc-update add iptables
doas iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE
doas iptables --append FORWARD --in-interface br0 -j ACCEPT
doas /etc/init.d/iptables save
Containers support
doas apk add lxc lxcfs lxc-download xz gnupg
echo "$(id -un):10000000:5000000" | doas tee -a /etc/subuid
echo "$(id -un):10000000:5000000 | doas tee -a /etc/subgid
echo "$(id -un) veth br0 10" | doas tee -a /etc/lxc/lxc-usernet
doas rc-update add cgroups lxc lxcfs dbus
Creating container
Create `~/.config/lxc/CONTAINERNAME.conf" with the following content:
lxc.net.0.type = veth
lxc.net.0.flags = up
lxc.net.0.link = br0
lxc.net.0.ipv4.address = 10.157.1.2/24 10.157.1.255
lxc.net.0.ipv4.gateway = 10.157.1.1
lxc.net.0.veth.pair = veth-if-0
# this is not a mistype, 500K should be enough for all your nesting needs, and 5M in /etc/subuid should be enough if you want to create any other containers
lxc.idmap = u 0 10000000 500000
lxc.idmap = g 0 10000000 500000
lxc.include = /usr/share/lxc/config/nesting.conf
lxc.apparmor.allow_nesting = 1
lxc.seccomp.allow_nesting = 1
lxc.mount.auto = proc sys cgroup:rw:force
Then:
lxc-create -n CONTAINERNAME -f .config/lxc/CONTAINERNAME.conf -t download
# pick OS (alpine/edge/amd64 in my case)
lxc-start -n CONTAINERNAME # make sure it does not produce any errors
lxc-attach --clear-env -n CONTAINERNAME
You'll get into a container root console.
(but still inside this container apk cgroups start
will produce errors
and mount everything in /sys/fs/cgroups except for openrc as nobody:nobody,
and won't mount openrc at all, and nested containers won't work.)
Networking (container)
In container root console, check if network is up with ifconfig
.
If there are no IPv4 address for eth0, you'll have to configure it manually,
by editing /etc/network/interfaces
.
The easiest way to do it is by
doas micro ~/.local/share/lxc/CONTAINERNAME/rootfs/etc/network/interfaces`
on the host.
In the end the file should look like
auto eth0
iface eth0 inet static
address 10.157.1.2
netmask 255.255.255.0
gateway 10.157.1.1
hostname $(hostname)
Then rc-service networking restart
, and check ifconfig
.
If everything is right, there should be an ipv4 address in ifconfig
,
and ping 10.157.1.1
inside container and ping 10.157.1.2
inside host should work.
ping 8.8.8.8
inside container should work too, thanks for routing.
Now, if ping google.com
does not work, configure DNS in container:
echo nameserver 8.8.8.8 >> /etc/resolv.conf
echo nameserver 8.8.4.4 >> /etc/resolv.conf
(or add them using micro on the host, as you did for interfaces)
Make sure ping 8.8.8.8
works.
APK should work too: apk add micro neofetch
Creating an user inside container
In container root shell:
adduser -g USERNAME USERNAME
adduser USERNAME wheel
echo "permit persist :wheel" >> /etc/doas.d/doas.conf
Now exit root shell (just with exit
), and try lxc-console -n CONTAINERNAME
.
You should be able to log in using the new username and password.
(To exit lxc console, use Ctrl+A, Q).
Alternatively: unprivileged LXC using LXD
Security notes
Note that with LXD, unprivileged containers run under root, which is not supposed to give them any extra privileges (source: https://discuss.linuxcontainers.org/t/privileged-and-unprivileged-containers/12060/2), but this implies that:
Containers can only be managed with LXD using root access.
Which means either doas
for every command (including connecting to the container shell),
or adding your user to the lxd
group which will have access to LXD daemon,
which will effectively give your user passwordless sudo (since access to LXD daemon can trivially be used to gain root privileges),
so that any process running under your user can trivially gain root privileges on the host
(which is for some reason not considered by LXD maintainers to be a problem).
DO NOT add your user to the lxd
group, and DO NOT uncomment --group lxd
in /etc/conf.d/lxd
Instead the secure way of doing things would probably be to only use lxd as a root, and connect to the container using ssh.
Containers support
As simple as
apk add lxd lxd-client lxcfs dbus
rc-update add lxc
rc-update add lxd
rc-update add lxcfs
rc-update add dbus
doas reboot
Networking with routing should work automatically.
Creating container
doas lxc launch images:alpine/edge -c security.nesting=true -c security.privileged=false -c security.idmap.isolated=true -c security.idmap.size=6553600 test-alpine-container
doas lxc exec test-alpine-container -- /bin/ash
Networking should work inside of container.
OpenSSH
With password-based auth (not recommended): in container (from root, lxc-attach
/lxc exec
)
apk add openssh
rc-update add sshd
rc-service sshd start
Check IP of container with ifconfig
, and then on host,
doas apk add openssh-client
ssh CONTAINER_IP
With keys-based auth:
ssh-keygen -t ed25519
ssh-copy-id CONTAINER_IP
(Also make sure that echo $SSH_AUTH_SOCK
is not empty; it shouldn't be if gnome-keyring-daemon is configured properly.)
Webdev
Accessing dev sites running inside container
In container: doas apk add squid
, and edit /etc/squid/squid/conf
accordingly
(most likely you'll only need to change local network definition to match the subnet shared between the host and the container).
Then:
doas rc-update add squid
doas rc-service squid start
(Note that squid requires devfs service to be running).
In host, create new FF profile (about:profiles
) for that purpose, and configure it to use squid proxy running inside of container.
VS Code Remote
Note that VS Code (and all related products) has a protection intended to prevent OSS variants from connecting to proprietary versions of VS code. However, apparently, it is implemented in such a way that it prevents even different OSS products from connecting to each other. Only "Code OSS" is packaged for Alpine; and only VSCodium has server-side builds, so you'll need to patch Code OSS to make it pretend to be VSCodium.
Steps to get it running, assuming that you already have keyring and key-based SSH auth (with non-RSA key) configured:
In container (one of the sources: https://github.com/microsoft/vscode-remote-release/issues/6347):
doas apk add gcompat libstdc++ curl bash git procps
and enable AllowTcpForwarding
and PermitTunnel
in /etc/ssh/sshd_config
.
On host (where you intend to run IDE client):
doas apk add code-oss
Using e.g. Firefox, download vscodium-reh-linux-x64-...
for a relevant build (with a version matching to code-oss)
from https://github.com/VSCodium/vscodium/releases
Unpack it: cd Downloads && ouch decompress vscodium-reh-... --dir vscodium
Edit /usr/lib/code-oss/resources/app/package.json
to make it mimic VSCodium (looking at package.json
from unpacked VSCodium).
In my experience, changing name
, removing distro
, and adding release
fields was enough.
(Make sure that version
fields are identical between installed Code OSS and downloaded VSCodium package.)
Edit /usr/lib/code-oss/resources/app/product.json
to make it mimic VSCodium (looking at product.json
from unpacked VSCodium).
In my experience, changing nameShort
, nameLong
, applicationName
, dataFolderName
, win32MutexName
,
licenseUrl
, serverApplicationName
, serverDataFolderName
, win32DirName
, win32NameVersion
, win32RegValueName
,
linuxIconName
, reportIssueUrl
and date
fields,
and adding updateUrl
, quality
and commit
fields was enough.
But most of these fields are probably irrelevant and can be left as is.
Run code-oss
, add "Open Remote - SSH" extension by jeanp413, exit.
Add "enable-proposed-api": ["jeanp413.open-remote-ssh"]
at the root level of ~/.vscode-oss/argv.json
.
Run code-oss
again, you'll get remote button under the marketplace button.
Go there, add your host, right-click it, connect.
Connection should be successful, and you should see "connected to remote" on Code OSS main screen.
"Open folder" should take you to the remote directory structure, allowing you to open projects hosted in container.
All code-related extensions will also work in remote context, isolated from the parent system and unable to affect it,
no matter what malicious npm packages get installed into container.
Docker
For container terminal apps to be usable:
doas apk add ncurses-terminfo
(inside LXC)
TODO once nesting in LXC works (reference: https://discuss.linuxcontainers.org/t/lxc-on-alpine-host-sys-fs-cgroup-is-not-mounted-into-unprivileged-alpine-guest/15026/1)
(inside LXD)
As simple as
doas apk add docker
doas rc-update docker start
doas docker run hello-world
in the guest.
For networked docker containers, doas lxc config edit CONTAINERNAME
,
add linux.kernel_modules: br_netfilter
to the config:
section,
and restart container (doas lxc restart CONTAINERNAME
).
TODO
- Fix internal mic
- Docker in containers ran by unprivileged users
- Make river usable
- Make waybar usable (+waybar fonts)
- nushell + starship instead of ash
- Mail client
- Fix call audio in firefox
- WiFi