sdr-enthusiasts
docker-shipfeeder
Shell

AIS feeder for ShipXplorer, VesselFinder, MarineTraffic, etc. based on AIS-Catcher. Multi-architecture (amd64, armhf, arm64)

Last updated Jul 8, 2026
90
Stars
6
Forks
0
Issues
+1
Stars/day
Attention Score
59
Language breakdown
No language data available.
Files click to expand
README

sdr-enthusiasts/docker-shipfeeder

Discord

What's New

So you came here expecting docker-shipxplorer? As of March 15, 2024 (the Ides of March!), the docker-shipxplorer repo has been renamed to docker-shipfeeder. The container can do so much more than just feeding ShipXplorer, and the new name covers the scope of what we're doing much better!

We're still enthusiastic feeders of AIS data to AirNav's ShipXplorer, and the amount of support that company has provided to the community is much appreciated. No changes there!

The newly updated container now also allows you to much easier configure feeding the other aggregators, see the Feeding AIS Aggregator Services section!

In adding all these improvements, we didn't forget our current users: the container is fully backwards compatible with the settings and environment variables you are already using. So no change is needed, unless you want to. We're also automatically producing two container images in parallel - they are exactly the same except for their names: ghcr.io/sdr-enthusiasts/docker-shipfeeder (new!) and ghcr.io/sdr-enthusiasts/shipxplorer (legacy).

If you need help, feel free to chat with us at the Discord server that is linked elsewhere in this Readme.

Table of Contents

- What's New - Table of Contents - Prerequisites - Multi Architecture Support - Up-and-Running with Docker Compose - Runtime Environment Variables - SDR and Receiver Related Variables - Website Related Parameters - Feeding AIS Aggregator Services - Easy sharing with other services - Exchanging data with aiscatcher.org - Configuring feeding to ShipXplorer - Obtaining a ShipXplorer Sharing Key - Claiming Your ShipXplorer Receiver - Adding Additional Command-line Parameters to sxfeeder - Workaround for CPU Serial (only needed when feeding ShipXplorer with non-Raspberry Pi systems) - Feeding Additional Services Using UDP - Feeding Additional Services Using TCP - Feeding Additional Services Using HTTP - Sending AIS data to a MQTT broker - Adding an About Page to the AIS-Catcher Website - Logging - AIS-Catcher Web Plugin Support and AIS-Catcher Persistency - Additional Statistics Dashboard with Prometheus and Grafana - Configuring 2 SDRs for Reception on Channels AB and CD - Aggregating multiple instances of the container - Hardware requirements - Working around ShipXplorer issues on Raspberry Pi 5 - Getting Help - Acknowledgements - License

Docker container for feeding many AIS aggregators, showing a local map with ships heard, etc. The container uses AIS-Catcher and also includes AirNav ShipXplorer's sxfeeder. Builds and runs on arm64, armv7/armhf, and amd64/x86.

Prerequisites

We expect you to have the following:

  • a piece of hardware that runs Linux. The prebuilt containers support armhf, arm64, and amd64. Systems with those architectures include Raspberry Pi 3B+, 4, and Linux PCs with Ubuntu.
  • a dedicated RTL-SDR dongle that can receive at 160 MHz, with an appropriate antenna
  • Docker must be installed on your system. If you don't know how to do that, please read here.
  • Some basic knowledge on how to use Linux and how to configure docker containers with docker-compose.

Multi Architecture Support

Currently, this image should pull and run on the following architectures:

  • arm32v7, armv7l, armhf: ARMv7 32-bit (Odroid HC1/HC2/XU4, RPi 2/3/4 32-bit)
  • arm64, aarch64: ARMv8 64-bit (RPi 4 64-bit OSes)
  • amd64, x86_64: X86 64-bit Linux (Linux PC)
Other architectures (Windows, Mac) are not currently supported, but feel free to see if the container builds and runs for these. In theory, it should work, but I don't have the time nor inclination to test it.

Up-and-Running with Docker Compose

You can find these as files here: docker-compose.yml example; .env example

<‐‐ Click the arrow to see the docker-compose.yml and .env examples

services:
  shipfeeder:
    image: ghcr.io/sdr-enthusiasts/docker-shipfeeder
    container_name: shipfeeder
    hostname: shipfeeder
    restart: always
    environment:

general parameters:

- VERBOSE_LOGGING=

ais-catcher general and website related parameters

- AISCATCHEREXTRAOPTIONS=${SXEXTRAOPTIONS} - STATIONNAME=${STATIONNAME} - STATION_HISTORY=3600 - BACKUP_INTERVAL=5 - FEEDERLONG=${FEEDERLONG} - FEEDERLAT=${FEEDERLAT} - SITESHOW=on - PROMETHEUS_ENABLE=on - REALTIME=on

ais-catcher receiver-related parameters

