Chrome OS devices/Crostini
Crostini is Google's umbrella term for making Linux application support easy to use and integrating well with Chrome OS.
This article describes how to install Arch Linux on a Chromebook in a container (via Crostini), without needing to enable developer mode, allowing apps to run alongside other Chrome/Android apps.
- Officially supported, do not need to enable developer mode - leaves Chrome OS secure, no need to flash a BIOS etc.
- Better battery life - battery life of Chrome with the functionality of Linux.
- Audio (in/out) & OpenGL are supported, but USB devices support in only partially supported and development is still in progress.
Enabling Linux support
Look for Linux under Settings and enable it. This installs a Debian Linux container that we will then replace with an Arch Linux container.
- Settings > Linux > Enable
Crostini is still rolling out to Chromebooks. If you do not see an option to enable Linux, you may need to switch to the beta or developer channel, if it has not rolled out to the stable channel for your laptop yet. This can be done via Settings > About Chrome OS > Channel > Dev/Beta.
Replacing the default Debian Linux container with Arch Linux
The below instructions based on https://www.reddit.com/r/Crostini/wiki/howto/run-arch-linux
Optional: Delete the Debian container
lxc delete penguinshould not leave the space unusable. See 
If you have no use for Debian anymore, you can save some storage space by destroying and recreating the Termina VM (this will let you skip renaming / deleting existing container later). Beware this will also delete any other containers you may have under Termina.
vmc destroy termina vmc start termina
Create the container
Open a new crosh terminal in Chrome (Ctrl + Alt + T). Create an Arch Linux container in Termina using VMC:
vmc container termina arch https://us.images.linuxcontainers.org archlinux/current
The following error will be shown after completion:
"Error: routine at frontends/vmc.rs:403 `container_setup_user(vm_name,user_id_hash,container_name,username)` failed: timeout while waiting for signal"
This is expected behaviour, proceed with following steps.
Open a shell in Termina and check if the Arch Linux container is present (it may a few minutes to show on the list):
vsh termina lxc list
If the container is not started, start it:
lxc start arch
Launch a bash shell in the container:
lxc exec arch -- bash
Set up the user
The container creates a default user on install based on the email used to sign in to Chrome OS. The username can be seen with the following command:
grep 1000:1000 /etc/passwd|cut -d':' -f1
Optionally you can rename user/group, by default named by your GMail id:
# pkill -9 -u old-username # groupmod -n new-username old-username # usermod -d /home/new-username -l new-username -m -c new-username old-username
A password needs setting for the user:
# passwd username
You may additionally want to install sudo and add the user to the wheel group. Use after installation:
Uncomment the following line to allow the wheel group to use sudo:
# %wheel ALL=(ALL) ALL
Add your user to the wheel group:
# usermod -aG wheel username
Leave the container:
Set up the container for use in Chrome OS
Login to the container using regular user account you just configured:
lxc console arch
Verify networking in the container. The command
$ ip -4 a show dev eth0
should return a non-empty output with the container's assigned IP address. If it is not empty, you can proceed, otherwise you are facing the issue described in #No network in container - follow the instructions listed there to address the issue.
Install the Crostini container tools, Wayland for GUI application support and XWayland for X11 application support:
Install the AUR package. Additionally install and to be able to use GUI tools.
Enable and start the services (for Wayland, X11, Wayland (low density) and X11 (low density) accordingly):
$ systemctl --user enable --now sommelier@0 sommelier-x@0 sommelier@1 sommelier-x@1
Make sure these services are running successfully by running:
$ systemctl --user status sommelier@0 $ systemctl --user status sommelier@1 $ systemctl --user status sommelier-x@0 $ systemctl --user status sommelier-x@1
Now, when apps are installed in Arch Linux, they will automatically appear in the Chrome OS launcher. Exit from the container shell back to the Termina shell by pressing <ctrl>+a q.
Replace the default Debian container with Arch Linux
The default Debian container is named penguin. Renaming the "arch" container created above to it will cause Chrome OS to launch Linux apps from the arch container. Stop the Arch Linux container:
lxc stop --force arch
Stop the Debian container and rename it to "debian" (this step can be skipped if you have already removed the Debian container):
lxc stop --force penguin lxc rename penguin debian
Rename the Arch container to "penguin" and start it:
lxc rename arch penguin lxc start penguin
Restart the Linux subsystem to apply the changes. After restart, the following commands in the Arch container's shell:
systemctl --failed systemctl --user --failed
should both report 0 loaded units listed, and
ip -4 a show dev eth0
should report the IP address assigned for container.
Arch container fails to start after update to Chrome OS 81
Most of custom containers stopped working with Chrome OS 81 update. The root cause is LXC version update, as a result container fails to start with following error:
lxc penguin 20200411193357.312 WARN initutils - initutils.c:setproctitle:324 - Invalid argument - Failed to set cmdline lxc penguin 20200411193357.395 WARN conf - conf.c:lxc_map_ids:2919 - newuidmap is lacking necessary privileges lxc penguin 20200411193357.395 WARN conf - conf.c:lxc_map_ids:2925 - newgidmap is lacking necessary privileges lxc penguin 20200411193357.400 WARN conf - conf.c:lxc_map_ids:2919 - newuidmap is lacking necessary privileges lxc penguin 20200411193357.400 WARN conf - conf.c:lxc_map_ids:2925 - newgidmap is lacking necessary privileges lxc penguin 20200411193357.477 ERROR conf - conf.c:run_buffer:335 - Script exited with status 32 lxc penguin 20200411193357.477 ERROR conf - conf.c:lxc_setup:3589 - Failed to run mount hooks lxc penguin 20200411193357.477 ERROR start - start.c:do_start:1263 - Failed to setup container "penguin" lxc penguin 20200411193357.478 ERROR sync - sync.c:__sync_wait:62 - An error occurred in another process (expected sequence number 5) lxc penguin 20200411193357.478 WARN network - network.c:lxc_delete_network_priv:2561 - Failed to rename interface with index 17 from "eth0" to its initial name "veth421fa9d1" lxc penguin 20200411193357.478 ERROR lxccontainer - lxccontainer.c:wait_on_daemonized_start:842 - Received container state "ABORTING" instead of "RUNNING" lxc penguin 20200411193357.479 ERROR start - start.c:__lxc_start:1939 - Failed to spawn container "penguin" lxc penguin 20200411193357.701 WARN conf - conf.c:lxc_map_ids:2919 - newuidmap is lacking necessary privileges lxc penguin 20200411193357.701 WARN conf - conf.c:lxc_map_ids:2925 - newgidmap is lacking necessary privileges lxc 20200411193357.706 WARN commands - commands.c:lxc_cmd_rsp_recv:132 - Connection reset by peer - Failed to receive response for command "get_state" lxc 20200411193357.707 WARN commands - commands.c:lxc_cmd_rsp_recv:132 - Connection reset by peer - Failed to receive response for command "get_state"
After some troubleshooting I made my container work by removing just two empty dirs from the container image. Navigate to crosh and execute following:
vmc start termina vsh termina lxc file delete penguin/var/lib/lxc lxc file delete penguin/var/lib/lxcfs
Restart Linux subsystem and container started should start normally.
No network in container
As was reported by multiple sources, systemd-networkd and systemd-resolved services in systemd-244.1 are not working properly for unprivileged LXC containers, which ends up in missing network connectivity inside the Crostini container. Proposed solution is completely disable systemd-networkd/systemd-resolved and perform network configuration by dhclient service instead. First, install , then, as the root user, run:
dhcpcd eth0 systemctl disable systemd-networkd systemctl disable systemd-resolved unlink /etc/resolv.conf touch /etc/resolv.conf systemctl enable dhclient@eth0 systemctl start dhclient@eth0
App not opening in chrome OS (infinite spinner)
I found that launching a console (lxc console penguin) session prevents apps from launching in Chrome OS. Launching results in an infinite spinner. In that case I have to stop and start the container to get the Chrome OS launcher working
lxc stop penguin lxc start penguin
Instead of using an lxc console session, I use a regular Linux terminal GUI launched from Chrome OS that prevents this issue.
Crostini support audio playback starting Chrome OS 74. WithAUR installed both ALSA and PulseAudio playback should work after PulseAudio configuration. Audio input is supported starting Chrome OS 79.
Edit and create the following configs in the container:
default-fragments = 4 default-fragment-size-msec = 20
.fail ### Automatically restore the volume of streams and devices load-module module-device-restore load-module module-stream-restore load-module module-card-restore ### Automatically augment property information from .desktop files ### stored in /usr/share/application load-module module-augment-properties ### Should be after module-*-restore but before module-*-detect load-module module-switch-on-port-available ### Disable udev event detection since we're in container ### Automatically load driver modules depending on the hardware available # .ifexists module-udev-detect.so # load-module module-udev-detect # .else ### Use the static hardware detection module (for systems that lack udev support) # load-module module-detect # .endif ### Load several protocols load-module module-native-protocol-unix ### Automatically restore the default sink/source when changed by the user ### during runtime ### NOTE: This should be loaded as early as possible so that subsequent modules ### that look up the default sink/source get the right value load-module module-default-device-restore ### Automatically move streams to the default sink if the sink they are ### connected to dies, similar for sources load-module module-rescue-streams ### Make sure we always have a sink around, even if it is a null sink. load-module module-always-sink ### Automatically suspend sinks/sources that become idle for too long load-module module-suspend-on-idle ### Enable positioned event sounds load-module module-position-event-sounds ### Load alsa devices manually since containers won't get udev events. ### Set tsched=0 to interrupt-based scheduling. # For output/playback load-module module-alsa-sink device=hw:0,0 tsched=0 # For input/record load-module module-alsa-source device=hw:0,0 tsched=0 .nofail
mpv can play videos using software rendering without any addition configuration, however this is CPU consuming and laggy experience for modern video codecs like H265. For hardware accelerated playback GPU acceleration is required. Take into account, that GPU acceleration for Crostini is based on Virgil 3D GPU project, so no real GPU device pass-though is performed and hardware-specific APIs like VA-API or VPDAU are not available. However OpenGL acceleration can be used, i.e. this is example of mpv.conf config for [mpv] media player which enabled accelerated video and audio playback on Google Pixelbook starting Chrome OS 77:
On Google Pixelbook GPU acceleration works with Arch out-of-the-box starting Chrome OS 77. Also no flags need to be enabled on recent released of Chrome OS:
$ glxinfo -B
name of display: :0 display: :0 screen: 0 direct rendering: Yes Extended renderer info (GLX_MESA_query_renderer): Vendor: Red Hat (0x1af4) Device: virgl (0x1010) Version: 19.1.4 --> Accelerated: yes <-- Video memory: 0MB Unified memory: no Preferred profile: core (0x1) Max core profile version: 4.3 Max compat profile version: 3.1 Max GLES1 profile version: 1.1 Max GLES profile version: 3.2 OpenGL vendor string: Red Hat OpenGL renderer string: virgl OpenGL core profile version string: 4.3 (Core Profile) Mesa 19.1.4 OpenGL core profile shading language version string: 4.30 OpenGL core profile context flags: (none) OpenGL core profile profile mask: core profile OpenGL version string: 3.1 Mesa 19.1.4 OpenGL shading language version string: 1.40 OpenGL context flags: (none) OpenGL ES profile version string: OpenGL ES 3.2 Mesa 19.1.4 OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
Unlock the keyring when starting the container
If you have problems with programs that use Systemd/User#Writing user units) that will run the keyring daemon when the container starts.-daemon, you need to write a user systemd daemon (see
Create the following two files
[Unit] Description=Keyring [Service] ExecStart=/usr/local/bin/export-keys KillUserProcesses=no [Install] WantedBy=default.target
cat ~/.passwordby creating the appropriate file in your home folder.
#!/bin/bash killall gnome-keyring-daemon echo random-password | gnome-keyring-daemon --components=secrets,ssh,pkcs11 --unlock --foreground
Give the file launch rights
# chmod a+x /usr/local/bin/export-keys
systemctl --user enable --now gnome-keyring && echo -n 'login' > ~/.local/share/keyrings/default
Fullscreen video, games and mouse capture
Currently Crostini has limited support for mouse capture starting with Chrome OS 79. You must enable the flag chrome://flags/#exo-pointer-lock to get mouse capture. The closed issue relating to mouse capture is https://bugs.chromium.org/p/chromium/issues/detail?id=927521