Configuring a SatNOGS station

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=&lt;NETWORK_TOKEN>
SATNOGS_ARTIFACTS_API_TOKEN=&lt;DB_TOKEN>
SATNOGS_DB_API_TOKEN=&lt;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>&amp;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

Leave a Reply

Your email address will not be published. Required fields are marked *