Installing signal-cli

Step 1: Install Java on the Template

First, install Java 26 on the template that your signal-cli AppVM will be based on.

For Whonix Workstation or Debian:

export https_proxy=http://127.0.0.1:8082/
wget https://download.oracle.com/java/26/latest/jdk-26_linux-x64_bin.deb
sudo dpkg -i jdk-26_linux-x64_bin.deb

For Fedora:

export https_proxy=http://127.0.0.1:8082/
wget https://download.oracle.com/java/26/latest/jdk-26_linux-x64_bin.rpm
sudo rpm -i jdk-26_linux-x64_bin.rpm

Shutdown the template after the JDK 26 installation is complete.

Step 2: Create and Start the AppVM

Now create an AppVM based on this updated template and open a terminal inside it.

Step 3: Download signal-cli

Download the latest signal-cli by running the following command:

wget https://github.com/AsamK/signal-cli/releases/download/v0.14.2/signal-cli-0.14.2.tar.gz

Step 4: Extract signal-cli

Extract the downloaded archive with this command:

tar xvf signal-cli-0.14.2.tar.gz

Step 5: Update the PATH Environment Variable

Run the appropriate commands below to add signal-cli to your PATH.

For Whonix Workstation 18:

echo 'export PATH="$PATH:$HOME/signal-cli-0.14.2/bin/"' >> ~/.zshrc
source ~/.zshrc

For Fedora or Debian-based AppVMs:

echo 'export PATH="$PATH:$HOME/signal-cli-0.14.2/bin/"' >> ~/.bashrc
source ~/.bashrc

Step 6: Verify the Installation

Check the installed version with:

signal-cli --version


Registering a Signal Account on signal-cli Behind Tor Using a Virtual Number

To register a Signal account on signal-cli, solving a captcha challenge on a browser is required. Both the browser and the terminal must connect to the Signal server using the same IP address; otherwise the Signal server will mark the captcha as invalid.

Similarly, in the case of virtual numbers, sometimes (not always) the virtual number does not receive the verification code if your IP address (in the case of Tor, the IP address of the Exit node) is not from the same country as the virtual number. That’s why fixing the exit node to a static IP is required to register a Signal account on signal-cli using Tor.

Configuring sys-whonix

Fixing the exit node in sys-whonix requires root privileges and in Whonix 18 you can’t do it in normal user mode. So follow these steps:

  1. Shutdown sys-whonix.
  2. Go to sys-whonix VM settings → Advanced Tab.
  3. In Boot Mode set: PERSISTENT Mode – UNRESTRICTED Session.
  4. Click OK and start sys-whonix again.
  5. Open sys-whonix → Tor User Config.
  6. A text file will open. Write the following at the end of the text file:
    ExitNodes {gb}
    StrictNodes 1
    
    Where {gb} is for Great Britain (United Kingdom). This is just an example. Use the country of your virtual number instead. For example {nl} for Netherlands, {ca} for Canada, etc.
  7. Save and close the text file then Reload Tor (sys-whonix → Reload Tor).
  8. Open Onion Circuits (Tor Control Panel → Utilities Tab → Onion Circuits Button).
  9. Click on a connected circuit and verify the exit node is from the same country as you defined in the Tor User Config.
  10. Do something on the internet to create new circuits. Click on a “Succeeded” circuit and copy the IP address of the Exit node.
  11. Open Tor User Config again and replace {gb} or whatever the country code is with the IP address like this:
    ExitNodes 212.38.189.186
    StrictNodes 1
    
  12. Save and close the text file and reload Tor.

Now your Tor is configured to register a Signal account using signal-cli.

Caution: Don’t do any other internet activity behind Tor after this, just use it to register the Signal account. Otherwise all of your internet traffic will go through a single exit node.


