Deploying SecureDrop staging instance on Qubes

This assumes you have an up-to-date Qubes installation on a compatible laptop with at least 16GB RAM and 60GB free disk space.


Follow the the Qubes platform instructions in Setting Up the Development Environment to create an sd-dev Standalone VM. Once done, we’ll create three new Standalone (HVM) Qubes VMs for use with staging:

  • sd-staging-base, a base VM for cloning reusable staging VMs
  • sd-staging-app-base, a base VM for the SecureDrop Application Server
  • sd-staging-mon-base, a base VM for the SecureDrop Monitor Server

While the development VM, sd-dev, is based on Debian 10, the other VMs will be based on Ubuntu Xenial.


The staging server VM names were recently changed from sd-app and sd-mon to account for a name change in the SecureDrop Workstation project.

Download Ubuntu Xenial server ISO

On sd-dev, download the Ubuntu Xenial server ISO, along with corresponding checksum and signature files. See the hardware installation docs for detailed instructions. If you opt for the command line instructions, omit the torify prepended to the curl command.

Create the base VM

We’re going to build a single, minimally configured Ubuntu VM. Once it’s bootable, we’ll clone it for the application and monitoring VMs.

In dom0, do the following:

qvm-create sd-staging-base --class StandaloneVM --property virt_mode=hvm --label green
qvm-volume extend sd-staging-base:root 20g
qvm-prefs sd-staging-base memory 2000
qvm-prefs sd-staging-base maxmem 2000
qvm-prefs sd-staging-base kernel ''

The commands above will create a new StandaloneVM, expand the storage space and memory available to it, as well as disable the integrated kernel support. The SecureDrop install process will install a custom kernel.

Boot into installation media

In dom0:

qvm-start sd-staging-base --cdrom=sd-dev:/home/user/ubuntu-16.04.6-server-amd64.iso

You may need to edit the filepath above if you downloaded the ISO to a different location within the sd-dev VM. Choose Install Ubuntu. For the most part, the install process matches the hardware install flow, with a few exceptions:

  • Server IP address: use value returned by qvm-prefs sd-staging-base ip, with /24 netmask suffix
  • Gateway: use value returned by qvm-prefs sd-staging-base visible_gateway
  • For DNS, use Qubes’s DNS servers: and
  • Hostname: sd-staging-base
  • Domain name should be left blank

Make sure to configure LVM and use Virtual disk 1 (xvda 20.0GB Xen Virtual Block device) when asked for a target partition during installation. It should be the default option.

You’ll be prompted to add a “regular” user for the VM: this is the user you’ll be using later to SSH into the VM. We’re using a standardized name/password pair: sdadmin/securedrop.

Once installation is done, let the machine shut down and then restart it with

qvm-start sd-staging-base

in dom0. You should get a login prompt.

Initial VM configuration

Before cloning this machine, we’ll update software to reduce provisioning time on the staging VMs. In the new sd-staging-base VM’s console, do:

sudo apt update
sudo apt dist-upgrade -y

Before we continue, let’s allow your user to sudo without their password. Edit /etc/sudoers using visudo to make the sudo group line look like


Finally, update the machine’s Grub configuration to use a consistent Ethernet device name across kernel versions. Edit the file /etc/default/grub, changing the line:



GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"

When initial configuration is done, run qvm-shutdown sd-staging-base to shut it down.

Clone VMs

We’re going configure the VMs to use specific IP addresses, which will make various routing issues easier later. We’ll also tag the VMs for management by the sd-dev VM. Doing so will require Qubes RPC policy changes, documented below. Run the following in dom0:

qvm-clone sd-staging-base sd-staging-app-base
qvm-clone sd-staging-base sd-staging-mon-base
qvm-prefs sd-staging-app-base ip
qvm-prefs sd-staging-mon-base ip
qvm-tags sd-staging-app-base add created-by-sd-dev
qvm-tags sd-staging-mon-base add created-by-sd-dev

Now start both new VMs:

qvm-start sd-staging-app-base
qvm-start sd-staging-mon-base

On the consoles which eventually appear, you should be able to log in with sdadmin/securedrop.

Configure cloned VMs

We’ll need to fix each machine’s idea of its own IP. In the console for each machine, edit /etc/network/interfaces to update the address line with the machine’s IP.

Edit /etc/hosts on each host to include the hostname and IP for itself. Use sd-staging-app and sd-staging-mon, omitting the -base suffix, since the cloned VMs will not have the suffix.

Next, on each host edit /etc/hostname to reflect the machine’s name. Again, omit the -base suffix.

Halt each machine, then restart each from dom0. The prompt in each console should reflect the correct name of the VM. Confirm you have network access by running ping It should show no errors.

Inter-VM networking

We want to be able to SSH connections from sd-dev to these new standalone VMs. In order to do so, we have to adjust the firewall on sys-firewall.


See the official Qubes guide on configuring inter-VM networking for details.

Let’s get the IP address of sd-dev. On dom0:

qvm-prefs sd-dev ip

