Im using SimpleX. I’m having trouble placing the icons and getting appimage to open directly. The “disposable template appvm” has also caused me some doubts and I don’t know if I’ve implemented it correctly. Could an experienced user check this?
#!/bin/bash
#######################################################################
# File Name : whonix-simplex-dvm.sh
# Description : This script creates a SimpleX qube and template based
# in Whonix DisposableVM template just with persistent
# identity across disposables. It downloads and verify
# the hash of the last SimpleX AppImage and uses sys-
# whonix NetVM. For ease of use the script aggregates
# shortcuts to application menu.
# Dependencies : curl
# Usage : • Transfer this script from appvm to dom0 with:
# [user@dom0 ~]$ qvm-run --pass-io appvm 'cat ~/whonix-simplex-dvm.sh' > ~/whonix-simplex-dvm.sh
# • Make the script executable with:
# [user@dom0 ~]$ chmod +x ~/whonix-simplex-dvm.sh
# • Run the script with:
# [user@dom0 ~]$ bash ~/whonix-simplex-dvm.sh
# • To update, run the script in whonix-simplex-template:
# bash ~/update-whonix-simplex-dvm.sh
# Author : Me and the bois
# License : Free of charge, no warranty
#######################################################################
# Safety check
set -eu
# Define Variables
APP_NAME="simplex-chat.AppImage"
APP_NAME_MENU="SimpleX Chat"
APP_DESKTOP="/usr/share/applications/simplex-chat.desktop"
BASE_TEMPLATE="whonix-workstation-17"
DISP_TEMPLATE_APPVM="whonix-simplex-template"
DISPVM_INSTANCE="whonix-simplex-dvm"
NET_VM="sys-whonix"
DOWNLOAD_URL="https://api.github.com/repos/simplex-chat/simplex-chat/releases/latest"
SIMPLEX_PERSISTENT_DIR="/rw/config/simplex-persistent"
SIMPLEX_CONFIG_DIR="$HOME/.config/simplex"
# Verify base template exists
if ! qvm-check "$BASE_TEMPLATE" >/dev/null 2>&1; then
echo -e "\nError: Base template $BASE_TEMPLATE not found!" >&2
exit 1
fi
# Update base template using qubesctl
echo -e "\nUpdating base template..."
sudo qubesctl --show-output --skip-dom0 --targets="$BASE_TEMPLATE" state.sls update.qubes-vm
# Create new AppVM based on Whonix template
echo -e "\nCreating $DISP_TEMPLATE_APPVM based on $BASE_TEMPLATE..."
qvm-create --class AppVM --property template="$BASE_TEMPLATE" --property label=gray "$DISP_TEMPLATE_APPVM"
echo -e "\nShutting down $DISP_TEMPLATE_APPVM to save changes..."
qvm-shutdown --wait "$DISP_TEMPLATE_APPVM"
# Configure it as DisposableVM template
echo -e "\nConfiguring $DISP_TEMPLATE_APPVM as DisposableVM template..."
qvm-prefs "$DISP_TEMPLATE_APPVM" template_for_dispvms True
qvm-prefs "$DISP_TEMPLATE_APPVM" netvm "$NET_VM"
qvm-features "$DISP_TEMPLATE_APPVM" appmenus-dispvm 1
# Install dependencies for new template
echo -e "\nInstalling dependencies..."
qvm-run -u root "$DISP_TEMPLATE_APPVM" 'apt update -y && apt install -y curl'
# Setup persistent storage
echo -e "\nConfiguring persistent storage..."
qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p '$SIMPLEX_PERSISTENT_DIR' && \
chown user:user '$SIMPLEX_PERSISTENT_DIR' && \
ln -s '$SIMPLEX_PERSISTENT_DIR' '$SIMPLEX_CONFIG_DIR'"
# Download function
download_appimage() {
echo -e "\nFetching release info from GitHub..."
# Get release JSON with --pass-io for reliable transfer
RELEASE_JSON=$(qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "curl -sL '$DOWNLOAD_URL'")
# Extract download URL (more robust parsing)
DOWNLOAD_URL=$(echo -e "\n$RELEASE_JSON" | grep -o '"browser_download_url": *"[^"]*"' | \
grep -i 'simplex-desktop.*x86_64.*\.AppImage' | \
cut -d '"' -f 4 | head -n 1)
# Fallback to any AppImage if specific one not found
if [[ -z "$DOWNLOAD_URL" ]]; then
DOWNLOAD_URL=$(echo -e "\n$RELEASE_JSON" | grep -o '"browser_download_url": *"[^"]*"' | \
grep -i '\.AppImage"' | cut -d '"' -f 4 | head -n 1)
fi
if [[ -z "$DOWNLOAD_URL" ]]; then
echo -e "\nError: Could not find AppImage download URL in:" >&2
echo -e "\n$RELEASE_JSON" >&2
exit 1
fi
echo -e "\nDownloading AppImage from: $DOWNLOAD_URL"
if ! qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "curl -L -o '$HOME/$APP_NAME' '$DOWNLOAD_URL'"; then
echo -e "\nDownload failed!" >&2
exit 1
fi
qvm-run "$DISP_TEMPLATE_APPVM" "chmod +x '$HOME/$APP_NAME'"
}
# Hash verification function
verify_hash() {
echo -e "\nExtracting expected hash from release info..."
# Get the release body text that contains the hashes
local release_body=$(echo "$RELEASE_JSON" | grep -zoP '"body":\s*".*?"' | cut -d'"' -f4 | tr -d '\0')
# Extract ONLY the AppImage hash from the release body
local expected_hash=$(echo "$release_body" | grep -o "SHA2-256(simplex-desktop-x86_64.AppImage)= [a-f0-9]*" | cut -d' ' -f2)
if [[ -z "$expected_hash" ]]; then
echo "Error: Could not extract AppImage hash from release info!" >&2
exit 1
fi
echo -e "\nCalculating actual hash of downloaded file..."
local actual_hash=$(qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "sha256sum '$HOME/$APP_NAME' | cut -d' ' -f1")
echo -e "\nVerifying hashes..."
echo "Expected: $expected_hash"
echo "Actual: $actual_hash"
if [[ "$expected_hash" != "$actual_hash" ]]; then
echo "ERROR: Hash verification failed!" >&2
exit 1
fi
echo "Hash verification passed"
}
# Download and verify
download_appimage
verify_hash
# Create desktop entry and menu entry
setup_desktop_entry() {
echo -e "\nSetting up desktop entry and app menu integration..."
# Define the desktop filename using Qubes naming convention
local QUBES_DESKTOP_FILENAME="org.qubes-os.vm._whonix_dsimplex_dtemplate.simplex-chat.desktop"
local DESKTOP_FILE_PATH="/usr/share/applications/$QUBES_DESKTOP_FILENAME"
# Create the desktop entry file with proper contents
qvm-run "$DISP_TEMPLATE_APPVM" "cat > '/tmp/$QUBES_DESKTOP_FILENAME'" <<"EOF"
[Desktop Entry]
Version=1.0
Type=Application
Name=SimpleX Chat
GenericName=Secure Messenger
Comment=Private and secure messaging with SimpleX
Terminal=false
TryExec=$HOME/$APP_NAME
Exec=$HOME/$APP_NAME
Icon=internet
Categories=Network;InstantMessaging;
StartupNotify=true
EOF
# Move it to the correct system location
qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p /usr/share/applications && \
mv '/tmp/$QUBES_DESKTOP_FILENAME' '$DESKTOP_FILE_PATH' && \
chmod 644 '$DESKTOP_FILE_PATH'"
# Create applications-merged directory in template
qvm-run "$DISP_TEMPLATE_APPVM" "mkdir -p /home/user/.config/menus/applications-merged"
# Create proper menu file in template
qvm-run "$DISP_TEMPLATE_APPVM" "cat > /home/user/.config/menus/applications-merged/user-qubes-vm-directory_whonix_dsimplex_dtemplate.menu" <<EOF
<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
<Name>Applications</Name>
<Menu>
<Name>qubes-vm-directory_whonix_dsimplex_dtemplate</Name>
<Directory>qubes-vm-directory_whonix_dsimplex_dtemplate.directory</Directory>
<Include>
<Filename>$QUBES_DESKTOP_FILENAME</Filename>
<Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.xfce4-terminal.desktop</Filename>
<Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.janondisttorbrowser.desktop</Filename>
<Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.systemcheck.desktop</Filename>
<Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.thunar.desktop</Filename>
<Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.anondist-torbrowser_update.desktop</Filename>
<Filename>org.qubes-os.qubes-vm-settings._whonix_dsimplex_dtemplate.desktop</Filename>
<Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.qubes-start.desktop</Filename>
</Include>
</Menu>
</Menu>
EOF
# Force menu refresh
echo -e "\nForce refreshing application menus..."
qvm-run "$DISP_TEMPLATE_APPVM" "/etc/qubes-rpc/qubes.GetAppmenus > /dev/null"
# Sync menus to dom0
echo -e "\nSyncing application menus to dom0..."
qvm-sync-appmenus "$DISP_TEMPLATE_APPVM"
echo -e "\nDesktop entry and app menu setup complete!"
}
# Call the function
setup_desktop_entry
# Create updater script in the template with proper variable handling
create_updater_script() {
echo -e "\nCreating updater in template...update only in the template!"
# Define the script content
local UPDATER_SCRIPT=$(cat <<EOF
#!/bin/bash
# Update only in the template!
# Variables
APP_NAME="simplex-chat.AppImage"
DOWNLOAD_URL="https://api.github.com/repos/simplex-chat/simplex-chat/releases/latest"
SIMPLEX_PERSISTENT_DIR="/rw/config/simplex-persistent"
SIMPLEX_CONFIG_DIR="\$HOME/.config/simplex"
$(declare -f download_appimage)
$(declare -f verify_hash)
# Ensure persistent directory link exists
if [[ ! -L "\$SIMPLEX_CONFIG_DIR" ]]; then
ln -s "\$SIMPLEX_PERSISTENT_DIR" "\$SIMPLEX_CONFIG_DIR"
fi
# Main execution
download_appimage
verify_hash
echo -e "\\nSimpleX Chat update completed successfully!"
EOF
)
# Transfer to template
echo "$UPDATER_SCRIPT" | qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "cat > \$HOME/update-simplex.sh"
# Make executable
qvm-run "$DISP_TEMPLATE_APPVM" "chmod +x \$HOME/update-simplex.sh"
echo "Updater script created in $DISP_TEMPLATE_APPVM"
}
create_updater_script
echo -e "\nShutting down $BASE_TEMPLATE..."
qvm-shutdown --wait "$BASE_TEMPLATE"
echo -e "\nSyncing DISP_TEMPLATE_APPVM application menus..."
qvm-sync-appmenus "$DISP_TEMPLATE_APPVM"
# Finalize
echo -e "\nShutting down $DISP_TEMPLATE_APPVM to create $DISPVM_INSTANCE..."
qvm-shutdown --wait "$DISP_TEMPLATE_APPVM"
echo -e "\nCreating disposable VM..."
qvm-create --property template="$DISP_TEMPLATE_APPVM" --class DispVM --property label=red "$DISPVM_INSTANCE"
qvm-features "$DISPVM_INSTANCE" appmenus-dispvm ''
echo -e "\nInstallation complete!"
echo -e "\nUse '$DISPVM_INSTANCE' from Qubes application menu."
I am also using SimpleX chat on qubeOS
my simplex qube is runing on a copy of whonix workstation as a template and sys-whonix as netvm
after that i just download simplex appimage and provide autorisation (like for every appimage) on it to make is working on my “simplex qube”
as you internet is working on Tor (sys-whonix) you have to set Simplex to use sockproxy for than you can go on settings, network and server and then use socks proxy
I hope this will help you !
In the context of Whonix (sys-whonix) everything is through Tor. You can enforce .onion-only mode (incognito mode via SOCKS). Its not clear to me if its important for Qubes setup, Simplex could use separate Tor circuits for connections from different profiles (transport isolation) only if SOCKS is enabled in the AppVM or Its just for Android?
“We have released support for using SOCKS proxy to access messaging servers via Tor, (…) It means that while your IP address was protected from the server, the whole Tor circuit could have been observed by some actors, and for some communication scenarios it is not desirable.
(…) all servers provided by SimpleX Chat now have dual addresses (one public and one .onion), and you can have your own servers available via two addresses as well (…) you should use the same format for the addresses of your servers.”
“Even when you create different chat profiles you are still connecting to your contacts via the same device. Transport isolation, by default, makes connections belonging to the same profile use different TCP sessions, so while the server sees the same IP address, it doesn’t see it as the same client connection. If you are connecting via Tor using SOCKS proxy (e.g. Orbot app on Android) not only the app will use different TCP sessions, it will also use separate Tor circuits for connections from different profiles, preventing the servers and network observers seeing this as traffic coming from the same device.”
regarding the script I am not the good one to help you.
I can just confirm than I had information than socks proxy is the best option regarding privacy and having onion address is always better.
It’s working well for me with the settings I previously explained