Registering the Signal Account

  1. Open a browser in your signal-cli VM and browse the following link:
    https://signalcaptchas.org/registration/generate.html
  2. Solve the captcha challenge. After solving the captcha challenge it will show a link “Open Signal”.
  3. Right-click on the link and copy the link address.
  4. In the signal-cli terminal, give the following command to register and press Enter:
    signal-cli -a PHONENUMBER register --captcha "CAPTCHACODE"
    
    Where:
  5. Type your virtual number starting with + in place of PHONENUMBER.
  6. Paste the copied link address from “Open Signal” in place of CAPTCHACODE.
  7. Make sure to put " before and after the captcha code.

Caution: The captcha code is only valid for less than a minute, so do this process within this time.

  1. If all goes well then you will receive a verification code. Type the following command to verify:
    signal-cli -a PHONENUMBER verify CODE
    
    Type the verification code you received in place of CODE.
  2. Your account is now registered. You can confirm it by giving the following command:
    signal-cli listAccounts
    

Configuring the Signal-cli Account

If you have only one account in your signal-cli, you will not need to provide your phone number every time you give a command. Otherwise you will have to provide your phone number every time you give a command.

The first command you need to provide after registration is this:

signal-cli receive

If you have multiple accounts in your signal-cli then:

signal-cli -a PHONENUMBER receive

Other configuration commands:


Linking Signal Desktop App with signal-cli

Signal Desktop app shows a QR code to link it with the parent device. This code is displayed for 30 seconds. You need to extract the QR code from the QR image and paste it in the signal-cli command within these 30 seconds.

If your Signal Desktop is in a separate VM than your signal-cli (which is recommended) then the steps will increase. You will need to take a screenshot of the QR image. The screenshot file will be saved in dom0. You need to copy it to your signal-cli VM from dom0. Then you need to give the image to an online QR scanner to extract the code. Then you will type the command in signal-cli to link the desktop device and paste the QR code there.

All this must be done within 30 seconds or the QR code will change. So here’s the trick:

Don’t open Signal Desktop app yet.

  1. In signal-cli terminal type the following command but don’t press Enter:
    signal-cli addDevice --uri "
    
  2. In signal-cli browser open the following address or any QR scanning website you know:
    https://scanqr.org
  3. Open dom0 terminal and go to Pictures directory:
    cd ~/Pictures
    
  4. Type the following command but don’t press Enter:
    qvm-copy-to-vm signal-cli qr.png
    
    (Where signal-cli is the name of your signal-cli VM, while qr.png is the screenshot file name that you will generate shortly.)
  5. Now when everything is in place, open Signal Desktop App. It will show the QR image.
  6. Press Print Screen button and take the screenshot of only the QR image region and save the file with the name qr.png in the default location which is the Pictures directory in dom0.
  7. In dom0 terminal just press Enter (the command is already typed there).
  8. In the scanqr website opened in the browser of signal-cli VM, select the qr.png file from /home/user/QubesIncoming/dom0/.
  9. The website will show the extracted QR code. Copy the code.
  10. In signal-cli terminal paste the extracted QR code in the already typed command after " and after pasting the code type another " and press Enter. The command will look like this:
    signal-cli addDevice --uri "QRCODE"
    
    Where your extracted QR code will be in place of QRCODE.

Signal Desktop app will start linking with the signal-cli.


Automating signal-cli

You normally don’t need to use signal-cli, you just need to link it with your desktop client. But it is required that the receive command should run frequently in signal-cli because:

  1. If you didn’t run the receive command in signal-cli for 45 days your desktop client will unlink.
  2. Signal server keeps the encrypted messages if the parent device or any linked device didn’t receive the message. When you run the receive command, signal-cli fetches the messages from the server, just displays them using stdout but doesn’t save them to the disk. If a parent device or any linked device don’t receive messages the Signal server will retain messages up to 45 days and the messages will be deleted after that.

So for frequently running the receive command we’ll put the receive command in a script and make it autostart on login.

Signal-cli doesn’t save messages on local storage but it does store attachments, stories, avatars and stickers. Similarly when the parent device and all the linked devices receive the message the Signal server deletes the message but the server doesn’t delete the attachments, stories, avatars and stickers. It automatically deletes them after 45 days from the server.