- RTLSDRDEVICESERIAL=${RTLSDRDEVICESERIAL} - RTLSDRDEVICEGAIN=${RTLSDRDEVICEGAIN} - RTLSDRDEVICEPPM=${RTLSDRDEVICEPPM} - RTLSDRDEVICEBANDWIDTH=${RTLSDRDEVICEBANDWIDTH} - AISCATCHERDECODERAFCWIDE=${AISCATCHERDECODERAFCWIDE}

aggregrators-related parameters

- AIRFRAMESSTATIONID=${AIRFRAMESSTATIONID} - AISCATCHERFEEDERKEY=${AISCATCHERFEEDERKEY} - AISFRIENDSUDPPORT=${AISFRIENDSUDPPORT} - AISHUBUDPPORT=${AISHUBUDPPORT} - APRSFIFEEDERKEY=${APRSFIFEEDERKEY} - BOATBEACONSHAREDATA=${BOATBEACONSHAREDATA} - HPRADARUDPPORT=${HPRADARUDPPORT} - MARINETRAFFICUDPPORT=${MARINETRAFFICUDPPORT} - MYSHIPTRACKINGUDPPORT=${MYSHIPTRACKINGUDPPORT} - RADARVIRTUELFEEDERKEY=${RADARVIRTUELFEEDERKEY} - RADARVIRTUELSTATIONID=${RADARVIRTUELSTATIONID} - SDRMAPSTATIONID=${SDRMAPSTATIONID} - SDRMAPPASSWORD=${SDRMAPPASSWORD} - SHIPFINDERSHAREDATA=${SHIPFINDERSHAREDATA} - SHIPPINGEXPLORERUDPPORT=${SHIPPINGEXPLORERUDPPORT} - SHIPXPLORERSHARINGKEY=${SHIPXPLORERSHARINGKEY} - SHIPXPLORERSERIALNUMBER=${SHIPXPLORERSERIALNUMBER} - VESSELFINDERUDPPORT=${VESSELFINDERUDPPORT} - VESSELTRACKERUDPPORT=${VESSELTRACKERUDPPORT} - UDPFEEDS=${SXUDP_FEEDS}

incoming UDP data related parameters:

- AISCATCHERUDPINPUTS=${AISCATCHERUDPINPUTS} ports: - 90:80 - 9988:9988/udp devicecgrouprules: - 'c 189:* rwm' tmpfs: - /tmp volumes: - "/etc/localtime:/etc/localtime:ro" - "/etc/timezone:/etc/timezone:ro" - "/opt/ais/shipxplorer/data:/data" - /dev:/dev:rw

Example accompanying .env file:

# ShipFeeder receiver and webpage related parameters:
FEEDER_LAT=xx.xxxxxx
FEEDER_LONG=yy.yyyyyy
RTLSDRDEVICESERIAL=DEVICE-SERIAL
RTLSDRDEVICEGAIN=xxx
RTLSDRDEVICEPPM=xxx
AISCATCHERDECODERAFC_WIDE=on
STATION_NAME=My&nbsp;Station&nbsp;Name
#

keys and params for aggregators:

If you aren't feeding a specific aggregator, leave the value EMPTY or remove the parameter

AIRFRAMESSTATIONID=XX-XXXXXXX-AIS AISCATCHERFEEDERKEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx AISFRIENDSUDPPORT=xxxxx AISHUBUDPPORT=xxxxx APRSFIFEEDERKEY=xxxxxxx APRSFISTATIONID=MYCALL BOATBEACON_SHAREDATA=true HPRADARUDPPORT=xxxxx MARINETRAFFICUDPPORT=xxxxx MYSHIPTRACKINGUDPPORT=xxxxx RADARVIRTUELFEEDERKEY=xxxxxxxxx RADARVIRTUELSTATIONID=xx SDRMAPSTATIONID=xxxxxx SDRMAP_PASSWORD=xxxxxx SHIPFINDER_SHAREDATA=true SHIPPINGEXPLORERUDPPORT=xxxxx SHIPXPLORERSHARINGKEY=xxxxxxxxxxxxxxxxxxx SHIPXPLORERSERIALNUMBER=SXTRPI00xxxx VESSELFINDERUDPPORT=xxxxx VESSELTRACKERUDPPORT=xxxxx

Replace these parameters with the appropriate values. You can use rtltest to see which devices and device serials are connected to your machine, or rtleeprom to rename the device's serial number.

Runtime Environment Variables

SDR and Receiver Related Variables

For backwards compatibility reasons the SDR related variables all have RTLSDR in their name, even though they apply to any supported SDR where that value makes sense.

