Running EXWM Inside a Debian VM on Apple Silicon

Installing Debian on VirtualBox on an M-series Mac, fighting through a few gotchas, and ending up with Emacs as my window manager

I’ve been curious about EXWM (the Emacs X Window Manager) for a while. The idea of having your entire desktop live inside Emacs, where every app is just another buffer, is either insane or brilliant depending on who you ask. I wanted to find out which.

To keep things clean, I decided to run it inside a virtual machine rather than messing with my main setup. This is a writeup of how that went, which turned out to involve more small obstacles than expected, but nothing that couldn’t be fixed.

Getting the right ISO

First mistake I made: downloading the wrong Debian ISO. I’m on an Apple Silicon Mac (M-series chip) and grabbed the default download from the Debian site, which is the x86/amd64 version. VirtualBox immediately told me:

Cannot run the machine because its platform architecture x86
is not supported on ARM.

The fix is straightforward once you know: you need the arm64 ISO. You can find it at https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/. Grab the netinst image, it’s around 400MB and perfectly sufficient.

One note: VirtualBox on Apple Silicon is still somewhat experimental. If you hit issues, UTM is a popular free alternative on Mac that works very well and even has a one-click Debian download in its gallery. I stuck with VirtualBox since it worked well enough for my purposes.

The “please insert disk” problem

After installing Debian via the text installer (no graphical install), I went to run apt and got prompted to insert a disk. The installer had set up the DVD image as a package source in /etc/apt/sources.list.

On Debian 13 (Trixie), the configuration has actually moved to a new file: /etc/apt/sources.list.d/debian.sources. Edit that file and make sure it looks like this:

Types: deb
URIs: http://deb.debian.org/debian
Suites: trixie trixie-updates
Components: main

Types: deb
URIs: http://security.debian.org/debian-security
Suites: trixie-security
Components: main

Also open the old /etc/apt/sources.list and comment out the cdrom: line there too. After that, apt update works as expected.

sudo not found

The Debian installer doesn’t automatically give your regular user sudo access if you set a root password during installation. This is different from Ubuntu, which sets it up automatically. So my first instinct of running sudo apt install ... got a command not found.

Fix it by switching to root first with su -, then:

apt install sudo
usermod -aG sudo yourusername

Log out and back in for the group change to take effect.

Installing EXWM

I first tried installing KDE to get a graphical environment going, then planned to launch EXWM from within it. That turned out to be the wrong approach. When I tried to enable EXWM inside a running KDE session, it failed because another window manager was already running.

The right way is to set EXWM as the window manager from the start, so X starts Emacs directly rather than KDE. Here’s how:

Create ~/.xsession:

exec emacs

Make it executable:

chmod +x ~/.xsession

Then create a session file so the login manager can see it:

sudo nano /usr/share/xsessions/exwm.desktop
[Desktop Entry]
Name=EXWM
Comment=Emacs X Window Manager
Exec=/home/yourusername/.xsession
Type=Application

After rebooting, select EXWM from the session menu at login. Emacs starts up and becomes your window manager.

For EXWM itself, you need to install it via MELPA. Add this to ~/.emacs.d/init.el:

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(require 'exwm)
(exwm-enable)

Then inside Emacs run M-x package-refresh-contents followed by M-x package-install RET exwm RET.

Launching apps from within Emacs

Once EXWM is running, the default keybinding to launch an external app is s-& (Super+&). On a Mac, Super maps to the Command key, so that’s ⌘+Shift+7. A prompt appears in the minibuffer where you can type any shell command like firefox-esr.

If that keybinding doesn’t work reliably (macOS can intercept Command key combos), you can bind a simpler shortcut in your init.el:

(exwm-input-set-key (kbd "s-r")
  (lambda (command)
    (interactive (list (read-shell-command "$ ")))
    (start-process-shell-command command nil command)))

This maps ⌘+r as an app launcher.

Using apps inside EXWM

When a window like Firefox is open, EXWM has two modes:

  • char-mode: keystrokes go to the app (this is the default)
  • line-mode: Emacs controls the window

Switch between them with s-i (char-mode) and s-w (line-mode).

In char-mode, Firefox behaves exactly as it would normally. Ctrl+l opens the address bar, everything works as expected. In line-mode, the Firefox window becomes just another Emacs buffer, so you can use C-x 2 or C-x 3 to split the screen and have Firefox side by side with an Emacs editing buffer.

That’s the thing that made it click for me. Every app is a buffer. You can switch between Firefox, a terminal, and your code the same way you’d switch between any other Emacs buffers with C-x b.

Was it worth doing?

As a learning exercise, yes. Running through all these small problems (wrong architecture, package sources, sudo setup, window manager conflicts, keybinding quirks on Mac) each one taught me something about how Linux and X actually work under the hood.

EXWM itself is an interesting concept. The workflow of treating every window as a buffer takes some getting used to, but you can see why people who live in Emacs love it. You never have to leave. Your text editor, your terminal, your browser, all in one place, all navigable with the same muscle memory.

I kept KDE installed as a fallback, but honestly didn’t need it once EXWM was running. The whole setup is a bit more brittle than a standard desktop environment, but that’s kind of the point. It’s Emacs all the way down.