Running Your Own Software on a Device
This guide covers running a custom web application on a device — code that is not available as an obacht template. The application is started manually via Docker Compose or a shell script, kept running in the background, and exposed through the obacht Hosting tab.
This guide assumes the repository has already been cloned to the device. If not, follow Advanced: Clone GitHub first.
How it works
An application running on the device listens on a port — a numbered address other programs use to reach it over the network. Common defaults are 3000, 8080, and 5000. The project README or start command output will indicate which port is used.
obacht can route a public domain to that port. The steps are:
- The application runs on the device and listens on a port (e.g.
3000) - In the Hosting tab, a domain is bound to Local port
3000 - Visitors to the domain reach the application
The sections below cover two approaches: Docker Compose (if the project includes a docker-compose.yml) and shell scripts or direct commands (if the project is started with a single command). Both use tmux to keep the process running after the terminal is closed.
Option A: Docker Compose
Use this approach if the project includes a docker-compose.yml file.
1. Install Docker
Docker is not installed on Raspberry Pi OS by default. Run the following command in the terminal:
curl -fsSL https://get.docker.com | sh
This downloads and runs the official Docker install script. Installation takes a few minutes. When it completes, add the obacht user to the Docker group:
sudo usermod -aG docker $USER
Disconnect and reconnect the terminal session for the group change to take effect.
2. Navigate to the project
cd my-project
ls
Confirm that docker-compose.yml is present.
3. Start the application
docker compose up -d
The -d flag stands for detached. Docker starts the containers defined in docker-compose.yml and returns to the prompt immediately. The application continues running in the background after the terminal is closed.
To verify the containers are running:
docker compose ps
To follow the log output:
docker compose logs -f
Press Ctrl + C to stop following the logs. The containers keep running.
4. Restart automatically on reboot
To restart the application when the device reboots, add restart: unless-stopped to each service in docker-compose.yml:
services:
app:
image: my-app
restart: unless-stopped
ports:
- "3000:3000"
Open the file with nano docker-compose.yml, add the line, save with Ctrl + O, exit with Ctrl + X, then apply:
docker compose up -d
5. Find the exposed port
Check the ports: section of docker-compose.yml. The format is host-port:container-port. The left number is the port on the device — this is the value to enter in the Hosting tab.
Installing Dependencies
Most projects require dependencies to be installed before the application can start. The steps differ depending on the language. Complete this section before starting the application in Option B below.
Node.js projects
Node.js is not installed on Raspberry Pi OS by default. Install it via the NodeSource repository:
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install nodejs -y
This installs both node and npm. Verify the installation:
node -v
npm -v
Then install the project's dependencies from within the project folder:
npm install
This reads package.json and downloads all required packages into a node_modules folder. The application can then be started with npm start or whichever command the README specifies.
Python projects
Python 3 is pre-installed on Raspberry Pi OS. The recommended approach is to install dependencies into a virtual environment — an isolated folder containing only the packages this project needs, separate from the rest of the system.
Create a virtual environment in the project folder:
python3 -m venv .venv
Activate it:
source .venv/bin/activate
The prompt changes to show (.venv) at the beginning, indicating the environment is active. Install the project's dependencies:
pip install -r requirements.txt
The virtual environment must be activated each time before starting the application. If the terminal session is closed and reopened, run source .venv/bin/activate again before running the app.
When using systemd for autostart (see below), the ExecStart line must point directly to the Python interpreter inside .venv — no activation step is needed in that case:
ExecStart=/home/obacht/my-project/.venv/bin/python app.py
Other runtimes
For projects in other languages or with other dependency managers, the project README is the authoritative reference. Common patterns follow the same structure: install a runtime, then install packages. If a Makefile is present, make install or make setup is often the intended first step.
Option B: Shell Scripts and Direct Commands
Use this approach if the project does not use Docker and is started with a single command such as node server.js or python app.py. Install all dependencies (see above) before proceeding.
What is tmux?
tmux is a terminal multiplexer. It runs processes in named sessions that persist after the terminal window is closed. The session can be re-attached later to inspect output or stop the process.
1. Install tmux
sudo apt update && sudo apt install tmux -y
2. Navigate to the project
cd my-project
ls -la
Identify the start command. Look for a start.sh, a package.json with a start script, a Makefile, or instructions in README.md.
3. Make the start script executable (if needed)
If the project includes a start.sh:
chmod +x start.sh
See Advanced: Unix Basics — Making a File Executable for details.
4. Start a tmux session
tmux new -s app
The prompt changes — the terminal is now inside a tmux session. A status bar appears at the bottom showing the session name.
5. Start the application
Run the project's start command, for example:
./start.sh
or
node server.js
or
python app.py
The application's startup output appears in the terminal.
6. Detach from the session
Press Ctrl + B, then D. The normal shell prompt returns. The application continues running inside the tmux session.
7. Re-attach to the session
To inspect or stop the application later:
tmux attach -t app
To list all running sessions:
tmux ls
8. Restart automatically on reboot
tmux sessions do not survive a device reboot. Use systemd to start the application automatically on boot.
Create a systemd service:
sudo nano /etc/systemd/system/myapp.service
Paste the following, replacing the paths and command to match the project:
[Unit]
Description=My App
After=network.target
[Service]
User=obacht
WorkingDirectory=/home/obacht/my-project
ExecStart=/home/obacht/my-project/start.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
Save with Ctrl + O, exit with Ctrl + X, then enable and start the service:
sudo systemctl enable myapp
sudo systemctl start myapp
To check the status:
sudo systemctl status myapp
Exposing the Application via a Domain
Once the application is running it is listening on a port on the device. The next step is routing a domain to that port through obacht.
1. Identify the port
The port is shown in the start command output, the project README, or the ports: section of docker-compose.yml. A line such as the following indicates port 3000:
Server listening on http://localhost:3000
2. Open the Hosting tab
In obacht, open the device and go to the Hosting tab. If no domain has been added yet, click + Add domain and follow the wizard (see Templates & Domains — Adding a Domain).
3. Bind to a Local Port
Once the domain is verified, the domain row shows a Local port bind control. Enter the port number and click Bind.
obacht routes incoming traffic for that domain to the specified port on the device.
Quick Reference
| Task | Command |
|---|---|
| Start containers in background | docker compose up -d |
| Check container status | docker compose ps |
| Follow container logs | docker compose logs -f |
| Stop containers | docker compose down |
| Start a new tmux session | tmux new -s app |
| Detach from tmux | Ctrl + B, then D |
| Re-attach to tmux session | tmux attach -t app |
| List tmux sessions | tmux ls |
| Enable app to start on boot | sudo systemctl enable myapp |
| Check systemd service status | sudo systemctl status myapp |