| Environment Variable | Purpose | Default value if omitted | | ---------------------- | ------------------------------- | --- | | SDR_TYPE | RTLSDR or AIRSPY or SDRPLAY | RTLSDR | | RTLSDRDEVICESERIAL | Serial Number of your SDR dongle | Empty | | RTLSDRDEVICEGAIN | SDR device gain. Can also be set to auto (RTLSDR only) | 33 (RTLSDR) / 12 (AIRSPY) / 32 (SDRPLAY) | | RTLSDRDEVICEPPM| PPM deviation of your SDR device | Empty | | RTLSDRDEVICERTLAGC | Switches AGC on/off for your RTLSDR or SDRPLAY device. | on | | RTLSDRDEVICEBANDWIDTH | Channel bandwidth of the receiver | 192K | | RTLSDRDEVICEBIASTEE | If set to on, 1, enabled, or yes, the bias-tee function of the SDR device will be switched on (only Airspy and some RTLSDR devices) | Empty | | AISCATCHER_CHANNELS | Channels flag for ais-catcher. Set to AB (receive on channel AB, default value if omitted), CD (receive on channel CD), or CD AB (receive on channel CD but forward this data to aggregators saying it's channel AB; this can be used to send channels CD data to aggregators that can't handle CD data) | Empty (AB) | | AISCATCHERDECODERMODEL | Decoder model number for ais-catcher | 2 | | AISCATCHERDECODERAFCWIDE | -go AFCWIDE flag for ais-catcher. Recommended to set to on | on | | AISCATCHERDECODERFPDS | -go PFDS flag for ais-catcher | Empty | | AISCATCHERDECODERPSEMA | -go PSEMA flag for ais-catcher | Empty | | AISCATCHERDECODERSOXR | -go SOXR flag for ais-catcher | Empty | | AISCATCHERDECODERSRC | -go SRC flag for ais-catcher | Empty | | AISCATCHERDECODERDROOP | -go DROOP flag for ais-catcher | Empty | | AISCATCHERUDPINPUTS | List of comma-separated hostname:port[:CHANNELS] combinations of external NMEA AIS data UDP sources. You can use this to feed data between ais-catcher or docker-shipfeeder instances. The :CHANNELS part is optional; channels AB will be used if omitted. Examples
AISCATCHERUDPINPUTS=remotehost-1:9999:AB CD,remotehost-2:9988,remotehost-3:8899:CD | Empty | | AISCATCHEREXTRAOPTIONS | Any additional command line parameters you wish to pass to AIS-catcher | Empty | | VERBOSELOGGING | If set to a number (0-5), it's set to the AIS-Catcher -o log level. Any other non-empty string corresponds to -o 2. To silence AIS-Catcher logs, set this parameter to 0 | 2 (a summary is displayed every 60 seconds) |

If the AISCATCHERCHANNELS and AISCATCHERDECODERXXXX parameters listed above are set, they will overwrite/remove any equivalent parameters added to the AISCATCHEREXTRA_OPTIONS parameter.

Website Related Parameters

| Environment Variable | Purpose | Default value if omitted | | ---------------------- | ------------------------------- | --- | | DISABLE_WEBSITE | If set to true, the AIS-Catcher website will not be available | false | | PLUGINS_FILE | Load a file with custom javascript to override parts of the WebUI or add functionality. Map the container /data to any volume, place your file inside the volume and put the file name here (for example plugins.js) | Empty | | STYLES_FILE | Load a file with custom css to override parts of the WebUI or add functionality. Map the container /data to any volume, place your file inside the volume and put the file name here (for example styles.css) | Empty | | STATION_NAME | Station name displayed on stat web page | Empty | | STATION_LINK | URL displayed on stat web page | Empty | | STATION_HISTORY | The number of seconds of history that will be shown in plots on the website | 3600 | | BACKUPINTERVAL | How often a file with data statistics (aiscatcher.bin) will be written to disk, in minutes. In order to make this backup persistent, make sure to map the /data directory to a volume. See example in docker-compose.yml. | 2880 (=2 days) | | BACKUPRETENTIONTIME | Time (in days) to keep backups of aiscatcher.bin and plugins. Note - this only affects the backups of these files and not the active aiscatcher.bin or active plugins. | 30 (days) | | SITESHOW | If set to anything non-empty, it will show the station location as a dot on the map | Empty | | FEEDERLAT or SXFEEDERLAT (legacy) | Used for calculating ship distances on web page | Empty | | FEEDERLONG or SXFEEDERLON (legacy) | Used for calculating ship distances on web page | Empty | | DISABLE_SHOWLASTMSG | If set to true, the last NMEA0182 message option won't be shown on the website. | Empty, i.e., last message option is available on website | | PLUGINUPDATEINTERVAL | Optional. Set this to the interval (for example, 30 (secs) or 5m or 6h or 3d) to check the AIS-Catcher github repository for updates to the JavaScript web plugins. Set to 0 or off to disable checking. | 6h | | REFRESHRATE | Refresh rate of the vessel data on the web page, in msec. Larger numbers reduce web page traffic, which can become an issue if there are a large number of vessels | 2500 (msec) | | DISABLEGEOJSON | If set to true, no GeoJSON info will be available at aiscatcher/geojson>. This is normally enabled if the parameter is omitted. | Empty (GeoJSON is default enabled) | | ADSBCONNECTOR | Connect to a beast or raw1090 ADS-B data stream to show aircraft on your AIS map. Format: ADSBCONNECTOR=<format>,<hostname>,<port> where <format> is either beast or raw1090, and the <hostname> and <port> parameters indicate where the data comes from | Empty |