Get a shell on sys-firewall. Create or edit /rw/config/qubes-firewall-user-script, to include the following:


iptables -I FORWARD 2 -s "$sd_dev" -d "$sd_app" -j ACCEPT
iptables -I FORWARD 2 -s "$sd_dev" -d "$sd_mon" -j ACCEPT
iptables -I FORWARD 2 -s "$sd_app" -d "$sd_mon" -j ACCEPT
iptables -I FORWARD 2 -s "$sd_mon" -d "$sd_app" -j ACCEPT

Run those commands on sys-firewall with

sudo sh /rw/config/qubes-firewall-user-script

Now from sd-dev, you should be able to do

ssh sdadmin@

and log in with the password securedrop.

SSH using keys


You likely already have an SSH keypair configured for access to GitHub. If not, create one with ssh-keygen -b 4096 -t rsa. The configuration logic will use the key at ~/.ssh/id_rsa to connect to the VMs.

Later we’ll be using Ansible to provision the application VMs, so we should make sure we can SSH between those machines without needing to type a password. On sd-dev:

ssh-copy-id sdadmin@
ssh-copy-id sdadmin@

Confirm that you’re able to ssh as user sdadmin from sd-dev to sd-staging-mon-base and sd-staging-app-base without being prompted for a password.

SecureDrop Installation

We’re going to configure sd-dev to build the SecureDrop .deb files, then we’re going to build them, and provision sd-staging-app and sd-staging-mon. Follow the instructions in the developer documentation to set up the development environment.

Once finished, build the Debian packages for installation on the staging VMs.

make build-debs

The .deb files will be available in build/.

Managing Qubes RPC for Admin API capability

We’re going to be running Qubes management commands on sd-dev, which requires some additional software. Install it with

sudo apt install qubes-core-admin-client

You’ll need to grant the sd-dev VM the ability to create other VMs, by editing the Qubes RPC policies in dom0. Here is an example of a permissive policy, sufficient to grant sd-dev management capabilities over VMs it creates:

  sd-dev @tag:created-by-sd-dev allow,target=@adminvm

  sd-dev @adminvm allow,target=@adminvm
  sd-dev @tag:created-by-sd-dev allow,target=@adminvm


See the Qubes documentation for details on leveraging the Admin API.

Creating staging instance

After creating the StandaloneVMs as described above:

  • sd-dev
  • sd-staging-base
  • sd-staging-app-base
  • sd-staging-mon-base

And after building the SecureDrop .debs, we can finally provision the staging environment. In from the root of the SecureDrop project in sd-dev, run:

make staging

The make staging command invokes the qubes-staging Molecule scenario. You can also run constituent Molecule actions directly, rather than using the Makefile target:

molecule create -s qubes-staging
molecule converge -s qubes-staging
molecule test -s qubes-staging


Previous workarounds to mitigate the error "stderr": "app: Failed to clone appmenus, qvm-appmenus missing\ are no longer required. If you experience errors at this stage, ensure you have followed all the previous steps correctly.

That’s it. You should now have a running, configured SecureDrop staging instance running on your Qubes machine. For day-to-day operation, you should run sd-dev in order to make code changes, and use the Molecule commands above to provision staging VMs on-demand. To remove the staging instance, use the Molecule command:

molecule destroy -s qubes-staging

Accessing the Journalist Interface (Staging) in Whonix-based VMs


These instructions are only appropriate for a staging setup and should not be used to access a production instance of SecureDrop.

To access the Source and Journalist Interfaces (staging) in a Debian- or Fedora-based VM, follow the instructions here.

To use a Whonix-based VM, the following steps are required to configure access to the Journalist Interface (staging).

In sd-dev

You will have to copy the app-journalist.auth_private file (located in your sd-dev VM in ${SECUREDROP_HOME}/install_files/ansible_base and generated after a successful run of make staging) into your Whonix gateway VM. On standard Qubes installations this VM is called sys-whonix.

To do this, in an sd-dev terminal, run the command:

qvm-copy ${SECUREDROP_HOME})/install_files/ansible_base/app-journalist.auth_private

and select sys-whonix in the resulting permissions dialog.

In the Whonix Gateway

Open a terminal in sys-whonix and create a directory with appropriate ownership and permissions, then move your credential file there:

sudo mkdir -p /var/lib/tor/onion_auth
sudo mv ~/QubesIncoming/sd-dev/app-journalist.auth_private /var/lib/tor/onion_auth
sudo chown --recursive debian-tor:debian-tor /var/lib/tor/onion_auth

Next, edit the Tor configuration so it recognizes the directory containing your credentials:

sudo vi /usr/local/etc/torrc.d/50_user.conf

In this file, enter the following:

ClientOnionAuthDir /var/lib/tor/onion_auth

Save and close the file. Finally, reload Tor by clicking Qubes Application Menu > sys-whonix > Reload Tor

At this point, you should be able to access the Journalist Interface (staging) in a Whonix VM that uses sys-whonix as its gateway.

Note that you will have to replace the app-journalist.auth_private file and reload Tor on the Whonix gateway every time you rerun make staging.