Running Emacs with wsl2-xrdp
Why
I have been using Emacs in WSL2 using an X server running in Windows and that works fine as long as long as the computer does not go to sleep. When the computer goes to sleep, the X connection is cut and the emacs process crashes. I like to just have my emacs session available so I can continue where I was last time and I like my computer to go to sleep when I not use it because Global Warming.
- start emacs in WSL2 in GUI mode
- can be reconnected after sleep
- copy-paste works transparent
Plan
- use xrdp as remote desktop is built into windows
- configure xrdp to startup in WSL2
- run emacs in a remote desktop session
Installation
Install xrdp
$ yay -S xrdp xorgxrdp-git
We do not have systemd in WSL2 so I started the daemons manually with a small script */usr/local/bin/start-xrdp:
#!/bin/bash
sudo /usr/sbin/xrdp
sudo /usr/sbin/xrdp-sesman
We can now start it with start-xrdp from the bash command line or using wsl -u root /usr/local/bin/start-xrdp. If not running as root (or recently authenticated sudo access) it will ask for your Linux password to allow running as sudo.
Trying to connect lets me login but after a timeout is shows a dialog box telling me Xorg did not want to start. This is confirmed in the /var/log/xrdp-sesman.log file.
The root cause is that I cannot read properly because if I could, I
would have read to add allowed\users=anybody to the
/etc/X11/Xwrapper.config file to allow Xorg to be started by
regular users like me instead of only root.
Once that is there I get a nice black screen after login.
Note: Each time WSL2 restarts it gets a random ip address. So I created a small script to dig out the actual ip address out of the output of ip address :
#!/bin/bash
ip address show dev eth0 | grep "inet " | sed -e 's/.*inet \([^/]*\).*/\1/'
Which I gave the original name of /usr/local/bin/ip-address (do not
forget to chmod +x /usr/local/bin/ip-address
to make it executable) so
I can easily call it from powershell with wsl ip-address
.
Installing DBUS replacement
DBUS is the de-facto GNU/Linux desktop communication bus which glues all kind of GUI apps together. I do not know if it is directly used by Emacs or any of the extensions I use, however it reduces the amount of errors and warnings.
$ yay -S dbus-x11
allows xfce and other programs to feel happy and display the desktop with an emacs window. Now just maximizing the window and the goal is reached.
Automatic start of Emacs only
In order to just start emacs maximized in a single remote desktop window we only need to start it as the only program in the XSession. This of course also means there is no chrome on the X-Window or the ability to lauch other programs outside of Emacs. This is exactly how I like it.
#file:~/.xinitrc
emacs -mm
If you rather have a full desktop environment, see further.
Installing Xfce4 (Optional)
I'd rather have something more lightweight as window manager, but I have experience with Xfce4 in Arch and I also like something which just works.
I only intend to run emacs in the window however having something a bit more capable which works can help me debug the environment. (I have some font things to sort out too...)
$ sudo pacman -S xfce4
and then start it form ~/.xinitrc
emacs &
startxfce4
If you have skipped the DBUS setup above, this hangs while the ~/.xorgxrdp.log file is filling up with errors complaining about missing connection to dbus.
Using this from Windows
Starting from the command-line
We can start remote desktop session using
>_ mstsc /v:$(wsl ip-address) /h:2560 /w:1600
This works, however we get now a prompt to accept the certificate and we still need to login. We can make this smoother
Accepting the certificate
You can accept the certificate and let remote desktop add it to your certificate stores. This solves this interruption.
However, this still happens each time the ip address changes.
Automatic login
Start remote desktop GUI using the search or from the start menu.
Fill in the ip address returned by wsl ip-address
and your username.
Enable the flag to store your password. Login and save the configuration
as e.g. emacs.rdp.
We can now start emacs using
>_ cmdkey /generic:$(wsl ip-address) /user:<username> /pass:<password>
>_ mstsc /v:$(wsl ip-address)
We can assemble this is a small script wsl-emacs.ps1 somewhere on your path:
wsl -u root /usr/local/bin/start-xrdp
$address = $(wsl ip-address)
$userName = "pti"
$userPwd = "shht!Secret"
cmdkey /generic:$address /user:$userName /pass:$userPwd
mstsc /v:$address
Which allows us to start our wsl-emacs from powershell or as a startup application with a shortcut. It ensures the xrdp daemons are running (they are idempotent, so the script can be run multiple times), then the credentials are created so they can be picked up by remote desktop.
To add a shortcut to the start menu:
- Type Win-R and open
*%AppData%
\Microsoft
{=latex}\Windows
{=latex}\Start
{=latex} Menu\Programs*
{=latex} - create a new shortcut
- set as target *powershell.exe "&
'<path-of-script>
\wsl
{=latex}-emacs.ps1'
Note the weird "& on the command-line.
A note on security
Since you can run any command from the windows command-line as root, the current logged in person has full access to anything in the WSL Linux machines. As such there is not a big hole added by adding your linux password somewhere securely in your account files such as the startup script.
This does not mean you should not have secure passwords, as your linux box can expose its ports (not by default but just assume they are) and allow e.g. ssh access. Since I assume a lot of WSL2 hosts will be used fast and loose as a development box, there is a good chance that sooner or later a port is opened for reasons.
So I would not worry too much your linux box password is exposed in the emacs startup script as long as it is hard enough and not used anywhere else. If you'd like to get it from some secure vault on your PC or from your infrastructure, go for it.
tldr;
- use a strong password for your WSL box
- do not reuse an existing password
- secure your startup script so it is only readable by you.