By popular demand from this post, here’s the write-up for my version of that travel server.

The travel server is shown with the, currently, bare 5V UPS board to its right. One day I hope to have a 3D printed case for both of those, but they’re currently separate as my 3D modeling skills are basically non-existent. The power cable is wrapped in aluminum foil and then wrapped in electrical tape due to EMI from the wifi adapter causing random glitches. A ferrite bead would probably solve that more elegantly, but I didn’t have any on hand so made due with what I have.

Hardware

  • Banana Pi M4 Zero
    • 1.5 GHz Quad Core ARM64
    • 4 GB RAM
    • 32 GB eMMC
    • 1 TB Samsung PRO Plus SD Card (bought before prices went nuts)
  • Li-2B UPS Board + 2x 3,000 mAh 18650 batteries
  • USB-C to USB-A 90 degree angle adapter
  • USB Nano Wifi adapter

Note: Unlike the Pi Zero, these have two USB ports. One is configured in host mode and the other in peripheral mode.

Features and Capabilities

  • Multiple wifi clients can use this for network access
  • Multiple “WAN” options
  • Multiple VPN connections (OpenVPN, Wireguard, IPSEC) e.g.
    • Privacy VPN for general internet traffic
    • Wireguard to connect back to home network
  • Ad-blocking via PiHole
  • Local file sharing via Samba/SMB
  • Locally-hosted web applications with valid hostnames and valid SSL certs (via Let’s Encrypt).
    • SearxNG
    • Jellyfin
    • Pairdrop
    • CodeServer
    • Snapcast Server
    • myMPD (MPD web UI)
    • Kiwix (including full Wikipedia dump with images)
    • NodeRED
    • CalibreWeb

Travel Router / Access Point

For internet uplink, there are multiple options depending on need. By default, the internal/bulit-in wi-fi is the internet uplink and the USB wi-fi adapter is the client-facing AP interface. This is how I normally keep it configured in my use-cases.

Alternatively, the built-in wi-fi can be used as the client-facing AP and the uplink to the internet can be provided by a USB-tethered smartphone or a USB ethernet adapter --OR-- the internet uplink can be omitted entirely and either the USB or built-in wifi adapters can serve clients (or both: one in 2.4 GHz mode and the other in 5 GHz mode). Fortunately, the built-in wifi chip in the Banana Pi works well in AP mode but that’s not always the case (cough Orange Pi Zero W2 cough).

If a PC is connected to USB0 (the OTG port), the device will act as an ethernet gadget. The travel server will add its end of the usb0 interface into the LAN bridge along with the client-side AP. This means the connected PC will be on the same LAN as the wireless clients.

It’s also possible to add a USB ethernet adapter and bridge it into the LAN side as well.

Depending on configuration, a small USB-C hub may be needed. I’ve got one that includes a USB A port, ethernet port, and additional USB C port.

VPNs can also be configured as needed. I’ve got a privacy one that can route all traffic as well as a Wireguard one that connects back to my home LAN when I’m using it remotely.

DHCP and DNS are both provided by PiHole

Reverse Proxy

All applications hosted on the travel server are fronted by Nginx and use valid Let’s Encrypt certificates. This eliminates the need to install a custom CA cert in end devices or have the clients accept an untrusted self-signed cert.

This also ensures all applications are protected by TLS which is required for full functionality of some applications.

How does that work?

The hostname of the travel server (mobile) is a subdomain of my personal, project domain (mydomain.xyz). All applications are a subdomain of that (e.g. jellyfin.mobile.mydomain.xyz), and I simply request a wildcard cert from Let’s Encrypt for *.mobile.mydomain.xyz. Currently, Let’s Encrypt requires the use of DNS validation when requesting wildcard certificates.

Movies/TV

Movies and TV shows are provided by Jellyfin and are stored on the 1 TB SD card. I’ve tested 4 simultaneous streams, and the travel server didn’t even break a sweat. Granted, it’s not transcoding anything so I believe I’m mostly limited by USB, wifi, and/or SD card bandwidth in that regard.

