# AIS

At the end you have your own live map of the ships near you, decoded in your house from 161.975 and 162.025 MHz. You can also send what you hear to the public tracking networks, if you choose to.

Spurious Emissions · Rev B · checked 2026-10-21 · https://spurious-emissions.net/guides/receive-ais/

Some links are affiliate links: if you buy through them, I may earn a commission at no extra cost to you. As an Amazon Associate I earn from qualifying purchases.

## 1. What this guide builds

One antenna, one USB radio and one small computer. The computer decodes the position reports that ships broadcast, and it draws them on a map in your browser. Every program in this guide is free and open source.

| Item | In this guide |
|---|---|
| Signal | AIS (Automatic Identification System): ships broadcast their identity, position, speed and course |
| Frequency | 161.975 MHz (channel A) and 162.025 MHz (channel B), marine VHF |
| Antenna | A vertical antenna for the marine band, tuned near 162 MHz |
| Radio | An RTL-SDR dongle (lowest cost), or an Airspy Mini ◆ |
| Decoder | AIS-catcher, alone or in the shipfeeder container ◆ |
| Computer | One Raspberry Pi, or any small Linux computer |

A part or a path marked ◆ is what I use.

```
 outside                      cable entry                          home network
 -------                      -----------                          ------------
 marine-band vertical         [FM filter, optional]
 as high as you can --------- radio (USB) ---------- computer `pi`
 put it, in view of           RTL-SDR dongle         AIS-catcher
 the water                    or Airspy Mini            |-- your ship map (browser)
                                                        |-- NMEA sentences (text)
                                                        `-- optional: tracking networks
