Portable Internet in a Box
This project is build an internet-in-a-box system that runs 100% off battery for use when there are extended power outages. It should be able to deliver an internet-like experience, along with critical information for living life without power.
In my other Internet in a box project, it is designed for being disconnected from the public internet. However, this only works if I still have access to power at home. Although it can run off of the generator, the combination of the server, hard drive array, switch, and router make it not usable from an offgrid situation.
Primary goals
In an ideal setup, this system should be able to operate directly from solar panels, a battery bank, or a car 12v connection without inverter.
From battery, the system should last 7 days running 4 hours per day.
It should be compact and able to be carried in a laptop bag.
All services should be accessible from a web browser, primarily on a mobile device.
Nothing should require access to the internet at any point.
All applications and services need to have a user-friendly GUI.
This system will provide:
- Stream TV shows, movies, and YouTube videos across the LAN.
- Offer a small ebook library.
- A Spotify clone with several playlists
- Have a collection of blogs and longform articles.
- An archive of documents to help with living in an emergency.
- Allow downloading of all content.
Networking goals
- Broadcast wifi to every room in the house.
- Have a DCHP server.
- Allow up to 10 devices to connect without issues.
- Run on USB power.
- Consume 1w or less.
- Optional: Provide access to a mobile data hotspot.
- Optional: Create custom DNS entries
Power goals
I want to be able to run this for an entire week, if possible, from my existing power bank. Ideally I would be able to run it for 4 hours a day, for 7 days. This means that everyone with access will be able to read, view, or download anything they want for an afternoon each day.
Video content goals
- A collection of comfort movies from each member of the house.
- At least one season from comfort TV shows, plus extended seasons for shows that are part of a habit (like watching before bed).
- An archive of YouTube videos for the girls, including Stampy and Eric Carle reads.
Power
My current bank is a Jackery Explore 160 that is rated at 167Wh. However, I want to assume there is some loss in usage. I am estimating that it is 85% efficient, which puts it at an actual capacity of 142Wh. I may be misunderstanding this. The efficiency loss may only come through the standard outlet when using a transformer. For example, when plugging in a laptop using the power brick, the brick is only 85% efficient. If I only plan to come out the USB ports on the power bank, I can assume 100% capacity.
For it to run for 4 hours a day for 7 days, that means I plan to use it for 28 total hours. At that rate, I can use 5w 6w.
To be on target, I have to take into account the router, server, and any storage. Then, I need to factor in the load on the devices when it is operational.
Server device options
- Pinebook Pro. A laptop that I can’t seem to find a use for. I know it uses low power and can charge from USB. It also runs Armbian, so can use with Docker, etc.
- Raspberry Pi 2 Model B. I have a couple just lying around and has the biggest ecosystem. I know I can setup everything I want on a RPI.
- An Android phone. I spent a little time investigating this. Although I could just setup a samba server on an Android device and let people download from it, I don’t like this option. I want something that is accessible through the clients browser. Also, I think most phones will exceed my power limits.
Device testing
Current device power usage rate:
- Raspberry Pi 2 Model B (without attached storage) idle: 2w
- Pinebook Pro (without attached storage/screen off) idle: 5w, once the battery was fully charged.
- GL.inet Router: 1w
The GL.inet router is a no-brainer. Not only does it only use 1w and has a ton of features, I already own it.
The Pinebook Pro offers a lot of flexibility. Since it has a screen, I can fix issues faster. It also has its own battery, which extends how long it will last without power. I can also connect a traditional USB external hard drive in addition to having an SD card slot. But, it is right on my power limit.
The RPI falls well below my power requirements, which makes it easy to pick. Being headless isn’t that much of a problem, as long as I can get an IP address. The main issue is storage. The USB ports on the Pi cannot power an external drive, so I will have to use something like a USB stick or a SD card in a USB reader. I’m not sure how reliable that is or how much power it will draw. My guess is the power will be significantly less than a USB external HDD.
Pinebook Pro
This is the primary route. The Raspberry Pi 2 model B is 6 years older and only has 1 GB of RAM. The PBP has 4 GB of RAM, which I will need for having 7 containers running and up to 4 users accessing the data.
I also decided to go with an SD card as the data storage, which uses significantly less power than a traditional external drive. The PBP has an SD card slot, which will be much faster than accessing the data from an SD card attached to USB storage on the RPI.
PBP power use
In order to drive down the amount of power being used, I want to slim the OS down as much as possible, disable unnecessary radios, and turn off the screen. This will use less power because the primary system will need less resources.
First, I disabled booting to the XFCE desktop using the armbian-config tool baked into the OS.
$ sudo armbian-config
Go to System and then Desktop.