For reliability, the Jellyfin database is stored on the internal 32 GB eMMC rather than the SD card. This both reduces wear and tear on the card as well as proves to be faster and more reliable.

CPU transoding is a non-starter, and the GPU drivers for these boards isn’t exactly well supported. The GPU drivers also rely on V4L which Jellyfin has deprecated for hardware transcoding, so I opted to forego transcoding entirely.

To load movies/TV shows on here, I pre-process them with ffmpeg in the following way:

  • Scale to 720p to save space
  • Encode to H.264 in an MP4 container (including subtitles as mov_text if available) in yuv420p pixel format to avoid the need for remuxing or transcoding
  • Map only the primary English audio and subtitle streams to further save space
  • Downmix multi-channel audio to two-channel stereo

Music

Music is provided by a combination of MPD and Snapcast and the library is also stored on the 1TB SD card.

MPD manages the music collection while Snapcast allows synchronized multi-room audio and connecting receivers via wifi.

For local playback, I use myMPD web UI and use its streaming feed or use the MPD and Snapcast clients on the end device. There’s also a Snapcast client installed on the travel server itself, so if you add a USB speaker it can playback music directly.

Books

It runs Calibre-Web to manage my book collection which is also stored on the 1 TB SD card. When my phone is connected to its wifi, it can use my FBReader app to connect to the Calibre library over OPDS to download books.

Development

The travel server runs CodeServer which is an un-Microsofted web-based version of VSCode. You can set that up however you want, but I’ve got it setup for:

  • React / NextJS development
  • Python development
  • ESP8266/ESP32 development with Platform.io

Other services it runs to facilitate development include:

  • NodeJS and Bun
  • Postgres (via Docker)
  • Mosquitto MQTT
  • Redis
  • CouchDB
  • NodeRED

Offline Knowledge

Kiwix is installed with a large selection of ZIMS for offline reference.

  • DevDocs for React, Bun, NodeJS, ExpressJS, NextJS, etc. Pretty much every major libarary and framework I work with has offline docs
  • Full text Wikipedia dump with images (approx 130GB)

Search

I installed SearxNG so I always have an ad-free, AI-free, no BS search engine available.

File Sharing