Feeding AIS Aggregator Services

Easy sharing with other services

This table shows which parameters to set and how to obtain credentials for a number of well-known AIS aggregators. A (partial) list of these aggregators and instructions on how to get a key or port for them can be found here

| Name | Parameter | Default IP/DNS/URL | Feeding protocol:
UDP/TCP/HTTP/Other | How to register for a key or ID | | ---- | --------- | ------------------ | --------------------------------------- | ------------------------------- | | ADSB-Network (RadarVirtuel) | RADARVIRTUELSTATIONID | STATION
ID> | HTTP | Use your station ID from your RadarVirtuel ADSB deployment for RADARVIRTUELSTATIONID. If you don't have a RadarVirtuel ADSB deployment, then Email with your request to join. If you receive an ais-catcher string like this: -H http://ais.adsbnetwork.com/ingester/insert/lourd ID xx INTERVAL 5 RESPONSE off, then simply set RADARVIRTUELSTATIONID to xx and ignore the rest | | Airframes | AIRFRAMESSTATIONID | http://feed.airframes.io:5599 | HTTP | No signup needed. AIRFRAMES
STATION_ID is a self-chosen ID that has the form of II-STATIONNAME-AIS, where II are the initials of the owner's name, and STATIONNAME is a self-chosen station name (A-Z, 0-9 only please) | | AIS-Catcher | AISCATCHERSHAREDATA=true
AISCATCHER
FEEDERKEY | | Other | See Exchanging data with aiscatcher.org https://aiscatcher.org/#join. In the future, AISCatcher may provide you with an optional UUID that you can set in AISCATCHERFEEDERKEY | | AIS Friends | AISFRIENDSUDPPORT | ais.aisfriends.com | UDP | Sign up at AIS Friends to receive a dedicated UDP port by email | | AISHub | AISHUBUDPPORT | data.aishub.net | UDP | https://www.aishub.net/join-us | | APRS.fi | APRSFIFEEDERKEY
APRSFI
STATIONID | http://aprs.fi/jsonais/post/$APRSFEEDERKEY | HTTP | Get AIS Password (APRSFIFEEDERKEY) at https://aprs.fi/?c=account. Use your Ham Radio callsign for APRSFISTATION_ID. Both fields are mandatory. | | BoatBeacon (aka Pocket Mariner)| BOATBEACONSHAREDATA=true or
BOATBEACON
UDPPORT or
BOATBEACON
TCPPORT | boatbeaconapp.com:5322 | UDP / TCP | https://pocketmariner.com/ais-ship-tracking/cover-your-area/set-up-and-ais-shore-station/ - set BOATBEACONSHAREDATA=true to feed without any key or assigned port, or set your assigned UDP or TCP port in the respective parameter | | HPRadar | HPRADARUDPPORT | aisfeed.hpradar.com | UDP | | | MarineTraffic | MARINETRAFFICUDPPORT or
MARINETRAFFICTCPPORT | 5.9.207.224 | UDP / TCP | https://www.marinetraffic.com/en/join-us/cover-your-area Please use either the UDP option or the TCP option as instructed by MarineTraffic, but don't use both! | | MyShipTracking | MYSHIPTRACKINGUDPPORT or
MYSHIPTRACKINGTCPPORT | 178.162.215.175 | UDP / TCP | https://www.myshiptracking.com/help-center/contributors/add-your-station By default, you should use UDP to feed, unless you are specifically asked to use TCP by the company. Do not use both! | | SDRMap | SDRMAPSTATIONID
SDRMAPPASSWORD | https://ais.feed.sdrmap.org/ | HTTP | See here for instructions to get your STATION_ID and PASSWORD: | | ShipFinder | SHIPFINDERSHAREDATA=true | ais.shipfinder.co.uk:4001 | UDP | https://shipfinder.co/about/coverage/ | | ShippingExplorer | SHIPPINGEXPLORERUDPPORT or
SHIPPINGEXPLORERTCPPORT | 144.76.54.111 | UDP or TCP | Request UDP port at https://www.shippingexplorer.net/en/contact By default, you should use UDP to feed, unless you are specifically asked to use TCP by the company. Do not use both! | | ShipXplorer | SHIPXPLORERSHARINGKEY or SHARINGKEY (legacy)
SHIPXPLORER
SERIALNUMBER or SERIALNUMBER (legacy) | | Other | See Obtaining a ShipXplorer Sharing Key | | ShipXplorer (alt. config with UDP) | SHIPXPLORERUDPPORT | hub.shipxplorer.com| UDP | Alternative way to feed ShipXplorer via UDP instead of via a Sharing Key. Please use one or the other, but not both! Sign up at https://www.shipxplorer.com/addcoverage and select "I want to share with: NMEA over UDP" | | VesselFinder | VESSELFINDERUDPPORT or
VESSELFINDERTCPPORT | ais.vesselfinder.com | UDP / TCP | https://stations.vesselfinder.com/become-partner By default, you should use UDP to feed, unless you are specifically asked to use TCP by the company. Do not use both! | | VesselTracker | VESSELTRACKERUDPPORT or
VESSELTRACKERTCPPORT | 83.220.137.136 | UDP or TCP| https://www.vesseltracker.com/en/static/antenna-partner.html By default, you should use UDP to feed, unless you are specifically asked to use TCP by the company |

