Skip to content

Instantly share code, notes, and snippets.

@drew3000
Last active January 10, 2026 17:27
Show Gist options
  • Select an option

  • Save drew3000/a61ca945fbbb0e610ef2243808a09d3c to your computer and use it in GitHub Desktop.

Select an option

Save drew3000/a61ca945fbbb0e610ef2243808a09d3c to your computer and use it in GitHub Desktop.
Running an OnionShare “anonymous dropbox” instance on a Raspberry Pi (Ubuntu 22.04, Headless)

Running an OnionShare “anonymous dropbox” instance on a Raspberry Pi (Ubuntu 22.04, Headless)

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.

What's changed or where I deviated

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.

Assumptions

  • 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

Tor is managed by systemd and runs as an instance unit.

Verification:

systemctl status tor@default

Tor needs to be running before OnionShare starts.

External storage

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.

Installing OnionShare CLI

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

OnionShare receive mode

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.

systemd service

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!

Some operations

Restart OnionShare without rebooting the system:

sudo systemctl restart onionshare-receive.service

View logs:

journalctl -u onionshare-receive.service -f

Notes

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment