This gist describes a current method I'm using to run OnionShare in persistent “receive” mode on a Raspberry Pi using Ubuntu 22.04 LTS, with external storage, only accessed over SSH. I initially set one up a few years ago following Micah Lee’s original post: https://micahflee.com/onionshare-anonymous-dropbox-raspberry-pi/
I'm still using the same hardware and following much of the same approach. A few implementation details have changed with later Ubuntu, Python, Tor, and OnionShare releases, and I've diverged to add external file storage and persistence that should be a little easier on the user. Maybe other people will find it helpful. These are just notes.
I'm using Ubuntu. Ubuntu 22.04 uses Python 3.10, which breaks older pip --user OnionShare installs created under Ubuntu 20.04 (or Raspberry Pi OS). OnionShare CLI is no longer consistently packaged as a standalone CLI in Ubuntu repositories. And Tor now runs as a systemd multi-instance service. For easier persistence, long-running processes should be managed by systemd rather than screen or SSH sessions. I'm also using an external USB storage disk, which should be mounted deterministically via UUID. Basically, a Raspberry Pi shuts off for any number of reasons, and I wanted a setup that rebooted everything seamlessly, with no faff.
- Headless Raspberry Pi
- Ubuntu 22.04 LTS
- SSH access only
- Tor installed from Ubuntu repositories
- External USB storage for received files
No desktop environment is required (I'm connecting from a Mac, and editing in nano. This may or may not influence some decisions below).
Tor is managed by systemd and runs as an instance unit.
Verification:
systemctl status tor@default
Tor needs to be running before OnionShare starts.
Received files are written to a USB drive, mounted at /media/USB. The filesystem type is exFAT (others can be used).
Example /etc/fstab entry:
UUID=C467-4E83 /media/USB exfat defaults,uid=1000,gid=1000,nofail 0 0
Using the UUID avoids device renumbering issues. nofail ensures the system still boots if the drive is absent.
On Ubuntu 22.04, the most reliable way to install OnionShare CLI is in a dedicated Python virtual environment (venv). This will avoid breakage during OS upgrades and keeps the runtime self-contained.
sudo apt update
sudo apt install -y python3-venv python3-pip
sudo mkdir -p /opt/onionshare-cli
sudo chown ubuntu:ubuntu /opt/onionshare-cli
python3 -m venv /opt/onionshare-cli/venv
/opt/onionshare-cli/venv/bin/pip install --upgrade pip
/opt/onionshare-cli/venv/bin/pip install onionshare-cli
The executable will live at:
/opt/onionshare-cli/venv/bin/onionshare-cli
There are a few operators you may or may not want to use in Onionshare, check them all out. This is an example of one set of them. Mess around until you're happy with the output and keep it for later re-use.
/opt/onionshare-cli/venv/bin/onionshare-cli --receive --persistent /home/ubuntu/anon-dropbox.session --public --title [YOUR TITLE HERE] --data-dir /media/USB
The onion address is generated once and reused. It may not be printed immediately on restart and will take some time to appear on low-powered hardware. See that it's working, save the onion url and then close it (crtl-c) to work on the persistence.
OnionShare in this setup is managed as a systemd service, not via screen or tmux. systemd provides deterministic startup, crash recovery, and log management, screen and tmux don't. This is where the magic/voodoo happens, and I'm still fidgeting with it to get the timings, sequence, etc., right.
We need to make a service file: /etc/systemd/system/onionshare-receive.service
(Note below where you plug in your desired onionshare configs)
[Unit]
Description=OnionShare Receive Service
After=network-online.target tor@default.service time-sync.target
Wants=network-online.target time-sync.target
Requires=tor@default.service
RequiresMountsFor=/media/USB
[Service]
Type=simple
User=ubuntu
Group=ubuntu
ExecStart=/opt/onionshare-cli/venv/bin/onionshare-cli --connect-timeout 600 --receive --persistent /home/ubuntu/anon-dropbox.session --public --title andrewfordlyons.net --data-dir /media/USB
Restart=always
RestartSec=20
WorkingDirectory=/
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable onionshare-receive.service
sudo systemctl start onionshare-receive.service
Fin!
Restart OnionShare without rebooting the system:
sudo systemctl restart onionshare-receive.service
View logs:
journalctl -u onionshare-receive.service -f
You can find my Onionshare instance currently (unless it's down) at:
http://entyms3fdn4fyl6lizog6hoztvaqkvv2njmcovslkm55xhahs7nnmiqd.onion
You'll see some custom elements which I haven't documented here, they aren't dangerous, but also not especially best practice. I want to come up with a more reliable way to achieve them without changing the default image files directly, and possibly CSS customisations. But that's all just cosmetics. Watch this space.