```

There are two ways to run the decoder. Choose one.

- **Path A: AIS-catcher in the shipfeeder container** ◆ (section 7). The container holds the decoder, the map and one setting for each tracking network. It needs Docker.
- **Path B: AIS-catcher alone** (section 8). One install command, no Docker. I do not run this path.

### If you live far from salt water

Read this before you buy anything. AIS is a line-of-sight signal. The AIS-catcher documents say it plainly: far inland, even a perfect station has nothing to hear. A large ship must be within about 25 to 30 km of a rooftop antenna, with no hill between you.

Check first. It costs nothing.

1. Open a public ship map, for example <https://aiscatcher.org/livemap> or <https://www.marinetraffic.com>.
2. Find your house on the map.
3. Look for ships within 25 km. Look again at a different time of day.
4. Count the ships that move. A large river, a canal or a large lake with commercial traffic also counts.

If the map shows no ship within 25 km, do not buy the parts for AIS. If it shows ships, and high ground stands between you and the water, expect little. If you already own an RTL-SDR dongle, do sections 5 to 9 with any antenna at a window before you buy an antenna.

## 2. What you need

Prices are US dollars, as listed by the named seller on 2026-10-07. They change. A part marked ◆ is what I use. A blank box is for your pencil.

### What I use

| ☐ | Part | Job | Connector | Price | Note |
|---|---|---|---|---|---|
| ☐ | ◆ [AIS-band vertical](https://www.amazon.com/dp/B09374SM2V?tag=spuriousemiss-20), tuned near 162 MHz | Antenna | See listing | See listing | A low-cost one is enough to start[^ais-ant] |
| ☐ | ◆ [Nooelec Flamingo FM](https://www.amazon.com/dp/B079CNCR8V?tag=spuriousemiss-20), over 40 dB typical | Blocks FM broadcast stations | SMA | See listing, Amazon | Optional[^fm-ais] |
| ☐ | ◆ [Airspy Mini](https://airspy.com/airspy-mini/), 24 to 1700 MHz, 12-bit | Radio | SMA | $99, airspy.us (out of stock that day) | |
| ☐ | ◆ [Raspberry Pi 5](https://www.amazon.com/dp/B0CK2FCG1K?tag=spuriousemiss-20), 8 GB | Computer | USB | $175 list (4 GB: $110) | Far more than AIS needs. Mine also runs other decoders |
| ☐ | Raspberry Pi 27 W USB-C power supply | Power for the computer | USB-C | See seller | |
| ☐ | microSD card, 32 GB or more | Storage | | See seller | |

### The lowest-cost path

| ☐ | Part | Job | Price | What it gives up |
|---|---|---|---|---|
| ☐ | An RTL-SDR dongle: [RTL-SDR Blog V4L](https://www.rtl-sdr.com/buy-rtl-sdr-dvb-t-dongles/) or [Nooelec NESDR SMArt v5](https://www.nooelec.com/store/nesdr-smart-sdr.html) | Radio | V4L: $37.95, rtl-sdr.com. SMArt v5: see listing | 8-bit samples, not 12-bit. Strong signals may overload it sooner. Read the note[^v4l] |
| ☐ | The telescopic antenna that comes with many RTL-SDR kits, extended to 44 cm | Antenna for a first test | With the kit | Range. It stands at a window, not on the roof |
| ☐ | A Raspberry Pi 3, 4 or Zero 2 W that you already own | Computer | | Nothing for AIS alone[^small-pi] |
| ☐ | No FM filter | | | Nothing, unless a strong FM station is close (section 4) |

The AIS-catcher documents put a complete station at roughly 60 EUR. I did not price that list. An RTL-SDR dongle receives both AIS channels at once, and so does the Airspy Mini. I use the Airspy Mini because I owned it.[^rtl-only]

### Cable and small parts

| ☐ | Part | Job |
|---|---|---|
| ☐ | 50 ohm coax to suit the antenna's connector, with an SMA plug at the radio end | Antenna to radio. Keep it short (section 4) |
| ☐ | One short SMA plug-to-plug jumper | Filter to radio, if you fit the filter |
| ☐ | A short USB extension cable | Keeps the radio away from the computer's own noise |
| ☐ | ◆ Stick-on aluminum heat sink, 50 x 25 x 10 mm ([mine](https://www.amazon.com/dp/B08QM84KPZ?tag=spuriousemiss-20), a pack of two) | Optional. My own addition, not part of the dongle as sold. I put one on most of my radios, because they run warm |
| ☐ | A grounding block and bonding wire | Where the cable enters the house (section 4) |
| ☐ | A mast, a bracket or a clamp for the antenna | See the antenna's listing |

Do not buy an amplifier at the start. Section 13 says why.

## 3. Before you start

**Skills.** You install an operating system on a memory card. You type commands in a terminal over SSH (a text connection to another computer). You edit one or two text files. You mount an antenna outdoors.

**Time.** About one hour for the computer and the software. The antenna takes as long as your roof asks for.

**Accounts.** None for your own map. One for each tracking network that you feed (section 10).

**Values to choose first.** Write these down. The steps use them as placeholders.

| Placeholder | Meaning | Example form |
|---|---|---|
| `<LAT>` `<LON>` | Antenna position, decimal degrees. The map uses it only to compute the distance to each ship | `xx.xx` |
| `<NAME>` | A station name with no personal detail | `my-station` |
| `<SER_AIS>` | The serial number of your radio | `162`, or 16 hexadecimal characters on an Airspy |

**The law, in short.** I am not a lawyer. This is what I read, for the United States. This guide only receives. US law (47 U.S.C. section 605) limits what a person may pass on from a radio message that is not meant for the public. AIS is a broadcast that a ship makes for every station in range. The AIS-catcher project says that the rules differ by country, and that you must check your own. Each tracking network also has terms for the data it gives back to you.

> **Warning.** A map made from a hobby receiver can be wrong or late. Do not use it to navigate a boat or to make a safety decision. The AIS-catcher project says the same.

> **Caution.** Marine VHF is a transmit band for ships. This station is receive-only. Never connect this antenna to a transmitter on these frequencies.

## 4. The antenna and the radio-frequency chain

Build the chain in this order, antenna first.

```
 AIS vertical -- coax -- [FM filter, optional] -- radio -- USB -- computer
```

### Choose the antenna

Use a vertical antenna. The AIS-catcher documents say that any antenna tuned for the marine VHF band works. A quarter wavelength at 162 MHz is about 44 cm.

- **To test:** the telescopic antenna of an RTL-SDR kit, extended to 44 cm, at a window that faces the water.
- **To keep:** an AIS-band or marine VHF vertical, outdoors. Mine is a low-cost one.
- **Do not use** a 1090 MHz aircraft antenna. The shipfeeder project says it will not work.

### Put it high, in view of the water

Height matters more than any part on the list. At these frequencies the signal travels in a straight line. The curve of the earth hides a ship that is too far away. The AIS-catcher documents give this estimate, with both antenna heights in meters:

```
 distance to the radio horizon, km  =  4.12 x ( sqrt(h1) + sqrt(h2) )
