Last time I covered using overlayfs on a Linux Single Board Computer to survive unwelcomed power hits.
To understand this post you may want to read or skim the last one...I wanted to finish the indestructible SBC setup by adding a Python virtual environment using uv, creating a basic webserver "hello world" using Python flask, and getting the flask service to auto-start at boot using systemd.
If you are a Linux/Python admin you may already know how to do all of this; please consider skipping this post to check out these guys instead.
As usual, I am writing the steps because I forget everything I have ever done.
| Pi Zero--512MB RAM but RPi's text-only OS still gave me a surprising amount of extra space to mess around in an overlayfs configuration. |
BUT FIRST--A WORD FROM THIS BLOG'S SPONSOR:

After getting your SBC set, you will probably want to design a PCB for your SBC then get it fabricated.
MAKING CHANGES TO THE READ-ONLY SBC
From last post: we set the Raspberry Lite OS to read-only to survive power hits using overlayfs, but today we are writing OS changes.
How?
- I removed the PI's SD card
- I mounted it on my PC using an SD to USB adapter
- I edited /boot/firmware/cmdline.txt, getting rid of overlayroot=tempfs at the end of the statement,
- then saved cmdline.txt.
Then I popped the SD back into the RPI and started it up--it was now a normal read-write device.
When I was ready to go back to indestructible mode, I added overlayroot=tempfs back to the cmdline.txt using vi, saved, and reboot.
WHAT IS UV?
I'd been administering Python environments for years; the amount of tools needed to set up/maintain python3 and Python projects-- pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and so on, drove me nuts.
I had a preflight checklist for creating new virtual environments and still make stupid mistakes.
Imagine my excitement when a tech from my geek tech group told me about uv, a single tool that kicks the other Python admin tools' butt.
Count me in!
I read about uv here; a good getting started video is here.
For Raspberry Pi OS here are the commands I used to create a new project called pyflask using uv:
#hint: to make my SSH terminal not look crap, I used UTF-8
#encoding (I use secureCRT9.6--
#properties > appearance > encoding
#default is "automatic" which wasn't working)
#install uv
apt update
apt install curl #needed for next command--may already be installed #on your SBC
#install uv using less HD space vs using pip install.
curl -LsSf https://astral.sh/uv/install.sh | sh
#SET PATH needed for terminal app to find uv when you try to run it
#put uv into PATH--for rpi I could skip this step and just restart #bash; #not sure w othr distros
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
#note, for some distros .local above is replaced by .cargo
#restart bash
bash
#is uv working? This should show a list of basic uv commands.
uv
CREATE A NEW PYTHON PROJECT AND VIRTUAL ENV USING UV
#cd to ~ you should do the next command from your home dir.
#"my home dir is /home/charlie, yours isn't".
uv init pyflask #pyflask is the name of the project
#cd to the project folder you just created.
cd ~/pyflask
uv run main.py
#creates venv and show you successful hello world.cd
#ACTIVATE THE NEW PROJECT
#you still must be in the project dir.
#must use source here or term will open
#a new term, make the change, and pop you back to old one....
source .venv/bin/activate
#INSTALL PYTHON PACKAGES
#in project root folder....
#uv add [whatever] # use this instead of pip, faster!
#much MUCH faster vs. pip install.
#let's add flask!
uv add flask
#ASIDE--with UV, WHERE DO YOUR FILES GO?
#see what is where in uv--useful cmd!
uv tree
#in project root. See below. note-- never edit anything inside the #.venv dir and its subdirs.
#/home/pi/my_weather_bot/ <-- YOUR PROJECT ROOT (You work here)
#├── main.py <-- Your code goes here
#├── utils.py <-- Your code goes here
#├── data/ <-- Your data folders go here
#│ └── weather_log.csv
#└── .venv/ <-- THE VIRTUAL ENV (Do not open/edit)
# ├── bin/
# ├── lib/
# └── pyvenv.cfg
After all of this I had a working venv for project pyflask. Good start!
GETTING FLASK GOING....
Flask is a simple webserver for Python--more here. Using flask I created a webserver that generated "hello world" when viewed from my browser--using only a few lines of Python--super easy!
touch /home/charlie/pyflask/app.py
vi /home/charlie/pyflask/app.py
####################SNIP ###############
#we used uv to install the flash module in our venv already.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
#START PYTHON APP using UV
#use this to test your flask setup.
uv run python3 app.py
#if you just use python3 app.py the path gets
#wacked and it won't work
###term will show something like what is below
#if flask is ready to process browser GETS #and PUTS
########################################
#* Serving Flask app 'app'
#* Debug mode: on
#WARNING: This is a development server. Do not use it in a production #deployment. Use a production WSGI server instead.
#* Running on all addresses (0.0.0.0)
#* Running on http://127.0.0.1:5000
#* Running on http://192.168.5.200:5000
#Press CTRL+C to quit
#* Restarting with stat
#* Debugger is active!
#* Debugger PIN: 430-777-572
####################SNIP ###############
ACCESSING THE FLASK WEBPAGE FROM A BROWSER
Once I had everything above working it was time to test from a browser.
#if I open browser or curl using PC on
#the same wifi subnet as RPi Zero using port 5000
#I see hello world.
#Your IP will be different, but I hope you get the idea.
http://192.168.5.200:5000/
GETTING FLASK TO AUTO-START
Our indestructable SBC's test app (in this case app.py) had to start on power-up every time.
There were lots of ways I could have done this, but to me the "Debian way" was to use systemd--good video series about how systemd works starts here; let's get right to it.
#we need to create a .service file for our python app.
#in Raspberry pi and maybe other debian likes create this in this dir.
#/etc/systemd/system/
#remember that systemd only works with
#the full path to a file or executable
#the command to create the .service file using vi on a raspberry pi is this.
sudo vi /etc/systemd/system/flaskapp.service
#what I put in this new file....
###########SNIP!#############################
[Unit]
Description=My Flask App
# Wait for the network to be ready before starting (crucial for Flask)
After=network.target
[Service]
# The user the app should run as
User=charlie
# The group
Group=charlie
# The folder where your app.py is located
WorkingDirectory=/home/charlie/pyflask
# The command to start the app.
# format: /path/to/python /path/to/app.py
#we are using uv, so, we use the uv created venv virtual directory.
ExecStart=/home/charlie/pyflask/.venv/bin/python3 /home/charlie/pyflask/app.py
# Automatically restart the app if it crashes
Restart=always
# Send Python output to the system log immediately
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
###########SNIP!#############################
FINISHING UP OUR BUILD
#let's load it! first, make the system reread all systemd config files...
sudo systemctl daemon-reload
#enable at boot
sudo systemctl enable flaskapp.service
#start it
sudo systemctl start flaskapp.service
#see its status
sudo systemctl status flaskapp.service
#stop the service (no changes needed to the service file for this)
sudo systemctl stop flaskapp.service
#restart the service
sudo systemctl restart flaskapp.service
OUTTRO