While in this tool, I also changed the CPU settings to reduce the power draw. Go to System and then CPU. I set it to the CPU speed to the lowest setting, and then capped the speed at 1416000 so it can’t draw higher under load. It may slow things down, but I need to keep the power draw under control.

Then, I set it to powersave, which dropped the power draw by 1-2 watts.

Next, I disabled hibernation/sleep when the laptop lid is closed. These are the commands to do this:
$ sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
Now add these lines to etc/systemd/logind.conf
HandleLidSwitch=ignore
LidSwitchIgnoreInhibited=no
HandleLidSwitchDocked=ignore
Reboot to apply the changes.
These changes will make it so the laptop does not sleep when the laptop lid is closes. However, it also keeps the screen on, which uses an additonal 4-6 watts. I tried everything I could find to disable the screen through commands on the machine, but none worked. Both xset and xrandr will error out because it says they can’t find a monitor. I also can’t use vbetool as it is not in the repos for Armbian.
In order to disable the screen, I had to physically disconnect the cable from the motherboard. It is simple to attach/detach if anything comes up later. Cable is located here:

Real world power draw
When sitting idle, the total power draw on the Jackery power bank is somewhere between 1-5 watts.
When accessing any of the services, the power draw is between 4-5 watts.
The highest power draw is streaming from Jellyfin. When streaming, the power draw is roughly 6 watts.
All of these numbers are with the GL.iNet router attached.
Performance
At idle, resource usage is low.

Even when streaming, the resource use is much lower than I anticipated. This is while streaming a movie:

Network setup
I am using the GL.iNet 300M configured with these settings:
Storage
This is probably going to be the biggest struggle. Looking at the movie & TV show list from everyone -plus Wikipedia, music, and books/PDFs - I probably need around 500 GB of storage for this box.
Now, I can do this from the Pinebook or any other laptop I have around. But, I will definitely exceed my power requirements.
The Pinebook Pro does give me the option to have an external HDD that can go through USB 3, which would be a significant performance upgrade for streaming. It also has an SD card slot that supports potentially up to 2 TB. According the Pinebook Pro wikiit is tested up to 512 GB, with 2 TB potential.
The RPI cannot handle an external USB HDD. It would need its own PSU for the HDD. I might be able to have this kind of storage from a USB thumb drive or an SD card in a reader. It keeps feeling like the SD card is the best option since it doesn’t require any additional power.
File sizes
In order to effectively choose which server device I will use, I need to find out how much storage I will need. The higher the storage, the more likely I will need a full external HDD compared to just an SD card.
Movies, TV shows, and YouTube videos are going to be the items that take up the most storage. In particular TV shows.
Since I am optimizing for mobile devices, I can significantly reduce the quality of the videos to cut the storage requirements.
Movies - Handbrake settings to reduce the file size:
- Android 480p30 preset with modified settings
- Encoder set to “fast”
- Bitrate at 900 kbps
- Audio set at 96 bitrate
In my testing, this took the file size to half of what it was. The file size of the movies folder is roughly 63 GB. After re-encoding the movies total storage size is only 31 GB.
TV Handbrake settings:
- Discord Small 360p 30
- RF: 23
Total TV file size before re-encoding was 108 GB, which is actually smaller than I was thinking. Most of these shows were ripped from the DVD seasons I own, so most were already at standard definition. After re-encoding, the total file size went down to 32 GB.
Files
I want all the files on the SD card so I can easily back it up by cloning the card. Then I won’t have to recreate this, I can just move to a new SD card at any time.
It also means I can move to any other machine at any time. For example, I want the lower power draw of the RPI and just use SD card as storage. Or is the PBP dies and I want to run it from a different laptop.
SD card setup:
- 📁 Parent
mediafolder on the SD card. This will be thesrvfolder for filebrowser as well:- 📂 Sharing. A folder for people to add their own files that are then accessible to everyone.
- 📂 Apps. Android apps in case anyone needs them for accessing server services. This is particularly important for Briar.
- 📂 Wiki. Collection of files explaining the
portable_iiabsetup. - 📂 eBooks. The book collection so they can be downloaded.
- 📂 Music. All music files.
- 📂 TV. All the TV shows in their subfolders
- 📂 Movies. All the movies
- 📂 YouTube. All YT videos in their sub-directories
- 📁 Parent
docker_configfolder. This is where all docker files will live, as well as some of the app data I don’t want people to have access to.- 📂
filebrowser - 📂
heimdall - 📂
freshrss - 📂
jellyfin - 📂
navidrome
- 📂
Filebrowser setup
docker run -d \
-e PUID=1000 -e PGID=1000 \
--name=filebrowser \
-v /mnt/storage/media/:/srv \
-v /mnt/storage/docker_config/filebrowser/filebrowser.db:/database.db \
-v /mnt/storage/docker_config/filebrowser/settings.json:/.filebrowser.json \
-p 8084:80 \
--restart unless-stopped \
filebrowser/filebrowser
Apps
In the directory that I will use for filebrowser, I would like to have a collection of Android apps just in case they are needed. I am currently archiving some of these on my homelab and I can setup an rync cronjob to just periodically move them over.
- Briar
- VLC
- Jellyfin
- Ultrasonic
Landing page
This is so there will be a single page for everyone to access that will then have easy to follow links to the other services on the server. Part of the build will include cards with the connection info for the wifi network, the URL for this landing page, along with any login info needed for the other services,
Heimdall setup
docker run -d \
--name=heimdall \
-e PUID=1000 -e PGID=1000 \
-e TZ=America/Los_Angeles \
-p 8083:80 \
-v /mnt/storage/docker_config/heimdall:/config \
--restart unless-stopped \
lscr.io/linuxserver/heimdall:latest
Articles, blogs, and resources
A key feature for this box is to have articles, whitepapers, ebooks, and more available to anyone in the portable_iiab LAN. This is more than just ebooks from Calibre. I would like to occasionally add longform articles I find that can be read in a power outage scenario. I also would like to add emergency resources, like how to purify water or start a fire.
To do this I am going to do this with ArchiveBox on my homelab and then use rsync to automatically copy that instance to portable_iiab. I will have to leave the PBP on, even when not in use, so I can archive the webpages to ArchiveBox and will be ready when I need them.
ArchiveBox is a rad tool that will download a webpage in various formats, including raw HTML and even save the page as a PDF. This will allow the webpage to be loaded in a totally offline state and can be opened in multiple ways, which will be important on mobile devices that certain formats may be problematic, such as being mobile responsive.
~One feature ArchiveBox has is that in can ingest articles from an RSS feed. Using Pocket I can add articles using the Pocket browser extension, and then publish my saves to an RSS feed that ArchiveBox will automatically pick-up. To do this, we just need to enable the Pocket RSS feed to be public and then tell ArchiveBox to check the feed everyday. ~~
ArchiveBox
Run:
docker run -d \
-e PUID=1000 -e PGID=1000 \
-e TZ=America/Los_Angeles \
--name=archive_box \
-p 8086:8000 \
-v /mnt/storage/docker_config/archivebox:/data \
--restart unless-stopped \
archivebox/archivebox
This is mapped to a folder that is being synced from my homelab to this box. I am doing it this way so I don’t have to manage two different instances of ArchiveBox. In theory, I should be able to rsync the folder from my homelab to portable_iiab with the ArchiveBox docker instance on portable_iiab stopped. Then, in the scenario I need it, I can start the container and all they articles, plus my settings, should be synced.
The cronjob:
1 4 * * 1 rsync -azP myhomelab:/mnt/storage/archivebox /media/docker_config/
It is scheduled to sync from my homelab toportable_iiab every Monday at 4:01AM.
ArchiveBox RSS automation - DEPRECATED
I have moved away from this. These notes are here for achive purposes.
Command to tell ArchiveBox in Docker to grab the feed. First we need to exec into the container:
$ docker exec -it archive_box_web /bin/bash
This will exec into the container, but as root. ArchiveBox refuses to do anything as root. So next we need to switch to the archivebox user:
# su archivebox
Then we pass the command to archive the Pocket RSS feed everyday:
$ archivebox schedule --depth=1 --every=day https://getpocket.com/users/$USER/feed/all
How to run manually
$ cd /data
$ curl https://getpocket.com/users/$USER/feed/all | archivebox add
FreshRSS
Using FreshRSS, I can access any articles it has collected from the feeds that are stored on the server. In my testing, any feed that delivers the full article in the feed is still accessible in the browser on FreshRSS, even if no internet is available.
I copied my existing FreshRSS installation from my homelab, which uses all the same configurations and users.
Setup:
docker run -d \
--name=freshrss \
-e PUID=1000 -e PGID=1000 \
-e TZ=America/Los_Angeles \
-p 8085:80 \
-v /mnt/stroage/docker_config/freshrss:/config \
--restart unless-stopped \
lscr.io/linuxserver/freshrss:latest
Video
Movies
Each person roughly has a movie a day. Plus, there are no movies on here that another person won’t watch.
I am compressing these to 480p since we might watch together on a laptop screen. The slightly higher fidelity will be worthwhile on a bigger screen.
TV shows
I would love to move a couple season of each to this build, but I don’t think I have the storage availability. For the first build, I think I will go with just one season of each show. If the planned usage for this build is one week, a single season of a show would allow for someone to watch a couple episodes a day and be fine.
I will be compressing TV shows to 360p, which on mobile will look okay. Not great, but passable, especially for the situation. This will minimize the file size and might be able to stretch more seasons onto the drive.
Youtube
This is mostly for my youngest kids, so only downloading the bare minumum for them. They have a night time habit of watching Minecraft songs or Eric Carle read-alongs, which will definitely need to be available for this build. I also want some regular videos they watch throughout the week.
I am downloading these at 360p since they will only be watched on a mobile device.
Jellyfin
Since the core reason I am building this box is because there will not be access to the internet, Jellyfin is a no-brainer since it doesn’t require it at all.
I’m not sure if the PBP will be able to keep up with streaming content to users. But, it will provide a usable interface for everyone to browse and then download what they want to watch. I will have to experiment with turning off transcoding, which will save a ton of CPU.
In additon to compute power, I am also not sure how this will do with actual electrical power when streaming. That would be another reason to turn off transcoding, and maybe require downloading only, as it will increase the amount of power being used. I can’t have this since I am on a tight power budget.
Setup:
docker run -d \
--name=jellyfin \
-e PUID=1000 -e PGID=1000 \
-e TZ=America/Los_Angeles \
-e JELLYFIN_PublishedServerUrl=192.168.1.194 \
-p 8096:8096 -p 8920:8920 -p 7359:7359/udp -p 1900:1900/udp \
-v /mnt/storage/docker_config/jellyfin:/config \
-v /mnt/storage/media/iiab_tv:/data/tvshows \
-v /mnt/storage/media/iiab_movies:/data/movies \
-v /mnt/storage/media/iiab_youtube:/data/youtube \
--restart unless-stopped \
lscr.io/linuxserver/jellyfin:latest
Navidrome
Another offline first application. Once the music is added the service can operate offline with no issues for streaming music.
It doesn’t have the capability to use directories as playlists, which is… unfortunate. However, the music is still in directories for lists on the server, which can be downloaded through Filebrowser.
Setup:
docker run -d \
--name navidrome \
--restart=unless-stopped \
--user $(id -u):$(id -g) \
-v /mnt/storage/media/iiab_music:/music \
-v /mnt/storage/docker_config/navidrome:/data \
-p 4533:4533 \
-e ND_LOGLEVEL=info \
-e TZ=America/Los_Angeles \
deluan/navidrome:latest
Wikipedia
Having a Wikipedia service will add a lot of possibilities for research while having down time with both the power and internet being out. Plus, Demetrius loves to read Wikipedia and would appreciate having it available while we are just sitting around.
Before it can be setup I need to download the “zim” files that Kiwix will be serving. Then, set the parameters for the zim files in the Docker command. I’m assuming that if I want to add new zim files I will need to download them to the data folder and then stop, remove, and relaunch the container with the new command including all the zim files
This .zim is all of Wikipedia, with no images. This way we have access to all the information, but with storage being significantly lower.
https://download.kiwix.org/zim/wikipedia/wikipedia_en_all_nopic_2022-01.zim
Download any other .zim files here:
https://download.kiwix.org/zim/
Kiwix setup:
docker run -d \
--name=kiwix \
-e TZ=America/Los_Angeles \
-e PUID=1000 -e PGID=1000 \
-p 8087:8080 \
-v /mnt/storage/docker_config/kiwix:/data \
--restart unless-stopped \
kiwix/kiwix-serve \
fas-military-medicine_en.zim www.ready.gov_en.zim zimgit-knots_en.zim zimgit-post-disaster_en.zim wikipedia_en_all_nopic_2022-01.zim zimgit-food-preparation_en.zim zimgit-medicine_en.zim zimgit-water_en.zim