Disposable Session Messenger Setup: "send messages, not metadata"

What is Session?

From the Session Lightpaper: “Session is a decentralised messenger that supports completely private, secure, and anonymous communications. Session provides one-on-one (direct message, or ‘DM’), group chats, and voice calls.”

What is session-desktop and how does the Session protocol differ from Signal protocol?

Oxen’s session-desktop is a fork of Signal’s signal-desktop, an E2EE messaging app available for Linux. The key contributions of Session are decentralization of E2EE and the addition of onion routing (lokinet) to protect metadata. The Session protocol does not implement PFS or deniability, but it does provide similar protections by way of anonymity. For example, use of a public key (SessionID) as an identifier in place of a personal phone number. session-desktop does not require a link to any other devices, whereas signal-desktop requires periodic linking to the Signal app on one’s mobile device to function.

For all of the details read:

How to install session-desktop in Qubes

The following adapts the official (Debian) Linux install instructions from Oxen. To maintain good security practice, please also read the Qubes guide on Verifying Signatures.

1. (optional) Create a new templateVM, <template>.
In the following we will assume <template> is a clone of debian-12-minimal.

    [user@dom0 ~]$ sudo qubesctl --skip-dom0 --targets=debian-12-minimal --show-output state.sls update.qubes-vm
    [user@dom0 ~]$ qvm-clone debian-12-minimal <template>

Open a root terminal in the (new) template.

[user@dom0 ~]$ qvm-run -u root <template> xterm

Run the following commands as root, which will install the curl program needed to download the Oxen signing key, a notification daemon for use with session-desktop, and the Qubes networking package. Add the Oxen GPG signing key and the Session repository. Finally, fetch all repositories (including the Session repo) and install Session:
Note: If using cacher, replace “https://” with “http://HTTPS///” in each command below.

    root@<template>:~# apt install curl xfce4-notifyd qubes-core-agent-networking glib-networking
    root@<template>:~# curl -so /etc/apt/trusted.gpg.d/oxen.gpg --proxy https://deb.oxen.io/pub.gpg
    root@<template>:~# echo "deb https://deb.oxen.io bookworm main" | tee /etc/apt/sources.list.d/oxen.list  
    root@<template>:~# apt update && apt install session-desktop

Optional: Installing color emojis will improve the messaging experience, as will installation of a file manager in the minimal template (substitute nautilus for thunar based on personal preference).

root@<template>:~# apt install fonts-noto-color-emoji thunar qubes-core-agent-thunar qubes-pdf-converter qubes-img-converter

Exit the root terminal and shutdown the templateVM.

[user@dom0 ~]$ qvm-shutdown <template>

2. Create a disposableVM template, <dvm-template>,
based on the <template> with session-desktop installed. Choose a color from the Qubes scheme for the label, which is red in this example. The final command will create an app menu for the disposableVM.

   [user@dom0 ~]$ qvm-create --template <template> --label red <dvm-template>
   [user@dom0 ~]$ qvm-prefs <dvm-template> template_for_dispvms True
   [user@dom0 ~]$ qvm-features <dvm-template> appmenus-dispvm 1

By default this setup will use sys-firewall as the netVM, but a sys-vpn as netVM will also work. To display the file manager and Session app menu entries for the disposableVM choose the following from the Qubes app menu: “Template (disp): <dvm-template>” → “<dvm-template>: Qube Settings” → “Applications” and select the appropriate apps.

3. Create a SessionID in a disposableVM and make it persistent

The following instructions demonstrate how to persist the SessionID while using disposableVMs. This setup will work well if you prefer ephemeral messaging. If you want messages to persist, then create an appVM based on <template> in place of the following setup.

Open a disposable terminal and execute session-desktop from the terminal, which will maintain access to the config files after closing the app.

     [user@dom0 ~]$ qvm-run --dispvm=<dvm-template> --service qubes.StartApp+debian-xterm

     [user@disp<#> ~]$ session-desktop
  • In the Session window select “Create Session ID”, then “Continue” and enter a personalized display name.
  • Select “Get Started”.
  • Show the recovery code to finish the setup process and store it in your vault (there are no passwords to remember).
  • While leaving the terminal open, close the Session chat window to free up the terminal.
  • Copy the following two, automatically generated, files to the disposableVM template, <dvm-template>.
        [user@disp<#> ~]$ qvm-copy .config/Session/config.json
        [user@disp<#> ~]$ qvm-copy .config/Session/sql/db.sqlite
  • In <dvm-template> create a new directory, /rw/config/Session, and move the above two files to this location, where they will persist.
  • Add the following lines to the rc.local script. This will ensure that each disposable Session instance spawned by <dvm-template> is configured with the above SessionID from the get go.
        [user@dom0 ~]$ qvm-run -u root <dvm-template> xterm

        [root@<dvm-template> ~]$ mkdir /rw/config/Session
        [root@<dvm-template> ~]$ mv /home/user/QubesIncoming/disp<#>/* /rw/config/Session/
        [root@<dvm-template> ~]$ echo -e "mkdir -p /home/user/.config/Session/sql/\ncp /rw/config/Session/config.json /home/user/.config/Session/\ncp /rw/config/Session/db.sqlite /home/user/.config/Session/sql/\nsudo chown -R user /home/user/.config/Session" >> /rw/config/rc.local
A quick check

[root@<dvm-template> ~]$ cat /rw/config/rc.local

should include the following lines:

 mkdir -p /home/user/.config/Session/sql/
 cp /rw/config/Session/config.json /home/user/.config/Session/
 cp /rw/config/Session/db.sqlite /home/user/.config/Session/sql/
 sudo chown -R user /home/user/.config/Session

4. Enjoy

With setup complete, we can now close our disposable template and run Session as a disposable app with an anonymous, but persistent, SessionID.

        [user@dom0 ~]$ qvm-shutdown <dvm-template>
        [user@dom0 ~]$ qvm-run --dispvm=<dvm-template> --service qubes.StartApp+session-desktop

Note: session-desktop will pull in approximately two weeks worth of existing messages after opening a new dispVM. You can read more of the details of how this works in the Session whitepaper.


  • Eliminate the recovery phrase popup with each respawn of the dispVMs
  • Persistence of contacts

*Thanks to the authors of the Qubes community guide for Signal, which provided a ready template for this guide.

Can I use Session in whonix-vm?

This question was posed on the Whonix forum soon after Session was released. The answer at that time was “most likely” yes. While I haven’t tried it, I have successfully used signal-desktop in a whonix vm. Since session-desktop has its own onion router, use of Session in a whonix vm would be along the lines of “other anonymizing networks over tor”.

Here are the relevant Whonix forum links:


Any progress on the recovery phrase popup with each respawn of the dispVMs ?
I used the qubes-copy-to-vm to copy my dispVM /home/user/.config/Session to get persistence of my contacts, but I still get the popup.

Thanks for the reminder. I’ll try playing around with it again and see if I can make some progress on the recovery phrase. Hasn’t been a priority since I respawn relatively infrequently, but just discovered today that I lost a contact after a recent shutdown so that’s some motivation…