Note: for all parameters SERVICEUDPPORT (and similarly for SERVICETCPPORT where supported), you may use one of the following formats:

  • - SERVICEUDPPORT=1234 --> use UDP port 1234
  • - SERVICEUDPPORT=hostname:1234 or - SERVICEUDPPORT=ip_addr:1234 --> use the hostname or ip address instead of the one indicated in the table, and UDP port 1234
For services that do not need any UDP ports or credentials, you can simply set - SERVICESHAREDATA=true. However, if you want to use a non-default port and/or hostname/ip, you can set also SERVICEUDP_PORT (as shown above) for that service. Order of preference:
  • if SERVICEUDPPORT is defined --> use this UDP port regardless of the value of SERVICE_SHAREDATA
  • if SERVICESHAREDATA is set to true and SERVICEUDP_PORT is not defined --> use the default UDP port to feed SERVICE
  • if SERVICETCPPORT is defined --> use this TCP port in addition to any UDP port (or SHAREDATA setting). Warning - this may cause duplicate feeding to the aggregator
We decided to allow parallel feeding to UDP and TCP ports because some aggregators have asked our users to do this temporarily for testing. However, the user should take caution not to feed duplicate data to any aggregator unless the aggregator specifically requested this for testing purposes.

Exchanging data with aiscatcher.org

aiscatcher.org is an exchange of AIS NMEA data. If you share your data with this server, you automatically receive data about other ships in return. We recommend to switch this on for an optimal viewing experience. You can enable it by simply adding the following to the environment section of your shipfeeder service section in docker-compose.yml. Note that the AISCATCHER_SHAREKEY parameter is optional and will be ignored for now, pending implementation of this feature by AIS-Catcher.

- AISCATCHER_SHAREDATA=true
  • AISCATCHER_SHAREKEY=xxxxxxxx

Configuring feeding to ShipXplorer

Obtaining a ShipXplorer Sharing Key

ATTENTION Raspberry Pi 5 users (only) should read Working around ShipXplorer issues on Raspberry Pi 5 before proceeding!

First-time users should obtain a ShipXplorer sharing key. In order to obtain a ShipXplorer sharing key, on the first run of the container, it will generate a sharing key and print this to the container log. If you can't find it, you can also copy and paste this command:

timeout 180s docker run \
    --rm \
    -it \
    --entrypoint /usr/bin/get-creds \
    ghcr.io/sdr-enthusiasts/docker-shipfeeder:latest

This will run the container for 3 minutes, allowing a sharing key to be generated. Shortly after, you will see something like this:

WARNING: SHARINGKEY or SERIALNUMBER environment variable was not set!
Please make sure you note down the keys generated and update your docker-compose.yml with these values.
Set environment var SHARING_KEY to the new key displayed below - this is the long hex number
Set environment var SERIAL_NUMBER to the Serial Number displayed below - this is the SXTRPIxxxxxx string
They must be set for this container to run.
Please set it and restart the container.

[2022-11-01 19:48:19] Your new key is f1xxxxxxxxxxxxxxxxxxxxxxxx57 and Serial Number (SN) is SXTRPIxxxxxx. Please save this key for future use. You will have to know this key to link this receiver to your account in https://www.shipxplorer.com/. This key is also saved in configuration file (/etc/sxfeeder.ini)

You can wait for the 3 minutes to pass, or you can press CTRL-C now to finish. Take a note of the Sharing Key (f1...57 - yours will be a different number) and the Serial Number (SXTRPIxxxxxx), and add these to the SHIPXPLORERSHARINGKEY and SHIPXPLORERSERIALNUMBER parameters of your docker-compose.yml file.

