1
0
forked from finn/tinyboard
Files
tinyboard/README.md
2026-04-18 21:50:28 -07:00

9.1 KiB

TinyBoard

A hub-spoke architecture for secure file sharing and sync over SSH tunnels using autossh, rclone, and Syncthing.

Spokes are ARM devices (e.g. OrangePi, Raspberry Pi) running Armbian that establish reverse SSH tunnels to a central hub server. The hub mounts spoke filesystems via SFTP using rclone, making files accessible across all devices without exposing them to the internet. Syncthing runs on each spoke for bidirectional file sync.


Quickstart

Setting up a new Hub

On a fresh Debian/Ubuntu VPS or server:

apt install git
git clone https://gut.oily.dad/justin/tinyboard
cd tinyboard
./setup.sh   # option 4 (setup new hub)

Setting up a new Spoke

On a fresh Armbian device:

  1. Modify spoke/armbian.not_logged_in_yet accordingly, then drop it onto the SD card as /root/.not_logged_in_yet before first boot (WiFi credentials) — see Armbian Autoconfig docs
  2. Boot, SSH in as root
  3. Run:
apt install git
git clone https://gut.oily.dad/justin/tinyboard
cd tinyboard
./setup.sh   # option 0 (configure network)
./setup.sh   # option 1 (configure new spoke)

Onboarding a Spoke from the Hub

Once the spoke tunnel is up, run on the hub:

cd tinyboard
./setup.sh   # option 2 (onboard spoke)

Offboarding a Spoke from the Hub

cd tinyboard
./setup.sh   # option 3 (offboard spoke)

Configuring Syncthing

After the hub and at least one spoke are set up, run syncthing.sh on either device to manage Syncthing devices and folders interactively:

./syncthing.sh