```

For a large ship with its antenna about 15 m above the water, the same documents give this table.

| Your antenna height | Radio horizon |
|---|---|
| 2 m, a window sill | about 22 km (12 nautical miles) |
| 5 m, a rooftop | about 25 km (14 nautical miles) |
| 10 m, a mast on the roof | about 29 km (16 nautical miles) |
| 20 m, an apartment building | about 34 km (19 nautical miles) |
| 50 m, a hill or a tower | about 45 km (24 nautical miles) |

A hill or a building between you and the water blocks the signal. No amplifier fixes that.

My own numbers: with a small whip indoors, the station heard about 5 messages a minute. The same radio and program heard about 30 a minute with a low-cost antenna on the roof.

### Keep the coax short

Coax loses signal with every meter. A loss of 3 dB halves the power that reaches the radio. The AIS-catcher documents give these losses for 10 m of cable near 160 MHz.

| Cable | Loss in 10 m |
|---|---|
| RG-58 | about 2.0 dB |
| RG-8X | about 1.5 dB |
| RG-213 | about 0.9 dB |
| LMR-400 | about 0.5 dB |

The better plan is to put the computer and the radio where the antenna cable enters the house. Then run network cable from there. Network cable loses nothing.

### The FM broadcast filter

An FM band-stop filter removes 88 to 108 MHz and passes the rest. A strong FM broadcast station can overload a wide-open radio, and then the radio hears weak ship signals badly. The filter goes between the coax and the radio.

On my station the filter changed nothing: the message rate was the same with it and without it. I left it in as cheap protection. Start without it. Add it if section 13 points to overload.

### Ground the cable

> **Warning.** An outdoor antenna and its cable can carry a lightning surge into the house. Give the cable a path to ground where it enters the building, before you connect the radio.

In the US the rule is National Electrical Code Article 810. Bond the grounding block to the building's own grounding electrode system. If you add a ground rod, bond it to that system with 6 AWG copper or heavier. Never use a rod that stands alone: a surge then goes through your equipment. I read a published summary of the rule, not the code text.[^nec] Use a licensed electrician if you are not sure.

### Connect the chain

1. Mount the antenna vertical, as high as you safely can.
2. Run the coax to the cable entry and through the grounding block.
3. Connect the coax to the FM filter, if you use one.
4. Connect the filter, or the coax, to the antenna socket of the radio.
5. Do not connect the radio to the computer yet. Section 6 does that.

Keep the bias tee off. A bias tee is a switch in the radio that puts DC on the antenna cable to power an amplifier. This chain has no amplifier. Both programs in this guide leave it off by default.

## 5. The computer

These steps are for a Raspberry Pi. Any 64-bit ARM or x86 computer with a Debian-based Linux follows the same steps from step 2. The computer has the name `pi` in this guide.

1. Write Raspberry Pi OS Lite (64-bit) to the card with Raspberry Pi Imager. In the Imager settings, set the host name to `pi`, turn SSH on, and add your public key.
2. Start the computer on your network. Log in with SSH.
3. Update the system.

   ```bash
   sudo apt update && sudo apt full-upgrade -y && sudo reboot
   ```

   Result: the computer restarts. Log in again.

I use wired Ethernet. AIS has no timing need like the aircraft networks have, so Wi-Fi may be enough. I did not test it.

If your browser cannot find the name `pi` later, use `pi.local` or the computer's address in its place.

## 6. Connect the radio and find its serial number

The decoder finds the radio by its serial number. With one radio this still matters: in Path A, the container applies its gain and bandwidth settings only when the serial number is set.

### For Path A (the container): install Docker first

Docker runs a program in a container: a sealed package that holds the program and everything it needs.

1. Install Docker with the sdr-enthusiasts script. It also stops the kernel's TV drivers from taking an RTL-SDR dongle.

   ```bash
   bash <(curl -s https://raw.githubusercontent.com/sdr-enthusiasts/docker-install/main/docker-install.sh)
   sudo reboot
   ```

2. Check Docker and the driver block.

   ```bash
   docker compose version
   cat /etc/modprobe.d/exclusions-rtl2832.conf      # expect 9 "blacklist" lines
   lsmod | grep -c dvb_usb_rtl28xxu                 # expect 0
   ```

   Result: a version number, nine lines that start with `blacklist`, and `0`.

### An RTL-SDR dongle, Path A

1. Plug the RTL-SDR dongle into the computer. Use the short USB extension cable.
2. Write the serial number `162` to it.

   ```bash
   docker run --rm -it --device /dev/bus/usb --entrypoint rtl_eeprom \
     ghcr.io/sdr-enthusiasts/docker-adsb-ultrafeeder -s 162
   ```

   Result: the tool shows the old and the new settings and asks you to confirm.

3. Change only the serial number. Do not change the maker or product text on an RTL-SDR Blog dongle: its driver looks for that text.
4. Unplug the RTL-SDR dongle and plug it in again. A restart of the computer does not load the new serial number.

Your `<SER_AIS>` is `162`. This command comes from the aircraft part of my station. It downloads a large aircraft image only to borrow one tool.

### An Airspy Mini ◆

1. Plug the Airspy Mini into the computer.
2. Install the Airspy tools and read the factory serial number.

   ```bash
   sudo apt install -y airspy
   airspy_info | grep -i serial
   ```

   Result: one line with 16 hexadecimal characters. That is `<SER_AIS>`.

### Any radio, Path B

Path B installs AIS-catcher on the computer itself. AIS-catcher then lists the radios and their serial numbers. Section 8 has the command.

## 7. Path A: AIS-catcher in the shipfeeder container ◆

Program: [docker-shipfeeder](https://github.com/sdr-enthusiasts/docker-shipfeeder), which runs [AIS-catcher](https://github.com/jvde-github/AIS-catcher). This is what I run. The project lists the Raspberry Pi 3B+ and 4 and Linux PCs. Mine runs on a Raspberry Pi 5.

1. Make the project folder.

   ```bash
   sudo mkdir -p -m 777 /opt/station && cd /opt/station
   ```

2. Create `/opt/station/.env` with your values.

   ```ini
   FEEDER_LAT=<LAT>
   FEEDER_LONG=<LON>
   FEEDER_NAME=<NAME>
   AIS_SDR_SERIAL=<SER_AIS>
   ```

3. Create `/opt/station/docker-compose.yml`. This file is for an Airspy Mini.

   ```yaml
   services:
     shipfeeder:
       image: ghcr.io/sdr-enthusiasts/docker-shipfeeder
       container_name: shipfeeder
       hostname: shipfeeder
       restart: unless-stopped
       environment:
         - SDR_TYPE=AIRSPY
         - RTLSDR_DEVICE_SERIAL=${AIS_SDR_SERIAL}
         - STATION_NAME=${FEEDER_NAME}
         - FEEDER_LAT=${FEEDER_LAT}
         - FEEDER_LONG=${FEEDER_LONG}
       ports:
         - 90:80
       device_cgroup_rules:
         - "c 189:* rwm"
       tmpfs:
         - /tmp
       volumes:
         - /opt/station/shipfeeder/data:/data
         - /dev:/dev:rw
   ```

4. For an RTL-SDR dongle, delete the line `- SDR_TYPE=AIRSPY`. The container then expects an RTL-SDR dongle.
5. Leave `SITESHOW` out of the file. When it is set, the map shows your station as a dot.
6. Start the container.

   ```bash
   cd /opt/station && docker compose up -d
   ```

   Result: Docker downloads the image, then prints `Started` for `shipfeeder`.

7. Check that the decoder opened the correct radio.

   ```bash
   docker logs shipfeeder 2>&1 | grep "Starting:"
   docker logs shipfeeder 2>&1 | grep "Searching for device"
   ```

   Result: the first line shows the full AIS-catcher command, with `-d <SER_AIS>`. The second line names `<SER_AIS>`.

8. Open `http://pi:90/` in a browser on your network.

   Result: the AIS-catcher web page, with a map. Section 9 says what you see next.

Facts to know:

- **The setting names say `RTLSDR`** for every kind of radio. `RTLSDR_DEVICE_SERIAL` is correct for an Airspy Mini when `SDR_TYPE=AIRSPY`.
- **Gain.** I leave `RTLSDR_DEVICE_GAIN` unset. The container then uses 12 on an Airspy (its "linearity" scale, 0 to 21). For an RTL-SDR dongle its default is a fixed gain near 33 dB, and `auto` is also accepted.
- **Filter width.** The container sets a 192 kHz tuner filter and the decoder option that tolerates frequency drift. Both are its defaults.
- **Your data stays at home** with this file. Nothing leaves your network until section 10.
- **Statistics survive a restart.** The folder `/opt/station/shipfeeder/data` holds them.

## 8. Path B: AIS-catcher alone

No Docker. One script installs AIS-catcher and a background service on a Debian-based system or on Fedora. I do not run this path. Every command here is from the AIS-catcher documents, read on 2026-10-10.

The project now recommends its "managed mode": you configure the station in a browser page at `8118`. This guide uses the older "manual mode", because its documents give exact commands.

1. Install the ready-made package in manual mode.

   ```bash
   sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/jvde-github/AIS-catcher/main/scripts/aiscatcher-install) -p"
   ```

   Result: the script installs the program and a service named `ais-catcher.service`.

2. Stop the service for the first tests. Only one program can hold the radio.

   ```bash
   sudo systemctl stop ais-catcher.service
   ```

3. Plug in the radio. List the radios that AIS-catcher can see.

   ```bash
   AIS-catcher -l
   ```

   Result: one line for each radio, with its serial number. That is `<SER_AIS>`.

4. Run the decoder on the screen, with a statistics line every 10 seconds.

   ```bash
   AIS-catcher -d <SER_AIS> -v 10
   ```

   Result: near ships, lines that start with `!AIVDM` appear. Press Ctrl+C to stop.

5. Run the decoder with its web page.

   ```bash
   AIS-catcher -d <SER_AIS> -N 8100
   ```

   Result: the ship map is at `http://pi:8100/`. Press Ctrl+C to stop.

6. Make the settings permanent. Open the settings file of the service.

   ```bash
   sudo nano /etc/AIS-catcher/config.cmd
   ```

7. Enter your settings. A line that starts with `#` is a comment.

   ```
   -d <SER_AIS>
   -N 8100 station <NAME> lat <LAT> lon <LON>
   ```

8. For an RTL-SDR dongle, add the line that the project calls a good starting point.

   ```
   -gr RTLAGC on TUNER auto -a 192K
   ```

9. Do not add `share_loc on` to the `-N` line. With it, the map shows your station.
10. Start the service, and make it start with the computer.

    ```bash
    sudo systemctl enable ais-catcher.service
    sudo systemctl start ais-catcher.service
    sudo systemctl status ais-catcher.service
    ```

    Result: the status shows `active (running)`. The map is at `http://pi:8100/`.

Facts to know:

- A second settings file, `/etc/AIS-catcher/config.json`, takes precedence over `config.cmd`. If your settings have no effect, look there.
- For an Airspy Mini, the gain option is `-gm`, for example `-gm linearity 17`. The value 17 is the program's default.
- To update, run the install command again. The project says it keeps your settings files.

## 9. The first signal, and how to read it

### The map

Open the web page: `http://pi:90/` in Path A, `http://pi:8100/` in Path B.

1. Wait. Near busy water, the first ships arrive within minutes.
2. Click a ship. A card opens with its identity number, speed, course and the strength of its last message.
3. Wait up to six minutes for the name. A ship sends its position every few seconds, and its name only every six minutes.
4. Open the statistics page from the menu at the top left. It counts messages on each channel and shows the farthest ship.

A ship with no heading shows as a circle. That is common for small boats.

### See the raw text

AIS-catcher writes each good message as one line of text. The format is called NMEA.

- **Path B:** stop the service, then run `AIS-catcher -d <SER_AIS> -n`.
- **Path A:** add the line `- VERBOSE_LOGGING=1` under `environment:`. Run `docker compose up -d`. Then run `docker logs -f shipfeeder`. Remove the line when you are done, or the log grows fast.

### Read one NMEA sentence

This is the example from the AIS-catcher documents.

```
!AIVDM,1,1,,B,33L=LN051HQj3HhRJd7q1W=`0000,0*03
```

| Field | In the example | Meaning |
|---|---|---|
| 1 | `!AIVDM` | A message received from another ship |
| 2 | `1` | The message has one sentence |
| 3 | `1` | This is sentence number one |
| 4 | (empty) | An ID that ties the sentences of a long message together |
| 5 | `B` | The radio channel: B is 162.025 MHz |
| 6 | `33L=LN05...` | The payload: the bits of the message, six bits in each character |
| 7 | `0` | The number of fill bits at the end of the payload |
| after `*` | `03` | The checksum: all characters between `!` and `*`, combined with XOR, in hexadecimal |

To get six bits from one payload character, take its ASCII value and subtract 48. If the result is more than 40, subtract 8 more. The first character here is `3`. Its ASCII value is 51, so the bits are `000011`. That is the number 3.

The payload has 28 characters, so it has 168 bits. Those are the 168 data bits that the episode shows. The checksum in this sentence protects the line of text. The 16-bit checksum that the ship sent by radio was checked earlier by AIS-catcher and is not in the sentence.

| Bits | Length | Field | In the example |
|---|---|---|---|
| 0 to 5 | 6 | Message type. Types 1, 2 and 3 are position reports | 3 |
| 8 to 37 | 30 | MMSI, the ship's identity number | 230907000 |
| 38 to 41 | 4 | Navigation status | 0, under way using engine |
| 50 to 59 | 10 | Speed, in steps of 0.1 knot | 8.8 knots |
| 61 to 88 | 28 | Longitude, in 1/10000 minute | 24.91524 degrees east |
| 89 to 115 | 27 | Latitude, in 1/10000 minute | 60.14811 degrees north |
| 116 to 127 | 12 | Course, in steps of 0.1 degree | 231.0 degrees |
| 128 to 136 | 9 | Heading. 511 means "not available" | 230 degrees |

I decoded the example by these rules on the check date. The values match the decode in the AIS-catcher documents. The layout is from the gpsd project's AIVDM reference, the best plain-language source I know.

The first three digits of an MMSI give the country. The codes 366 to 369 are United States codes. The ship's name, callsign, size and destination come in message type 5. That message has 424 bits, so it fills two sentences.

## 10. Feed the tracking networks (optional)

> **Your position becomes public.** Most tracking networks show their feeder stations on a map. A network may ask for your position when you sign up. The ships you report also show where you are, to within your range. Choose a station name that does not name you or your street. If this is not acceptable to you, stop here: your own map needs none of this.

A tracking network collects the messages of many home stations and draws one public map. I feed five: aiscatcher.org, MarineTraffic, AISHub, VesselFinder and ShipXplorer. Some of them give a paid-level account in return. Decode once, then share with many.

| Network | Setting in Path A | Where to sign up |
|---|---|---|
| aiscatcher.org | `AISCATCHER_SHAREDATA=true` | Nothing to do. An account and a key are optional: <https://aiscatcher.org> |
| MarineTraffic | `MARINETRAFFIC_UDP_PORT` | <https://www.marinetraffic.com/en/join-us/cover-your-area> |
| AISHub | `AISHUB_UDP_PORT` | <https://www.aishub.net/join-us> |
| VesselFinder | `VESSELFINDER_UDP_PORT` | <https://stations.vesselfinder.com/become-partner> |
| ShipXplorer | `SHIPXPLORER_UDP_PORT` | <https://www.shipxplorer.com/addcoverage>, choose "NMEA over UDP" |

The shipfeeder README lists more networks in the same form.

### Path A

1. Add the sharing line for aiscatcher.org under `environment:` in the compose file.

   ```yaml
         - AISCATCHER_SHAREDATA=true
   ```

2. Sign up with each other network. Each one sends you a host name and a number.
3. Add one line for each network, with what it sent you.

   ```yaml
         - MARINETRAFFIC_UDP_PORT=<host>:<number>
         - AISHUB_UDP_PORT=<host>:<number>
         - VESSELFINDER_UDP_PORT=<host>:<number>
         - SHIPXPLORER_UDP_PORT=<host>:<number>
   ```

   The number alone is also accepted. The container then uses the network's usual host.

4. Apply the change.

   ```bash
   cd /opt/station && docker compose up -d
   docker logs shipfeeder 2>&1 | grep "Starting:"
   ```

   Result: the command line now holds one `-u <host> <number>` for each network, and `-X` for aiscatcher.org.

5. Check your station page on each network.

Two rules from the shipfeeder README:

1. Use UDP unless the network tells you to use TCP. Never set both for one network: it would receive every message twice.
2. For ShipXplorer on a Raspberry Pi 5, use the UDP method above. Its sharing-key program does not run on the standard Pi 5 kernel (section 13).

Keep the compose file private. It holds the values that identify your station to each network.

### Path B

1. Open `/etc/AIS-catcher/config.cmd`.
2. Add `-X` to share with aiscatcher.org. With no key after it, the sharing is anonymous.
3. Add one line for each other network, with the host name and the number that it sent you.

   ```
   -X
   -u <host> <number>
   -u <host> <number>
   ```

4. Restart the service with `sudo systemctl restart ais-catcher.service`.

## 11. Run it unattended

- **Path A** starts by itself. The line `restart: unless-stopped` starts the container after a crash and after a restart of the computer.
- **Path B** starts by itself after `sudo systemctl enable ais-catcher.service`.
- **Update Path A** with `cd /opt/station && docker compose pull && docker compose up -d`.
- **Update Path B** with the install command of section 8.
- **Write down a baseline.** After one normal day, note the messages a minute, the ships in a day and the farthest ship. Change one thing at a time, and compare with it.

## 12. Check that it works

| # | Check | Where | Pass | How long to wait |
|---|---|---|---|---|
| 1 | The container runs | `docker ps --filter name=shipfeeder` (Path A) | Status `Up` | 1 minute |
| 2 | The service runs | `sudo systemctl status ais-catcher.service` (Path B) | `active (running)` | 1 minute |
| 3 | The correct radio is open | `docker logs shipfeeder 2>&1 \| grep "Searching for device"` (Path A) | Names `<SER_AIS>` | 1 minute |
| 4 | Ships on the map | The web page | One ship or more | Minutes near busy water |
| 5 | Both channels carry messages | The statistics page | Counts on channel A and on channel B | 10 minutes |
| 6 | Names appear | Click a ship | A name, not only a number | 6 minutes or more |
| 7 | The frequency is correct | The ship card, "Drift" | Between -3 and +3 ppm | 10 minutes |
| 8 | The range is sensible | The statistics page | Near the table in section 4 for your height | One day |

For comparison, my station: about 30 messages a minute, more than a hundred vessels in a day, and a farthest ship at 10 to 15 nautical miles. My antenna is on a roof in the Puget Sound, and the fast ships here are the state ferries. Most of the other vessels are small boats.

My range is shorter than the table's best case. Ships and antennas sit low, so the horizon is close. Small boats also transmit with 2 to 5 watts, and a large ship with 12.5 watts. So a small boat drops off the map sooner than a ferry.

## 13. If it does not work

| Symptom | Likely cause | What to do |
|---|---|---|
| No ships, ever, and public maps show none near you | There is nothing to hear | Read "If you live far from salt water" in section 1 |
| No ships, but public maps show ships within 25 km | The antenna is indoors, low, or behind high ground | Move it outdoors and up. This raised my rate about six times |
| `usb_claim_interface error -6`, "Device or resource busy" | The kernel's TV driver took the RTL-SDR dongle | Path A: check step 2 of section 6, then restart the computer |
| "Device or resource busy" in Path B | The service and your test both want the radio | `sudo systemctl stop ais-catcher.service` before a test |
| The log repeats "cannot open device" | A wrong serial number, or another program holds the radio | Check `<SER_AIS>`. If you own two Airspy radios, give every decoder its radio's serial number |
| An RTL-SDR Blog V4L opens and decodes nothing | A driver older than August 2026 does not know its tuner | Path A: `docker compose pull && docker compose up -d`. Path B: read section 15 |
| Few messages, and the ship card shows a drift beyond 3 ppm | The oscillator of a low-cost RTL-SDR dongle is off frequency | Path A: set `RTLSDR_DEVICE_PPM`. Path B: add `-p` and the value |
| Few messages, and a strong FM station is near | Overload | Fit the FM filter. On an RTL-SDR dongle, also try a lower fixed gain |
| Fewer messages after you add an amplifier | The strong signals now overload the radio, and the weak ones are lost | Remove it. On my station an amplifier halved another feed |
| The gain setting has no effect in Path A | `RTLSDR_DEVICE_SERIAL` is empty | Set it. The container adds its radio settings only with a serial number |
| Path B loses data on a slow computer | The USB data rate is too high for it | Add `-F`. If that is not enough, add `-s 288K`, which costs some reception |
| The ShipXplorer key program stops at once on a Pi 5 | It needs 4 kB memory pages. `getconf PAGE_SIZE` shows 16384 | Use the UDP method. Or add `kernel=kernel8.img` to `/boot/firmware/config.txt` and restart |
| Your station shows as a dot on your own map | `SITESHOW` is set (Path A) or `share_loc on` (Path B) | Remove the setting |
| A ship appears far inland or far out of range | A damaged message passed the checksum by chance | Ignore it. The ship card marks it as not validated |

## 14. What I did wrong

- **I started with the antenna indoors.** A small whip in the room heard about 5 messages a minute. A low-cost vertical on the roof heard about 30. I should have gone to the roof first.
- **I bought the filter before I had a problem.** The FM filter did not change my message rate. It is still in the chain, as protection.
- **I trusted "the first radio".** I own two Airspy radios, and both report the same USB identity. A decoder with no serial number opened the wrong one, and another feed stopped. Every decoder on my station now has its radio's serial number.
- **I thought about an amplifier first.** On another feed of my station, an amplifier cut the messages by half. Height is the gain that works.

## 15. Not run and not confirmed

- **Path B, all of it.** I run AIS-catcher only inside the shipfeeder container. The commands in section 8 are from the AIS-catcher documents. I did not run them.
- **The layout of `config.cmd`.** The documents say that the file holds command line options and that `#` starts a comment. They show no complete example. One option on each line is my reading.
- **That the Path B install leaves the service running**, and so that step 2 of section 8 is needed. The documents say the script starts the service. I did not see it.
- **AIS-catcher's "managed mode"** and its page at `8118`. I did not use it.
- **Any RTL-SDR dongle on AIS.** My AIS radio is an Airspy Mini. I ran a Nooelec NESDR SMArt v5 on another signal for six weeks, not on AIS. That an RTL-SDR dongle samples with 8 bits is common knowledge, not a figure I read on the check date.
- **The RTL-SDR Blog V4L with AIS-catcher.** The AIS-catcher documents name the V3 and the V4. They do not name the V4L. My V4L needed a driver from August 2026 or later for another decoder. The newest AIS-catcher release that I found is dated June 2026.
- **The serial-number command for an RTL-SDR dongle with `-s 162`.** My station ran the same command with another number, for the aircraft radio.
- **`VERBOSE_LOGGING=1`.** The setting is from the shipfeeder README and its start script. I run the default.
- **A Raspberry Pi smaller than the Pi 5, and Wi-Fi.** The projects name smaller models. I measured only my own.
- **The price and the connector of the low-cost AIS antenna**, and the price of the NESDR SMArt v5. Read the listings.
- **Whether aiscatcher.org receives or shows your position** when you share with no account.
- **Which networks give a paid-level account today, and on what terms.** Read each network's page.
- **The slot and frame numbers of AIS** (2,250 slots, 9,600 bits a second) and the reporting times. They are from the AIS-catcher and gpsd documents, not from the ITU standard itself.
- **The grounding rule.** I read a summary, not the code text.
- **No step in this guide was run on a new, empty computer as written.** The Path A settings are the ones on my station, checked against the project's documents.

## 16. Sources

All were read on 2026-10-10, except where a date is given.

**The decoder.** AIS-catcher: <https://github.com/jvde-github/AIS-catcher>. Its documents: <https://jvde-github.github.io/AIS-catcher-docs/> (pages read: AIS Basics, What You'll Need, the installation pages for Raspberry Pi, Linux and Docker, Command Line Usage, Running as a Service, RTL SDR, AirSpy Mini/R2, Web Viewer, UDP, Console, Community Feed, Troubleshooting).

**The container.** docker-shipfeeder: <https://github.com/sdr-enthusiasts/docker-shipfeeder> (the README, and the start script `rootfs/etc/s6-overlay/scripts/aiscatcher`). The Docker install script: <https://github.com/sdr-enthusiasts/docker-install>.

**The message format.** AIVDM/AIVDO protocol decoding, gpsd project: <https://gpsd.gitlab.io/gpsd/AIVDM.html>.

**My station.** The full-station guide on this site, [Build the station](/guides/build-the-station/), checked against the station on 2026-10-07: the compose file, the driver checks, the serial-number steps, the message rates and the traps. The episode's fact sheet: the vessel count and the range band, from the station's statistics page on 2026-10-06.

**Parts.** The maker or seller page linked from each row of section 2. Prices are from the full-station guide, 2026-10-07.

**Rules.** 47 U.S.C. 605: <https://www.law.cornell.edu/uscode/text/47/605> (read 2026-10-07 for the full-station guide).

[^ais-ant]: I started with a small whip indoors, then put a low-cost AIS-band vertical on the roof. The rate went up about six times. A marine-grade antenna is a later step, if at all.
[^fm-ais]: I added it and the message rate did not change. I left it in as cheap protection.
[^v4l]: The RTL-SDR Blog V4L needs a driver from August 2026 or later. I could not confirm that AIS-catcher has it (section 15). The older V4 is no longer made. The AIS-catcher documents advise a current model with a temperature-compensated oscillator (TCXO), because a low-cost dongle drifts with temperature.
[^small-pi]: The AIS-catcher documents call a Pi Zero 2 W sufficient and a Pi 3 or newer comfortable. The shipfeeder project names the Pi 3B+ and the Pi 4. The ready-made AIS-catcher package does not run on the first Raspberry Pi and the first Pi Zero.
[^rtl-only]: The shipfeeder README still describes the station with an RTL-SDR dongle. That is the common build. The Airspy Mini is the less common one.
[^nec]: Mike Holt's summary of NEC 810.21, 2020 edition: <https://www.mikeholt.com/files/PDF/20BG_810.21.pdf>.