If you're not a first time user and are migrating from another installation, you can retrieve your sharing key by doing this:

  • SSH onto your existing receiver and run the command cat /etc/sxfeeder.ini
The key and sn lines show your current credentials

Claiming Your ShipXplorer Receiver

Once your container is up and running, you should claim your receiver.

  • Go to
  • Create an account or sign in
  • Claim your receiver by visiting and following the instructions
Note - you will need your SHARING_KEY and the location of your feeder (coordinates or pick on map). As of now, it appears that you don't need your SN or Public IP address.

Adding Additional Command-line Parameters to sxfeeder

sxfeeder is the binary component that is used to feed data to ShipXplorer. Normally, you don't have to interact with it, but exceptional circumstances may arise where you would like to add additional command line parameters to this program. You can do so, by adding them as follows:

| Environment Variable | Purpose | Default value if omitted | | --- | --- | --- | | SXFEEDEREXTRAOPTIONS | Any additional command line parameters you wish to pass to sxfeeder | Empty |

Workaround for CPU Serial (only needed when feeding ShipXplorer with non-Raspberry Pi systems)

The sxfeeder binary effectively greps for serial\t\t: in your /proc/cpuinfo file, to determine the RPi's serial number.

For systems that don't have a CPU serial number in /proc/cpuinfo, we can "fudge" this by generating a replacement cpuinfo file with a random serial number. To do this, copy and paste the following on your host machine:

sudo mkdir -m777 -p /opt/shipfeeder/cpuinfo
sudo install -m 666 /proc/cpuinfo /opt/shipfeeder/cpuinfo/
echo -e "serial\t\t: $(hexdump -n 8 -e '4/4 "%08X" 1 "\n"' /dev/urandom | tr '[:upper:]' '[:lower:]')" >> /opt/shipfeeder/cpuinfo/cpuinfo

You can now map this file into your container:

  • If using docker run, simply add -v /opt/shipfeeder/cpuinfo/cpuinfo:/proc/cpuinfo to your command.
  • If using docker-compose, add the following to the volumes: section of your shipfeeder container definition:
- /opt/shipfeeder/cpuinfo/cpuinfo:/proc/cpuinfo

Feeding Additional Services Using UDP

If you want to feed and additional AIS aggregator that uses a hostname/UDP port that is not listed above, then simply add a comma separated list of hostnames/ip addresses and UDP ports to the UDPFEEDS parameter. Format: UDPFEEDS=domain1.com:port1[:params],domain2,com:port2[:params],...

For example:

- UDP_FEEDS=1.2.3.4:9999,ais.aggregator.org:1234

Feeding Additional Services Using TCP

If you want to feed and additional AIS aggregator that uses a hostname/TCP port that is not listed above, then simply add a comma separated list of hostnames/ip addresses and UDP ports to the TCPFEEDS parameter. Format: TCPFEEDS=domain1.com:port1[:params],domain2,com:port2[:params],...

For example:

- TCP_FEEDS=1.2.3.4:8888,ais.aggregator.org:4321

Feeding Additional Services Using HTTP

To feed additional AIS aggregators that are not listed above using HTTP, you first need to create an AIS feeder account at that service. They will provide you with a URL and any additional parameters you need to configure AIS-Catcher. For example:

- AISCATCHEREXTRAOPTIONS=-H http://1.2.3.4/test ID mystationname INTERVAL 30 RESPONSE off

Note: if you want to feed multiple HTTP aggregators, you can simply append each feeder string to the AISCATCHEREXTRAOPTIONS variable with a space in between them. For example:

- AISCATCHEREXTRAOPTIONS=-H http://5.6.7.8/test/post/aBcDeFgHiJkL ID MYSTATION PROTOCOL aprs INTERVAL 30 RESPONSE off -H http://1.2.3.4/test ID mystationname INTERVAL 30 RESPONSE off JSON on

Sending AIS data to a MQTT broker

Shipfeeder supports sending AIS data to a MQTT broker. This is done by setting the MQTT broker's URL in the AISCATCHERMQTTURL parameter, and (optionally) adding values to the parameters listed below.

| Environment Variable | Purpose | Default value if omitted | | --- | --- | --- | | AISCATCHERMQTTURL | MQTT Broker's URL. This often has the format of mqtt://username:password@ipaddress:1883. When left empty, MQTT is disabled. Note - the ipaddress can be an IP Address or hostname that is resolved by the container. When using IP addresses, avoid using internal IP addresses like 128.0.0.1 because they point at the container itself. Instead, if your MQTT broker runs on your host system, use the IP address that is rendered when you do hostname -I \| awk '{print $1}' on the command line | Empty | | AISCATCHERMQTTCLIENTID | (Optional) CLIENTID value that is passed to the MQTT Broker. For example, aiscatcher. | Empty | | AISCATCHERMQTTQOS | (Optional) QOS (Quality of Service) value that is passed to the MQTT Broker. For example, 0. | Empty | | AISCATCHERMQTTTOPIC | (Optional) MQTT Topic that is passed to the MQTT Broker. For example, data/ais. | Empty | | AISCATCHERMQTTMSGFORMAT | (Optional) Message Format indicator for the messages passed to the MQTT Broker. The following values are supported: NMEA, NMEATAG, FULL, JSONNMEA, JSONSPARSE JSONFULL | JSON_FULL |