The travel server has a few different ways to share files:

  • Samba (SMB) shared folder
  • PairDrop for quick and easy one-to-one local sharing in the browser or phone app
  • SSHFS (alternative method of accessing the SMB shares

Future Plans / Not Yet Implemented

  • Add data passthrough to the UPS board so a host PC can charge the UPS/power the travel server while also enumerating it as a USB ethernet device. Currently the UPS board only passes power and plugs into the peripheral USB port.
  • Add some kind of tile server and map viewer. Inspired by this project.
  • Set up captive portal so Android (and probably Apple, too) devices don’t freak out if there’s no internet uplink. Currently requires an annoying “Stay connected to this network” and enabling airplane mode so that DNS will work over the wifi connection if there’s no internet uplink available.
  • Make a web UI to manage services/configs. Currently, config changes require SSH-ing in and modifying the config directly. I do have preset configs for different “modes” but you still have to swap them around by hand.
  • Design and 3D print a case that can hold the UPS board and the travel server itself while allowing the travel server to be “ejected” (basically I imagine it slotting into it from the outside and connecting to fixed USB and mini HDMI connectors embedded in the case).
  • DecronymB
    link
    fedilink
    English
    arrow-up
    3
    ·
    edit-2
    2 hours ago

    Acronyms, initialisms, abbreviations, contractions, and other phrases which expand to something larger, that I’ve seen in this thread:

    Fewer Letters More Letters
    AP WiFi Access Point
    DHCP Dynamic Host Configuration Protocol, automates assignment of IPs when connecting to a network
    DNS Domain Name Service/System
    NAT Network Address Translation
    NVMe Non-Volatile Memory Express interface for mass storage
    PiHole Network-wide ad-blocker (DNS sinkhole)
    SSD Solid State Drive mass storage
    VPN Virtual Private Network

    8 acronyms in this thread; the most compressed thread commented on today has 13 acronyms.

    [Thread #50 for this comm, first seen 11th Jul 2026, 12:40] [FAQ] [Full list] [Contact] [Source code]

  • mal3oon@lemmy.world
    link
    fedilink
    English
    arrow-up
    7
    ·
    9 hours ago

    Great project. One risk I see (and faced in the past) is dying sdcards. They hold up much less overtime compared to ssds. Did you face this before? I have gotten a bunch a corruption on my dbs, and even filesystems (ext4). SDcards are vulnerable especially if running 24/7. I wonder if there are better tiers or better solutions.

    • Iced Raktajino@startrek.websiteOP
      link
      fedilink
      English
      arrow-up
      3
      ·
      edit-2
      6 hours ago

      I addressed that in a few ways:

      1. I bought a quality SD card to start with. A 1 TB card is a lot of eggs in one basket so I wasn’t about to cheap out on that part.
      2. The board has 32 GB of eMMC which is where the OS is installed
      3. There are very few writes to the SD card during normal operation (after initially loading content onto it). Running data (DBs, caches, log dirs, etc) for most applications is stored on the eMMC rather than the SD card or in some cases written to tmpfs (logs).
      4. The subset of content I loaded onto this from my main media server was all chosen because it has the most re-watch potential, so re-loading close to a TB of media isn’t something that’s going to happen too often. The largest write it sees is the semi-annual refresh of the full ~130 GB Wikipedia ZIM dump, but I may push that back to once a year. I’ve only updated it twice so far.
      5. Armbian assumes it’s going to run from SD card and does a pretty good job about minimizing the number of writes. Logs are all written to zram and only occasionally written to disk, it has no swap file, etc. If those are good enough to keep an SD card happy, they should keep an eMMC even happier.

      Basically, I tried my best to configure the SD card so that in day to day use it’s WORM (write once, read many) without actually going so far as mounting it read only. The data that gets synced daily from my main servers is incremental and usually has few changes.

      I’ve had PIs running for years without issue with the SD card mounted read only and retired them from service before the SD cards ever started showing issues. My Meshtastic EAS Alerter project is using one of those Pi Zero W2’s I retired from an older project and its 6 year old SD card.

      This is actually the second iteration. Originally I attached a 1 TB SSD via a USB->NVMe enclosure. That worked, but also made the unit sprawl which was something I wanted to trim down in the final version. It worked but had random glitches and instability that I initially chalked up to the board and/or Armbian. I didn’t realize it was EMI from the Wi-Fi coming in through the USB cable until after I switched to the 1 TB SD card. That’s why I added some ghetto shielding to the power cable for lack of having ferrite beads on hand lol.

      Should the SD card prove problematic over time, I can always go back to the USB->NVMe solution and lose its “keychain” form factor.

         /_\  _ _ _ __ | |__(_)__ _ _ _  
        / _ \| '_| '  \| '_ \ / _` | ' \ 
       /_/ \_\_| |_|_|_|_.__/_\__,_|_||_|
                                         
       v25.11.2 for BananaPi BPI-M4-Zero running Armbian Linux 6.12.58-current-sunxi64
      
       Packages:     Ubuntu stable (noble)
       Updates:      Kernel upgrade enabled and 52 packages available for upgrade 
       WiFi AP:      SSID: (BananaAP), channel 6 (2437 MHz), width: 20 MHz, center1: 2437 MHz
       IPv4:         (LAN) 192.168.5.1, 10.10.10.15 (WAN) 192.168.1.12
       Containers:   postgres_postgres_1
      
       Performance:  
      
       Load:         4%           	 Uptime:       18 weeks, 22 hours, 49 minutes	 Local users:  2           	
       Memory usage: 45% of 3.83G  	 Zram usage:    74% of 1.91G  	
       CPU temp:     63°C           	 Usage of /:   35% of 29G    	
       RX today:     6 GiB  
      
  • glizzyguzzler@piefed.blahaj.zone
    link
    fedilink
    English
    arrow-up
    4
    ·
    9 hours ago

    This is great, I’d love to see the config files - especially the WiFi pass through stuff. No experience with that! But the rest all fitting together would be rad as hell.

    Peeps would be able to get the 4GB banana zero and just rock it up quick full service!

    I know that’s a big ask, sharing your cursed config files is work… if you feel up for it tho - hell yes

    • Iced Raktajino@startrek.websiteOP
      link
      fedilink
      English
      arrow-up
      2
      ·
      edit-2
      5 hours ago

      It’s kind of a mix of things duct-taped together, but here’s the gist of what controls what. If you want to see any specific configs, let me know.

      Network Manager controls the “static” interfaces. I’ve got some udev rules for my known hardware (USB wifi/ethernet adapters) so that they get friendly names as opposed to ugly “predictable” names.

      The interfaces managed by NetworkManager are:

      • STA mode Wi-Fi (internet uplink)
      • LAN Bridge
      • Wired Ethernet (internet uplink)

      Connecting a USB-tethered smartphone is pretty plug and play. It automatically gets picked up as a USB ethernet interface, receives its IP address from DHCP, and gets set as the default gateway. So there’s nothing that needs to be configured when using that as the internet uplink other than making sure there’s no other active gateway that might interfere.

      The LAN segment is a generic Linux bridge called br-lan (I’m borrowing OpenWRT’s naming convention). In normal operation, it has wlan1 and usb0 as members (AP and USB ethernet gadget, respectively). If I need a wired ethernet port on the LAN side, I just plug a USB ethernet adapter in and add it with brctl addif br-lan eth{XXX}

      The usb0 ethernet gadget interface is brought up using a script that runs at boot via systemd to configure a libcomposite ethernet gadget before the network target. This ensures it’s available when the network comes up so it can be successfully added to the LAN bridge.

      When changing out of the default configuration, I just go into network manager to enable/disable the correct interfaces. e.g. If I want to use wired ethernet for uplink and internal wifi for client AP, I enable the wired ethernet and disable the internal wifi’s connection to the router. Then I swap hostapd conf files to use the one configured for the internal wifi instead of the USB one and update the members in the LAN bridge accordingly. e.g. brctl delif br-lan wlan1 ; brctl addif br-lan wlan0

      To add a LAN-side wired ethernet, I just make sure it’s not already configured for “WAN” in NetworkManager and add it to the LAN bridge. That, or setup a VLAN interface and use a single USB ethernet adapter for both (haven’t done that on this device but I know it works from having done that in the past).

      Thankfully, PiHole exposes the DHCP controls for its underlying dnsmasq and since I’m already running PiHole for ad blocking and DNS, it was natural to also use it for DHCP. It’s configured to advertise addresses to the br-lan interface only.

      Routing/NAT is all done directly with iptables. The VPNs dynamically update it as they connect/disconnect using their up and down hook scripts, and for the NAT used for client connections, it’s basically just iptables -t nat -A POSTROUTING -s $SOURCE_CIDR -o $OUT_INTERFACE -j MASQUERADE where SOURCE_CIDR=192.168.5.0/24 is the LAN segment address range and OUT_INTERFACE=wlan0 is the uplink interface (in the default configuration).

      I’ve got some ugly scripts to adjust the NAT rules depending on which interface is currently acting as the “WAN” interface.

  • DataCrime@lemmy.dbzer0.com
    link
    fedilink
    English
    arrow-up
    10
    ·
    13 hours ago

    Just don’t travel without putting it in checked baggage… that’s just TSA bate. I traveled with a pair of battlebot kits once and they still swab my wrists every time I go through PDX 🤓

    • quick_snail@feddit.nl
      link
      fedilink
      English
      arrow-up
      1
      ·
      2 hours ago

      One time I had to take an emergency flight on a day I was playing with electronics.

      I had no electronics on me, but the swab test gave a false positive for explosives. Then they took me into a back room and escalated. This time they groped my dick with the front of their hand, not the back of their hand.

      Always shower well before going to the airport, if you like to tinker with low voltage electronics or use cleaning products of any kind.

  • picnic@lemmy.dbzer0.com
    link
    fedilink
    English
    arrow-up
    5
    ·
    12 hours ago

    I travel a few times a month for work. My main concern would be losing that, and thinking either what personal info I’d have there or what access it would give to a malicious party. I travel to somewhat hostile countries so my main risk scenario is someone confiscating my devices at border upon entry. That’s why I dont carry the flipper zero around, ever.

    I have a beryl travel router which does wireguard to home and mullvad. I also have a broken samsung phone, which I use in dex mode to access services on hotels’ tvs. Minimal setup needed.

  • null@piefed.nullspace.lol
    link
    fedilink
    English
    arrow-up
    24
    ·
    24 hours ago

    This is sick! Thanks for this write-up.

    One thing this shows off nicely is just how many services you can squeeze onto some pretty modest hardware. I know people with big server racks running mostly this same stuff.

    • Iced Raktajino@startrek.websiteOP
      link
      fedilink
      English
      arrow-up
      16
      ·
      24 hours ago

      Yeah, I was surprised as well by how many things can run concurrently and why this project ballooned like it did. It was originally just going to be a travel router and PiHole but I decided to see how much I could cram in there. There’s still room for more but I had to move on to other projects once winter was over. If/when I have time, I’d like to add a map tile server to the mix.

      The only limit I’ve run into is when I’m running the NextJS dev server and Jellyfin at the same time. That’s just a bit too much demand on the memory so one or the other crashes. So I can’t watch JF while I work, but considering what’s hosting these, I can forgive it.

        • Iced Raktajino@startrek.websiteOP
          link
          fedilink
          English
          arrow-up
          4
          ·
          edit-2
          6 hours ago

          I think it’s the other way around, at least in the US. The last time I flew, anything with a lithium battery had to be either on your person or in your carry-on and couldn’t exceed a certain amperage/watt-hour rating. I remember having to check specifically on that since I wasn’t sure if I could bring my vape.

          But mostly, a bare PCB with two 18650’s visible isn’t something I want to have to explain to airport security lol. They may let it pass, but it’s definitely going to be a hassle. Easiest to just use an approved power bank or just power it from my phone’s USB port. The UPS was mostly so I could make it mobile and use solar chargers with it.

          • silenium_dev@feddit.org
            link
            fedilink
            English
            arrow-up
            2
            ·
            5 hours ago

            Iirc I had to check in my checked bag before going through security. Also had no problem with putting my Nintendo Switch and controller in my checked bag.

            Although I only flew within the EU, so different regulations may have applied than in the US.

            • Iced Raktajino@startrek.websiteOP
              link
              fedilink
              English
              arrow-up
              4
              ·
              5 hours ago

              Ah, yeah, you can have most devices with lithium batteries in your checked baggage, but they have to be off and packed so they’re protected from damage. It’s preferred for those to be carry-on items but isn’t required.

              Power banks, vapes, spare batteries, etc are specifically prohibited in checked baggage and must be in your carry-on or on your person.

              https://www.faa.gov/newsroom/lithium-batteries-baggage

  • brap@lemmy.world
    link
    fedilink
    English
    arrow-up
    30
    ·
    1 day ago

    Very very nice. Some good inspiration in this post, especially the mobile Jellyfin part.

  • RandomStranger@piefed.social
    link
    fedilink
    English
    arrow-up
    8
    ·
    22 hours ago

    Cool! Please enlighten me of the use cases a bit. The offline part I get. But since you call it a travel server, I assume you also have a home server? Then why not just VPN home to access that? What benefits (other than being available offline) does the additional hardware being?

    • Iced Raktajino@startrek.websiteOP
      link
      fedilink
      English
      arrow-up
      18
      ·
      22 hours ago

      The original intent of this was a travel router that VPN’d back to home as well as providing PiHole ad blocking, but it ballooned when I just wanted to see how much could run on this little board. I didn’t have anything in mind when I made it other than if I could, so I had to invent reasons after the fact lol

      SHTF Server

      If shit ever hits the fan (evacuation order, natural disaster, house burns down, etc), this is something that’s easy to grab, takes up almost no space, can be powered for days with a power bank, and has all my important docs on an encrypted volume. If I’m stuck in a temporary shelter or whatever, I can keep myself entertained as well as a handful of other people who can connect to it.

      I’ve also got cron jobs to sync important files from my main servers to this one, so it stays up to date.

      Power Outages

      We don’t maintain any permanent streaming subscriptions (only when there’s something good on like a new season of Star Trek drops lol). So if the power goes out, and I can’t run the main servers, this can (and has!) run from a power bank for about 36 hours. Everyone in the house can stream something different to their phone if they want.

      Camping, Traveling, Etc.

      Kinda covered under offline access, but can keep the kids entertained without cell service or racking up data overages.

      I also made a couple of Snapcast receiver speakers with some old Pi Zero W’s so we can have wireless speakers around the campsite. I was able to add an RTL-SDR dongle to it and pipe the FM audio to Snapcast, so if there’s a game on, we can listen to that. I haven’t used that in practice, but it worked on the bench.

      Internet access isn’t a given

      I’ve had to travel places that have no or poor internet access and poor cell reception. Depends on where and why I have to travel and is always a crapshoot. This gives me a bare minimum environment that’s always on hand.

      Black Start

      If my homelab ever goes totally down or has a major malfunction, I’ve got copies of documentation, console passwords (that are normally kept in Vaultwarden hosted on the stack that’s unavailable in this scenario), and other resources to bring things back up. I host pretty much everything we use (including email) so when the lab is down (rare but does happen) it’s nice to have a backup stack.

  • furby@infosec.pub
    link
    fedilink
    English
    arrow-up
    8
    ·
    23 hours ago

    Great writeup and encouraging work! Thanks for taking the time to share and kudos for your work!

  • mlfh@lm.mlfh.org
    link
    fedilink
    English
    arrow-up
    14
    ·
    1 day ago

    Very very cool! Would love to see it all in the case once you design and print it.

  • Denys Nykula@piefed.social
    link
    fedilink
    English
    arrow-up
    2
    ·
    23 hours ago

    Pretty much every major libarary and framework I work with has offline docs

    Library, as in every library from npm that you import directly? Are Preact, lodash, MDN JS and Tailwind docs included in that collection? If I’m making a library, do I need to do anything specific to ease offline reading (and searching) of its website and readme along with other libraries if anybody finds it useful? All docs currently fit in these two pages.

    • Iced Raktajino@startrek.websiteOP
      link
      fedilink
      English
      arrow-up
      3
      ·
      22 hours ago
      • MDN (HTML, CSS, JS): Yes - Had to manually crawl/scrape that one myself. Took almost 3 days since I had a pretty generous delay between pages.
      • Tailwind: Yes (v3 anyway)

      The Kiwix web interface has a search, and it’s decent. AFAIK, unless you build your own somehow, that’s all there is for that.

      • Denys Nykula@piefed.social
        link
        fedilink
        English
        arrow-up
        3
        ·
        22 hours ago

        Thanks for checking! Meanwhile I found the instructions on adding more scrapers for making documentation of other libraries and tools available offline if one wants to write them. Idk if it makes the docs available in Kiwix automatically, but Kiwix community seems to base its offline documentation packages on indexing this project.

        • Iced Raktajino@startrek.websiteOP
          link
          fedilink
          English
          arrow-up
          1
          ·
          22 hours ago

          Nice. I forget what project I used (it’s been over a year and I haven’t used it since). I just remember it was Docker based and I setup a wrapper script where I could just feed it a base URL to start from and a filename for its output. It definitely didn’t do the cleanup and polishing that DevDocs does with theirs, but it worked well enough for my purposes.