The typical pairing flow:

  1. Run option 0 (Show This Device's ID) on the spoke — copy the ID
  2. Run option 3 (Add Device) on the hub — paste the spoke's ID
  3. Run option 0 (Show This Device's ID) on the hub — copy the ID
  4. Run option 3 (Add Device) on the spoke — paste the hub's ID
  5. On both devices, run option 6 (Add Folder) or option 8 (Share Folder with Device) to share folders between them

Architecture

  [ Spoke ]                        [ Hub ]
  OrangePi / RPi                   VPS / Server
  Armbian                          Any Linux

  autossh container  ──────────►  sshd (GatewayPorts)
  reverse tunnel                   port 111xx

  syncthing container ◄──────────► syncthing (hub or other spokes)
  file sync

                                   rclone SFTP mount
                                   ~/mnt/<spoke-name>/

Spokes initiate outbound SSH connections to the hub, creating reverse tunnels. The hub then uses rclone to mount each spoke's filesystem over SFTP through the tunnel. No inbound ports need to be open on the spoke.


Directory Structure

tinyboard/
├── setup.sh                  ← entry point for hub/spoke setup
├── syncthing.sh              ← manage Syncthing devices and folders
├── spoke/
│   ├── setup-network.sh      ← configure static IP before setup
│   ├── setup-spoke.sh        ← automated spoke setup
│   ├── compose.yaml          ← Docker Compose for autossh + Syncthing
│   ├── Dockerfile            ← autossh container
│   └── armbian.not_logged_in_yet ← Armbian first-boot WiFi config template
└── hub/
    ├── setup-hub.sh          ← automated hub setup
    ├── onboard-spoke.sh      ← add a new spoke to the hub
    └── offboard-spoke.sh     ← remove a spoke from the hub

Setup Scripts

setup.sh

Entry point. Presents a menu:

    1. Reconfigure network (static IP via netplan — SSH session will drop, reconnect)
    1. Set up this device as a new spoke
    1. Onboard a new spoke from the hub
    1. Offboard a spoke from the hub
    1. Set up this device as a new hub

syncthing.sh

Interactive Syncthing management. Can be run on the hub or any spoke. Presents a menu:

    1. Show This Device's ID
    1. Pending Devices
    1. List Devices
    1. Add Device
    1. Remove Device
    1. List Folders
    1. Add Folder
    1. Remove Folder
    1. Share Folder with Device
    1. Unshare Folder from Device

Requires Docker and a running Syncthing container. Auto-discovers the container and API key.

spoke/setup-network.sh

Run as root on a new spoke before setup.sh. Configures a static IP via netplan. Supports both WiFi and wired interfaces. Backs up the existing netplan config with a timestamp before writing. Automatically reverts if network connectivity is lost after applying.

spoke/setup-spoke.sh

Run as root on a new spoke. Handles:

  • Package installation (apt/dnf/yum/pacman)
  • Docker installation
  • SSH server setup
  • Hostname configuration (validated for safe characters)
  • SSH key generation and hub authorization
  • Tunnel port auto-detection on the hub (scans up to 100 ports)
  • Docker image build and container start
  • Optional password auth disable

hub/setup-hub.sh

Run as root on a new hub server. Handles:

  • Package installation (apt/dnf/yum/pacman)
  • rclone installation
  • Hub user creation
  • SSH server configuration (GatewayPorts, AllowTcpForwarding, ClientAliveInterval)
  • FUSE configuration
  • rclone config directory setup
  • Optional password auth disable

hub/onboard-spoke.sh

Run as the hub user after a spoke connects. Handles:

  • SSH key generation and deployment to spoke
  • rclone remote configuration (with trailing newline guard)
  • Optional union remote setup with configurable upstream access mode (none, :ro, :nc, :writeback)
  • Spoke registration in ~/.config/tinyboard/spokes

Union Remote

During onboarding, the user is optionally prompted to add the spoke to an rclone union remote for redundancy. If multiple spokes share the same files (via Syncthing), a union remote merges them into a single path so that if one spoke goes offline, the other can serve the files. Each upstream can be configured with an access mode:

  • none — full read/write (default)
  • :ro — read only
  • :nc — no create (read/write existing files, no new files)
  • :writeback — writeback cache

The union remote is automatically updated when a spoke is offboarded.

hub/offboard-spoke.sh

Run as the hub user to remove a spoke. Handles:

  • Unmounting the spoke filesystem
  • Crontab backup (timestamped to ~/.config/tinyboard/) then entry removal
  • Removing the rclone remote
  • Removing the spoke from any union remotes in rclone.conf
  • Optionally removing the hub SSH key
  • Removing from the spoke registry

Spoke Registry

The hub maintains a registry of connected spokes at ~/.config/tinyboard/spokes:

rocky  11113  /home/armbian/.ssh/armbian-rocky-202504  /home/armbian/mnt/rocky
gouda  11114  /home/armbian/.ssh/armbian-gouda-202504  /home/armbian/mnt/gouda

Each spoke gets its own mount point at ~/mnt/<spoke-name>/ and a dedicated rclone remote.


Backups

Scripts that modify critical configs create timestamped backups before writing:

  • Netplan: /root/.config/tinyboard/netplan-backups/<filename>.<datetime>
  • Crontab: ~/.config/tinyboard/crontab.<datetime>

Restore hints are printed to the terminal after each backup.


Security

  • All communication is over SSH tunnels — no spoke ports exposed to the internet
  • SSH keys used for all authentication
  • Scripts check and auto-fix unsafe file permissions (600/400)
  • Password authentication can be disabled during setup
  • Scripts refuse to disable password auth if no authorized keys are present (lockout prevention)
  • Netplan changes verified with a 30-second connectivity check before being made permanent
  • Spoke names validated against ^[a-zA-Z0-9._-]+$ to prevent injection into hostnames and container names
  • Syncthing admin UI bound to 127.0.0.1:8384 only (not exposed on the network)
  • Syncthing config and certs stored in a Docker-managed named volume, separate from the data directory

Sensitive Files

Before committing, ensure the following do not contain real credentials:

  • spoke/armbian.not_logged_in_yet — contains WiFi SSID, password, and user passwords
  • spoke/compose.yaml — may contain hub hostname after spoke setup runs

Troubleshooting

apt update fails with beta.armbian.com error

On some Armbian images, a beta apt repository is enabled by default and may cause apt update to fail. Comment it out:

grep -r "beta.armbian" /etc/apt/sources.list /etc/apt/sources.list.d/

Open the file that contains it (usually /etc/apt/sources.list.d/armbian.sources) and comment out or remove the line referencing beta.armbian.com, then run apt update again.

Tunnel is up but rclone mount fails

Check that FUSE is configured on the hub (user_allow_other in /etc/fuse.conf) and that the hub user is in the fuse group. You may need to log out and back in for group membership to take effect.

Syncthing container not found by syncthing.sh

The script looks for a running container with "syncthing" in its name. Run docker ps to confirm the container is running. If it stopped, run docker compose up -d from the spoke/ directory.


Requirements

Spoke: Armbian (or any Debian/Ubuntu/RHEL/Arch Linux), ARM device, Docker, autossh, git

Hub: Any Linux server (Debian/Ubuntu/RHEL/Arch), rclone, fuse, openssh-server, python3