Note - if you want to configure ShipFeeder to receive AIS data from a MQTT broker, you can do this by adding (for example) the following to the AISCATCHEREXTRAOPTIONS parameter:

AISCATCHEREXTRAOPTIONS=-t mqtt://hostname:port -gt TOPIC data/ais USERNAME admin PASSWORD password

Adding an About Page to the AIS-Catcher Website

You can add an About page to the AIS-Catcher Website by placing a file called about.md in the /data directory of the container. If you mapped this directory to a volume as shown in the example, the file as seen from the host system would be /opt/ais/shipfeeder/about.md. You can format the text in this file using Markdown.

Logging

  • All processes are logged to the container's stdout, and can be viewed with docker logs [-f] container.

AIS-Catcher Web Plugin Support and AIS-Catcher Persistency

We recommend mapping a volume (as shown in the sample docker-compose.yml file in this repo) to the /data directory. This will ensure that AIS-Catcher data will persist across restarts and container recreation.

Web Plugins for AIS-Catcher can be placed in the /data/plugins directory.

Additional Statistics Dashboard with Prometheus and Grafana

See this readme for information on how to set up and configure a Grafana stats dashboard for use with shipfeeder. Make sure to set this parameter to enable Prometheus data for the container:

| Environment Variable | Purpose | Default value if omitted | | --- | --- | --- | | PROMETHEUS_ENABLE | If set to true, enables Prometheus data at /metrics on the webserver. | Empty (disabled) |

Configuring 2 SDRs for Reception on Channels AB and CD

If you want shipfeeder to use 2 SDRs to listen to AIS Channels AB and CD at the same time, you can do the following

  • Configure your first SDR (for use with channels AB) via the "normal" RTLSDRDEVICEXXXX parameters
  • Configure the second SDR using the AISCATCHEREXTRAOPTIONS parameter as follows (replace SDR2-SERIAL with the Serial Number of your second SDR):
- AISCATCHEREXTRAOPTIONS=-d SDR2-SERIAL -p 2 -a 192K -c CD -gr tuner auto rtlagc ON -v 60
  • Subsequently, you can also add separate web pages for each SDR individually. The "normal" web interface on port 80 will show the combined receivers, while the following adds new web interfaces on ports 81 for your Channels AB receiver, and on port 82 for your Channels CD receiver. You can add this to the end of the AISCATCHEREXTRAOPTIONS parameter, replacing SDR1SERIAL and SDR2SERIAL with the two serial IDs of the SDRs, and adjusting the other parameters as appropriate:
- AISCATCHEREXTRAOPTIONS=... -N 81 GROUPSIN 1 STATION SDR1-SERIAL FILE /data/aiscatcher-ab.bin PLUGINDIR /data/plugins BACKUP 5 HISTORY 3600 STATIONLINK https://my.ais-station.com LAT xx.xxxx LON yy.yyyy SHARELOC on MESSAGE on REALTIME on -N 82 GROUPSIN 2 STATION SDR2SERIAL FILE /data/aiscatcher-cd.bin PLUGINDIR /data/plugins BACKUP 5 HISTORY 3600 STATIONLINK https://my.ais-station.com LAT xx.xxxx LON yy.yyyy SHARE_LOC on MESSAGE on REALTIME on

Aggregating multiple instances of the container

Sometimes it's convenient to aggregate the data of multiple instances of the container into a single one, and then feed the AIS aggregators from this "central" instance. An example of this is when you have a SDR receiving from channels AB in one instance, and a SDR receiving from channels CD in a separate instance on another machine. (If you have both SDRs on the same machine, you can use a single container instance for both of them as described above). In our case, you'd want to send the data from channels CD to the instance that receives channels AB, and then use that machine to disperse the data to the various services, show its webpage, etc.

Do the following. We are assuming that the hostname/container name for the instance receiving channels AB is shipfeederab and the hostname/container name for the instance receiving channels CD is shipfeedercd. Your names may vary.

  • In the section of the docker-compose.yml file for shipfeedercd, make sure to add the following to the UDPFEEDS parameter. Make sure that you replace targetmachine with the IP or hostname of the machine where shipfeederab runs:
- UDPFEEDS=.....;targetmachine:9988
  • In the section of the docker-compose.yml file for shipfeederab, make sure to add the following to the AISCATCHERUDP_INPUTS parameter. (DO NOT USE localhost or 127.0.0.1 - that won't work):
- AISCATCHERUDPINPUTS=shipfeeder_cd:9988:AB CD
  • In addition, to the same section of the docker-compose.yml file for shipfeeder_cd, make sure to forward the UPD port to the container:
ports:
      [...]
      - 9988:9988/udp

Once you have done this, and after you recreate the containers, the shipfeedercd instance will now forward its data to shipfeederab, and shipfeeder_ab will aggregate this data, display it on the AIS-Catcher map and tables, and forward it to any service you may have configured for it.

Hardware requirements

AIS data is transmitted in the 160 MHz band, for which you'd need a suitable antenna. Note -- ADSB/UAT antennas will definitely not work! You would need a RTL-SDR dongle, potentially with an LNA, and potentially with a filter. The filter must be dedicated to the 160 MHz band. Dongles with built-in filters for the ADSB or UAT bands won't work. Last - the software will run on a Raspberry Pi 3B+ or 4, with Raspberry Pi OS, Ubuntu, or a similar Debian-based operating system. It will also run on X86 (Linux PC) systems with Ubuntu. The prebuilt Docker container will work on armhf/arm64 (aarch64) /x86_64 (amd64) architectures. You may be able to build containers for other systems, but for that you're on your own.

Working around ShipXplorer issues on Raspberry Pi 5

If you use ShipXplorer as recommended in Configuring feeding to ShipXplorer, the container internally uses a binary called sxfeeder to send data to the ShipXplorer service. This binary is provided as closed-source by AirNav (the company that operates ShipXplorer) and is only available in armhf (32-bits) format using 4kb kernel pages. This will work well on Raspberry Pi 3B+, 4B, and other ARM-based systems that use either 32-bits or 64-bits Debian Linux with a 4kb kernel page size.

Debian Linux for Raspberry Pi 5 uses by default a kernel with 16kb page sizes, and this is not compatible with the sxfeeder binary. You will see this in your container logs:

2024-05-23T23:15:48.998327000Z [2024-05-24 01:15:48.998][sxfeeder] Starting: /usr/bin/sxfeeder
2024-05-23T23:15:49.003069000Z [2024-05-24 01:15:49.002][sxfeeder] FATAL: sxfeeder cannot be run natively, and QEMU is not available. You cannot use this container
2024-05-23T23:15:49.004680000Z [2024-05-24 01:15:49.004][sxfeeder] FATAL: on this system / architecture. Feel free to file an issue at https://github.com/sdr-enthusiasts/docker-shipxplorer/issues
2024-05-23T23:15:49.006086000Z [2024-05-24 01:15:49.005][sxfeeder] FATAL: Cannot initiate feeder to ShipXplorer.

You can check your kernel page size with this command: getconf PAGE_SIZE . If the value returned is 4096, then all is good. If it is something else (for example 16384 for 16kb page size), you will need to implement one of the following work-arounds. You should implement either of them; it's not necessary to implement both:

  • Add the following to /boot/firmware/config.txt (Debian 12 Bookworm or later) or /boot/config.txt (Debian 11 Bullseye or earlier) to use a kernel with page size of 4kb. This will make CPU use across your Raspberry Pi 5 slightly less efficient, but it will solve the issue for many software packages that have the same issue. After changing this, you must reboot your system for it to take effect:
kernel=kernel8.img
  • Feed ShipXplorer with UDP instead of with a Sharing Key. To do this:
- Browse to https://www.shipxplorer.com/addcoverage and select "I want to share with: NMEA over UDP" - Follow the instructions until you are issued a hostname and UDP port number - set this environment variable in your docker-compose.yml file: SHIPXPLORERUDPPORT=portnumber (replace portnumber with the UDP port you were assigned) and remove SHIPXPLORERSHARINGKEY and/or SHARING_KEY from your configuration - recreate and restart the container with docker compose up -d

Getting Help

You can log an issue on the project's GitHub.

I also have a Discord channel, feel free to join and converse.

Acknowledgements

This effort wouldn't exist without much help and advice of the following individuals:

  • JvdE-Github, who created the excellent ais-catcher package which forms the basis of this container
  • Wiedehopf without whose advice we'd all still live in the stone age
  • John Norrbin for his ideas, testing, feature requests, more testing, nagging, pushing, prodding, and overall efforts to make this a high quality container and for the USB "hotplug" configuration
  • The community at the SDR-Enthusiasts Discord Server for helping out, testing, asking questions, and generally driving to make this a better productn
  • Pete who provided access and major help testing new features

License

Copyright (C) 2022-2025, Ramon F. Kolb (kx1t)

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .

🔗 More in this category

© 2026 GitRepoTrend · sdr-enthusiasts/docker-shipfeeder · Updated daily from GitHub