The SatNOGS documentation is mess, with bits and bobs spread across multiple places (main site, wiki, forums etc). To enable me to remember how to re-configure if required, here’s the process I followed for an RTL-SDR ➜ Raspberry Pi.
I wanted to share a special thanks to Bali from the Libre Space discussion group for taking the bully by the horns and creating a tutorial offering what the official documentation can’t.
This whole setup is docker based, with only configuration files living directly on the RPi host.
Setting up the RPi
Unfortunately even though it runs within docker, the host still needs an old version of Debian, so prepare your SD card with raspios-bookworm. Using the RPi Imager makes it simple.
To use an RTL-SDR we need to force it not to use the default drivers:
Paste the following into /etc/modprobe.d/blacklist-sdr.conf
<code>blacklist rtl2832_sdr blacklist dvb_usb_rtl28xxu blacklist rtl2832 blacklist airspy blacklist hackrf blacklist msi001 blacklist msi2500</code>
Add rtl-sdr.rules
<code>wget https://raw.githubusercontent.com/rtlsdrblog/rtl-sdr-blog/refs/heads/master/rtl-sdr.rules sudo mv ./rtl-sdr.rules /etc/udev/rules.d/ sudo chown root: /etc/udev/rules.d/rtl-sdr.rules</code>
Setup Docker
<code>sudo apt update sudo apt install docker-compose docker.io</code>
Create a directory in your home directory which will hold the station’s configuration. Create the folder with your station ID, so that if you end up with additional stations you just need additional folders.
<code>mkdir ~/station4938 cd ~/station4938</code>
Defining the configuration
Inside the station folder create station.env
<code>SATNOGS_API_TOKEN=<NETWORK_TOKEN> SATNOGS_ARTIFACTS_API_TOKEN=<DB_TOKEN> SATNOGS_DB_API_TOKEN=<DB_TOKEN> SATNOGS_STATION_ELEV=0 SATNOGS_STATION_ID=4938 SATNOGS_STATION_LAT=-43.02166 SATNOGS_STATION_LON=147.29000 SATNOGS_ARTIFACTS_ENABLED=True SATNOGS_SOAPY_RX_DEVICE=driver=rtlsdr SATNOGS_ANTENNA=RX SATNOGS_LOG_LEVEL=DEBUG #SATNOGS_LOG_LEVEL=INFO SATNOGS_RX_SAMP_RATE=2.048e6 #Supported gain values: 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 SATNOGS_RF_GAIN=15.7 SATNOGS_PPM_ERROR=0 GR_SATELLITES_ENABLED=true GR_SATELLITES_APP=gr_satellites GR_SATELLITES_KEEPLOGS=true UDP_DUMP_HOST=0.0.0.0 AUTO_SCHEDULER_EXTRA=-P /var/lib/satnogs-client/priority.txt -d 1.5 -m 5</code>
Note that the SATNOGS_ARTIFACTS_API_TOKEN and SATNOGS_DB_API_TOKEN have the same values. They are used by different docker containers (client and auto-scheduler).
Get the NETWORK_TOKEN from https://network.satnogs.org/, and the DB_TOKEN from https://db.satnogs.org/
Defining Docker-Compose
Still in the station folder, create docker-compose.yaml, and paste the following:
<code>version: '3.8'
services:
rigctld:
image: librespace/hamlib:latest
user: '500'
read_only: true
environment:
MODEL: '1'
PORT: '4532'
restart: 'unless-stopped'
command: 'rigctld'
satnogs_client:
image: librespace/satnogs-client:master-unstable
user: '500'
read_only: true
init: true
env_file:
- ./station.env
environment:
SATNOGS_RIG_IP: 'rigctld'
SATNOGS_RIG_PORT: '4532'
command: 'satnogs-client'
device_cgroup_rules:
- 'c 189:* rwm'
devices:
- '/dev/bus/usb'
volumes:
- type: 'tmpfs'
target: '/tmp'
- type: 'volume'
source: 'satnogs-client-latest'
target: '/var/lib/satnogs-client'
restart: 'unless-stopped'
stop_grace_period: 1s
auto-scheduler:
image: librespace/satnogs-auto-scheduler:0.4 # stable
# image: librespace/satnogs-auto-scheduler:master # latest
user: '500'
command: 'bash -c "while true; do sleep 30; schedule_single_station -s $$SATNOGS_STATION_ID $$AUTO_SCHEDULER_EXTRA -l INFO > /var/lib/satnogs-client/.cache/auto-scheduler/last_schedule.log 2>&1; sleep 3600; done"'
read_only: true
env_file:
- ./station.env
environment:
CACHE_DIR: '/var/lib/satnogs-client/.cache/auto-scheduler'
depends_on:
- satnogs_client
volumes:
- type: 'tmpfs'
target: '/tmp'
- type: 'volume'
source: 'satnogs-client-latest'
target: '/var/lib/satnogs-client'
restart: unless-stopped # du not use with exiting client as this will just loop
stop_grace_period: 1s
volumes:
satnogs-client-latest:</code>
Creating a priorities file
The satellite auto-scheduler will automatically schedule satellite passes to monitor. To ensure that the satellites I want to monitor are given preference, I need to create a priorities file containing one satllite per line, with
The priority file should have columns of **NORAD** **priority** **UUID**.
A comment may be added to the end of the line for human reading.
Information is available from the SatNOGS database.
e.g. for the SSTV transmitter on the ISS:
`25544 0.9 8qgr8X9wKAwb9BwA6uZYqX` # ISS SSTV Transmitter
Below is a sample with SSTV transmitting satellites.
<code># SSTV 57172 0.99 AjYqcyjoAjJrmfsYtH7oux # UmKA 1 RS40S 67290 0.98 n5r2A8UVR5hmytgVVPnULu # SAKHACUBE-CHOLBON RS18S 57189 0.97 kreKfmt4vs4n22TyJZ4Mft # VIZARD-meteo RS38S 57203 0.96 JnBA9dq5WnWQugErAnPDcz # UTMN-2 RS27S 57180 0.95 AUF5QGKakLf5FGfK5aCZfZ # MONITOR-3 RS58S 61762 0.94 n5r2A8UVR5hmytgVVPnULu # ARCTICSAT 1 RS74S 25544 0.93 8qgr8X9wKAwb9BwA6uZYqX # Zarya ISS RS0ISS 40908 0.92 q6CVKJirfoUjNzD2A4rxsk # LILACSAT 2 67291 0.91 AeDo8VuKWD3VWRgfDk7bt7 # QMR-KWT 2 67279 0.90 KBkJKKjq4VDwdZWUSKZCMp # GALAPAGOS-UTE-SWSU 57182 0.60 PRJ9oz5oKUAVgCrPPB9u3j # Monitor-4 RS57S</code>
Starting it up
The while shebang can then be started up, which will retrieve the docker images, create containers and get it all running.
docker-compose up -d
Debugging
Access running docker containers
While docker is running, access a shell within with: <mark style="background-color:#00420e;color:#b1ffd5" class="has-inline-color"> </mark><mark style="background-color:#00420e;color:#f3fff3" class="has-inline-color">docker-compose exec auto-scheduler sh</mark><mark style="background-color:#00420e;color:#b1ffd5" class="has-inline-color"> </mark>
Review auto schedule log
<code>> docker-compose exec auto-scheduler sh # check last update ls -lah /var/lib/satnogs-client/.cache/auto-scheduler/last_schedule.log #view log cat /var/lib/satnogs-client/.cache/auto-scheduler/last_schedule.log</code>
Run a test schedule
<code>> docker-compose exec auto-scheduler sh # run with passed args schedule_single_station -s $SATNOGS_STATION_ID $AUTO_SCHEDULER_EXTRA --dryrun -l INFO # or with custom args schedule_single_station -s $SATNOGS_STATION_ID -P /var/lib/satnogs-client/priority.txt -d 1.5 -m 5 --dryrun -l INFO</code>
Review run state
The docker images are read-only, with run state stored on a ramdisk. All run state may be found in /var/lib/satnogs-client/.
<code>ls -lah /var/lib/satnogs-client/</code>
I think that’s it. I guess I’ll know when future-me needs to follow these instructions. :/
Lance
July 2026