So there is no need to download these attachments, stories, avatars and stickers. They will just use disk space and will be of no use. So we’ll skip them in the receive command.

Create a signal-receive.sh file and open it in editor:

nano signal-receive.sh

Paste the following in the editor:

On Whonix Workstation 18:

qterminal -e "zsh -ic 'signal-cli receive --ignore-attachments --ignore-stories --ignore-avatars --ignore-stickers; signal-cli receive --ignore-attachments --ignore-stories --ignore-avatars --ignore-stickers; exit;'"

On Debian or Fedora:

xfce4-terminal -e "bash -ic 'signal-cli receive --ignore-attachments --ignore-stories --ignore-avatars --ignore-stickers; signal-cli receive --ignore-attachments --ignore-stories --ignore-avatars --ignore-stickers; exit;'"

The command is ignoring all the attachments, stories, avatars and stickers. I provided the command two times because while using it behind Tor sometimes Tor takes time creating new circuits and the command times out in that period. So giving the command two times is for fail-safe. This command will open a new terminal, start receiving messages from server, display them on the terminal, do it two times then exit the terminal.

Make it executable:

chmod +x signal-receive.sh

Now to run this script on VM startup create an autostart folder in .config directory:

mkdir -p ~/.config/autostart

Create a desktop file to run the signal-receive.sh script on VM startup:

nano ~/.config/autostart/signal-receive.desktop

Paste the following:

[Desktop Entry]
Type=Application
Exec=/bin/bash -c "sleep 300 && /home/user/signal-receive.sh"
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name=Signal Receive
Comment=Runs signal-cli receive at startup

I’ve added a 300 seconds delay to run the script. Because we’ll set this VM to boot on startup. So the 300 is for safety so that the system, internet and Tor will connect properly and then this script will run. Otherwise if we run it immediately on startup the commands will probably time out.

Now in the signal-cli VM settings check the boot on startup checkbox.

It will be best if after running the receive script the signal-cli VM shuts down automatically because it will be of no use after that. For that check the “Shutdown when Idle for more than 15 minutes” checkbox in your signal-cli VM settings.

If this checkbox is disabled you need to install the package in your template first.

Open your template’s terminal and install it with the following command:

For Whonix & Debian:

sudo apt install qubes-app-shutdown-idle

For Fedora:

sudo dnf install qubes-app-shutdown-idle

Shutdown the template after installation.

Now check the “Shutdown when idle for more than 15 minutes” checkbox.

After these settings, on your system startup the signal-cli process will run in the following steps:

  1. Signal-cli VM will start on system startup.
  2. After 5 minutes (300 seconds) the receive script will start.
  3. The receive command will run, show the received messages in terminal and then the terminal will exit.
  4. The signal-cli VM will shutdown after 15 minutes of running the script.

With this setup the user will not need to do anything with the signal-cli. It will become like a service that automatically runs and stops.


Troubleshooting during Registration

During registration sometimes Signal doesn’t accept VOIP virtual numbers of some countries. It will show an authentication error. You need to change the country and use a virtual number of some other country, or use a virtual number that is not VOIP.

Sometimes the Tor exit node that you are using gets blocked. As a result signal-cli always displays “Captcha Invalid” or “Authentication Error”. Change the exit node.

If your initial try of registration failed and you changed the virtual number, the signal-cli will keep the failed number in the database. Then you will not be able to use signal-cli account commands (like receive or account configuration commands) without providing -a PHONENUMBER.

To check if you have failed phone numbers give the following command:

signal-cli listAccounts

This command will display your registered number and also the failed numbers.

To delete the failed numbers give the following command:

signal-cli -a PHONENUMBER deleteLocalAccountData --ignore-registered

Replace PHONENUMBER with your failed phone number in signal-cli.

The --ignore-registered option will ignore the registered number if you have provided the registered number accidentally instead of the failed number.