Skip to content

Latest commit

Β 

History

209 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

9M2PJU DXSpider Docker Banner

9M2PJU DXSpider Docker

The Ultimate Modern DX Cluster Solution

License Issues Pull Requests Last Commit
Stars Forks Contributors Activity
GHCR Image CI Smoke Test Platform
Repo Size Language Base Image Security


Experience the future of Amateur Radio Networking. Deploy a professional-grade DX Cluster node in minutes, not hours.

What is this? β€’ Quick Start β€’ Documentation β€’ Configuration β€’ Architecture β€’ Security β€’ FAQ


What is a DX Cluster?

A DX Cluster is a network of servers that share real-time "spots", reports of rare or interesting amateur radio stations heard on the air. When someone hears a DX station, they post a spot to their local cluster node, which then propagates it to all connected nodes worldwide within seconds.

DXSpider is the software that runs most of these cluster nodes. Originally created in the late 1990s and written in Perl, it has been actively maintained and extended by the amateur radio community for decades. This project packages DXSpider into a Docker container so you can deploy it without manually installing Perl, CPAN modules, or configuring a server.


Key Features

Feature Description
Instant Launch Three lines of code and you are live. Literally.
Web Console Built-in web terminal (ttyd) for easy administration without SSH.
Hardened cap_drop: ALL + no-new-privileges, with only the minimal kernel capabilities needed.
Data Safety User database, spots, and logs are safe in persistent bind-mounted volumes.
Universal Multi-arch images: amd64, arm64, arm/v7, arm/v6, 386, ppc64le, s390x, from servers to Raspberry Pi Zero.
Automation Built-in Cron and Startup script support.
Optional DB Flat-file storage by default; optional MariaDB backend via compose profile.
CI Tested Every commit is smoke-tested in GitHub Actions before publishing.

Documentation

This project includes a complete docs/ directory with beginner-friendly guides:

Document What it covers
Getting Started Installation, first run, your first spot, basic commands
Configuration Reference All environment variables and DXVars.pm explained
Connecting to Partner Nodes Joining the global DX Cluster network
Filters Controlling what spots and announcements you see
User Commands Reference Full command list for users and sysops
Cron & Automation Scheduled tasks, auto-reconnect, startup scripts
Database Backend Optional MariaDB setup for spot logging
Security Hardening guide, capabilities, best practices

| Troubleshooting | FAQ, debugging, common problems and solutions |

New to DX Clusters? Start with Getting Started. It walks you through everything step by step.


Architecture & Flow

graph TB
    subgraph Host["Your Station (Host Machine)"]
        Env[".env<br/>Configuration"]
        LD["local_data/<br/>Users, Spots, Logs"]
        Conn["connect/<br/>Partner Scripts"]
        Cmd["cmd/<br/>Custom Commands"]
        Msg["msg/<br/>Bulletins"]
        Cron["local_cmd/<br/>Crontab + Local Cmds"]
        Startup["startup<br/>Boot Commands"]
    end

    subgraph Container["Docker Container (Alpine 3.23)"]
        direction TB
        EP["entrypoint.sh<br/>(root: fix perms)"]
        subgraph App["su-exec β†’ sysop (UID 1000)"]
            Cluster["cluster.pl<br/>DXSpider Core"]
            Console["console.pl<br/>via ttyd"]
        end
        DB{"DB enabled?"}
    end

    subgraph Optional["Optional (compose profile)"]
        MariaDB["MariaDB 11<br/>Spot Logging"]
    end

    subgraph External["Global Network"]
        World["DX Cluster Network<br/>(Partner Nodes)"]
        Users["Hams via Telnet<br/>:7300"]
        Web["Sysop via Web<br/>:8080"]
    end

    Env --> EP
    LD <--> App
    Conn --> Cluster
    Cmd --> Cluster
    Msg --> Cluster
    Cron --> Cluster
    Startup --> Cluster
    EP --> App
    Cluster --> DB
    DB -->|yes| MariaDB
    DB -->|no| LD
    Cluster <--> World
    Users -->|TCP 7300| Cluster
    Web -->|HTTP 8080| Console
Loading

Quick Start

Prerequisites

Option A: Interactive Setup (Recommended)

The easiest way to get started is using our interactive installation script. It will check dependencies, clone the repository, prompt you for the necessary configuration, and launch the cluster automatically.

curl -sSL https://raw.githubusercontent.com/9M2PJU/9M2PJU-DXSpider-Docker/main/install.sh | bash

Option B: Manual Setup

Note

This guide uses docker compose (Docker Compose V2) which is the recommended method to manage the container and its configuration.

  • If you prefer not to use Compose at all, you can use standard docker commands. See the Standalone Docker Run section below.

1. Get the Code

git clone https://github.com/9M2PJU/9M2PJU-DXSpider-Docker.git
cd 9M2PJU-DXSpider-Docker

2. Configure Identity

Important

After cloning this repository, make sure all configurations are correct in your .env file before starting the cluster. An incorrectly configured node can cause routing loops or be rejected by the DXSpider network.

cp .env.example .env
vi .env
# At minimum, set:
#   CLUSTER_CALLSIGN=YOURCALL-2
#   CLUSTER_SYSOP_CALLSIGN=YOURCALL
#   CLUSTER_LOCATOR=YOURGRID
#   WEB_PASS=a-secure-password

3. Pull & Launch!

docker compose pull      # Download the pre-built image from GHCR (fast)
docker compose up -d     # Start the cluster

Tip

docker compose pull downloads the pre-built multi-arch image from GitHub Container Registry. No local build is needed, and this is much faster than --build.

If you prefer to build locally (e.g., offline or custom modifications), use docker compose up -d --build instead.

You are live! Access your node:

  • Telnet: telnet localhost 7300 (users connect here)
  • Web Console: http://localhost:8080 (use WEB_USER / WEB_PASS from .env)

Warning

A standalone DXSpider node will not receive any DX spots on its own! To get spots flowing, you must connect your node to a partner node on the DX Cluster network. You will need to find a partner to connect to. See Connecting to Partners for instructions.

Important

The container runs as UID 1000 internally. If your host directories are owned by a different UID, either:

  • Change SPIDER_UID in .env to match your host UID, or
  • chown -R 1000:1000 local_data connect cmd msg on the host before starting.

Your First Commands

Once connected via telnet, try these:

Command What it does
help Show available commands
sh/dx Show recent DX spots
sh/dx 20m Show spots on the 20-meter band
sh/configuration Show all connected nodes and users
set/name Your Name Set your name
set/homenode YOURCALL-2 Set your home node
bye Disconnect

See the User Commands Reference for the full list.

Tip

For a complete walkthrough including posting your first DX spot, see Getting Started.


Multi-Architecture Support

This project supports a wide range of CPU architectures, making it compatible with everything from high-end servers to Raspberry Pi Zero.

Docker (Linux): Supported Platforms

Platform Typical Hardware
linux/amd64 Standard 64-bit PC / servers
linux/arm64 Raspberry Pi 4/5, Apple Silicon, AWS Graviton
linux/arm/v7 Raspberry Pi 2/3 (32-bit)
linux/arm/v6 Raspberry Pi Zero/1
linux/386 32-bit x86 PCs / older servers
linux/ppc64le IBM POWER servers
linux/s390x IBM Z / LinuxONE mainframes

Pre-built images are published automatically to GHCR on every push to main:

docker pull ghcr.io/9m2pju/9m2pju-dxspider-docker:main

Standalone Docker Run

If you prefer not to use Docker Compose, you can run the cluster with a single docker run command. This is useful for quick testing or cloud environments like AWS ECS or Azure ACI.

Important

Always mount all the bind volumes shown below. Without them, your connect scripts, crontab, startup commands, MOTD, and data will be lost when the container is recreated or the image is updated.

docker run -d \
  --name dxspider \
  -p 7300:7300 \
  -p 8080:8080 \
  -e CLUSTER_CALLSIGN=N0CALL-2 \
  -e CLUSTER_SYSOP_CALLSIGN=9M2PJU \
  -e CLUSTER_LOCATOR=OJ03UD \
  -e CLUSTER_LATITUDE=+03.08 \
  -e CLUSTER_LONGITUDE=+101.41 \
  -e CLUSTER_QTH="Kuala Lumpur" \
  -e WEB_USER=sysop \
  -e WEB_PASS=your-secure-password \
  -v $(pwd)/local_data:/spider/local_data \
  -v $(pwd)/connect:/spider/connect \
  -v $(pwd)/local_cmd:/spider/local_cmd \
  -v $(pwd)/cmd:/spider/cmd \
  -v $(pwd)/msg:/spider/msg \
  -v $(pwd)/startup:/spider/scripts/startup \
  -v $(pwd)/motd:/spider/local_data/motd \
  -v $(pwd)/motd_nor:/spider/local_data/motd_nor \
  ghcr.io/9m2pju/9m2pju-dxspider-docker:main

Tip

Persistent Data: Always mount all volumes. The local_data volume holds your user database and spots. The connect, local_cmd, startup, motd, and motd_nor volumes hold your node configuration. Without them, rebuilding the image would reset your settings to the defaults baked into the image.

Manual Multi-Arch Build (Advanced)

Note

This is optional. Our GitHub Actions automatically build and push these images for you. Use this only if you want to build a custom version locally.

docker buildx build \
  --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le,linux/s390x \
  -t ghcr.io/9m2pju/9m2pju-dxspider-docker:latest \
  --push .

To pin DXSpider to a specific commit (for reproducible builds):

docker buildx build \
  --build-arg SPIDER_GIT_REF=<commit-sha> \
  -t dxspider-custom:latest \
  --load .

Configuration Reference

Edit these in your .env file (copy from .env.example). All variables have sensible defaults. Only CLUSTER_CALLSIGN and CLUSTER_SYSOP_CALLSIGN are truly required.

For a complete explanation of every variable and how configuration works, see the Configuration Reference.

Identity & Sysop

Variable Description Default
CLUSTER_CALLSIGN Required. The callsign of your node. N0CALL-2
CLUSTER_SYSOP_CALLSIGN Required. Your admin callsign. 9M2PJU
CLUSTER_SYSOP_NAME Sysop's display name. DXSpider Sysop
CLUSTER_SYSOP_EMAIL Sysop contact email. 9m2pju@hamradio.my
CLUSTER_SYSOP_BBS_ADDRESS BBS forwarding address. bbs@localhost
CLUSTER_QTH Your QTH description. DXSpider Node
CLUSTER_LOCATOR Maidenhead grid square. JO01aa
CLUSTER_LATITUDE Latitude (decimal degrees). 0
CLUSTER_LONGITUDE Longitude (decimal degrees). 0

Network

Variable Description Default
CLUSTER_PORT Telnet port (user-facing). 7300
CLUSTER_SYSOP_PORT Web Console port (ttyd). 8080

Web Console

Variable Description Default
WEB_USER Username for the Web Console (HTTP basic auth). sysop
WEB_PASS Password for the Web Console. changeme-web

Optional MariaDB Backend

Leave CLUSTER_DB_HOSTNAME empty (default) to use flat-file storage. To enable MariaDB for spot logging:

Variable Description Default
CLUSTER_DB_HOSTNAME Database hostname. Set to db to use the compose service. (empty = disabled)
CLUSTER_DB_NAME Database name. spider
CLUSTER_DB_USER Database username. sysop
CLUSTER_DB_PASS Database password. sysoppassword
CLUSTER_DB_PORT Database port. 3306
CLUSTER_DB_ROOT_PWD MariaDB root password (compose db service only). changeme-root
# Enable MariaDB:
# 1. Uncomment the DB lines in .env
# 2. Start with the with-db profile:
docker compose --profile with-db up -d --build

See Database Backend for full setup instructions.

Build & Advanced

Variable Description Default
CLUSTER_DXSPIDER_BRANCH DXSpider git branch (mojo or master). mojo
SPIDER_GIT_REF Pin DXSpider to a specific commit SHA. (pinned default)
SPIDER_UID UID for the sysop user inside the container. 1000
OVERWRITE_CONFIG Set to yes to force-regenerate DXVars.pm and Listeners.pm on every start. no

Security & Hardening

This container follows security best practices:

Measure How
No privileged mode privileged: true is not used. The container runs with normal Docker isolation.
Minimal capabilities cap_drop: ALL + only CHOWN, FOWNER, SETUID, SETGID added back.
No new privileges security_opt: no-new-privileges:true prevents privilege escalation.
Non-root application cluster.pl and console.pl run as the sysop user (UID 1000) via su-exec.
Root only for setup The entrypoint starts as root only to fix volume permissions, then drops to sysop.
tini as PID 1 Proper zombie reaping and signal forwarding.
No secrets in git .env and local_data/ are gitignored. Use .env.example as your template.

For a full hardening guide including firewall setup, SSH tunneling, and abuse reporting, see Security.


Persistence & Bind Mounts

All your node's configuration and data lives on the host filesystem, not inside the container. Docker bind mounts map host directories into the container, overriding the default files baked into the image. This means:

  • Rebuilding the image does NOT change your configuration. Your host files always take precedence over the image's defaults.
  • Upgrading is safe. Pull a new image, rebuild, and restart. Your connect scripts, crontab, startup commands, MOTD, user database, and spots are all preserved on the host.
  • Backups are easy. Just back up the project directory (especially local_data/).

What is persistent?

Host Directory What's Stored There Bind-Mounted?
local_data/ User database, spots, logs, debug data, filter lists Yes
connect/ Partner node connection scripts Yes
local_cmd/ Cron schedule (crontab) + local command overrides Yes
startup Boot-time DXSpider commands Yes
motd Message of the day (registered users) Yes
motd_nor Message of the day (non-registered users) Yes
cmd/ Custom user commands Yes
msg/ Bulletins and private messages Yes

What is NOT persistent (regenerated on each start)?

File Why
/spider/local/DXVars.pm Generated by entrypoint.sh from .env variables
/spider/local/Listeners.pm Generated by entrypoint.sh from CLUSTER_PORT

If you need to persist these too (e.g., you manually edit DXVars.pm inside the container), set OVERWRITE_CONFIG=no in .env and add a bind mount for ./local:/spider/local:rw in compose.yaml.

Tip

To force-regenerate config from .env after changing variables, set OVERWRITE_CONFIG=yes in .env and restart. Set it back to no afterward.


Connecting to Partner Nodes

To join the global DX Cluster network, your node needs to link to at least one other node. This is both a technical and social process. You need the other sysop's permission.

Important

You cannot simply connect to any node without permission. Contact the sysop of the node you want to link with, agree on a password, and then configure your connect script.

Quick steps:

  1. Create a file in connect/ named after the partner node (lowercase), e.g., connect/gb7mbc
  2. Add the connection logic (telnet hostname, port, login, password)
  3. Mark the partner as a node: set/spider gb7mbc
  4. Connect: connect gb7mbc
  5. Add auto-reconnect to local_cmd/crontab

See Connecting to Partner Nodes for the complete guide.


Automation (Cron & Startup)

Startup Tasks: Edit the startup file. Commands here run every time the container boots:

# Example 'startup' file content:
load/forward
set/spider gb7mbc
connect gb7mbc

Scheduled Tasks (Cron): Edit local_cmd/crontab. Standard cron format, but commands are Perl expressions:

# Reconnect to GB7MBC every 10 mins if link dropped
0,10,20,30,40,50 * * * * start_connect('gb7mbc') unless connected('gb7mbc')

The default crontab also fetches bad-IP, bad-DX, bad-spotter, bad-node, and bad-word lists hourly from the dxspider_info repo to keep your node protected from known abusers.

See Cron & Automation for the complete guide.


Windows Support

Windows users can run 9M2PJU DXSpider Docker easily using WSL2 or traditional virtualization.

WSL2 (Recommended)

  1. Install Docker Desktop and enable the WSL2 Backend.
  2. Install a Linux distribution (e.g., Ubuntu) from the Microsoft Store.
  3. In Docker Desktop, enable Settings > Resources > WSL Integration for that distribution.
  4. Open the distribution's WSL terminal and run the Interactive Setup command above.
  5. Keep the installation inside the WSL2 filesystem (~/dxspider) rather than on the Windows C: drive.

Hyper-V

  1. Enable the Hyper-V feature in Windows.
  2. Create a Linux Virtual Machine.
  3. Install Docker and follow the standard Linux instructions.

Troubleshooting & FAQ

My container keeps restarting!

Check the logs immediately:

docker compose logs -f

Common issues:

  • Invalid characters in .env (e.g., unquoted spaces in values).
  • Port 7300 is already in use by another application.
  • Bind-mounted directories owned by a UID other than 1000 (set SPIDER_UID to match, or chown -R 1000:1000 the directories).
How do I access the internal shell?

If you need to run manual spider commands or debug internally:

docker compose exec dxspider sh
# Then run commands like:
/spider/perl/console.pl
How do I update to the latest version?

Simple. We built this to be easy.

git pull                  # Get latest docker configs
docker compose pull       # Download the latest pre-built image from GHCR
docker compose up -d      # Restart with the new image

Your data in local_data/ will remain safe.

If you build locally instead of pulling, use docker compose up -d --build in place of the pull + up steps.

Permission denied errors on volumes?

The container expects bind-mounted directories to be writable by UID 1000. Fix with:

chown -R 1000:1000 local_data connect cmd msg

Or set SPIDER_UID in .env to match your host user's UID.

How do I force-regenerate the configuration?

Set OVERWRITE_CONFIG=yes in your .env and restart:

docker compose down
docker compose pull
docker compose up -d

Set it back to no afterward to preserve manual edits.

For more troubleshooting, see the Troubleshooting Guide.


History & Legacy

To understand why this project exists, we must look back at the rich history of Amateur Radio networking.

The Dawn: Packet Clusters

In the late 1980s, PacketCluster software revolutionized DX hunting. Before this, DX spots could only be shared via voice repeaters or local shouting. This software allowed spots to be distributed over Packet Radio (AX.25) networks. A "Sysop" would run a node, and users would connect via radio to see a live stream of DX spots.

The Evolution: DXSpider

By the late 1990s, the internet was emerging, and the original DOS-based PacketCluster software was showing its age. A new, more flexible solution was needed to bridge the gap between RF networks and the Internet.

Perl was chosen for its robust text handling and modularity, and DXSpider was born. It was designed to be:

  • Compatible: It spoke the exact same protocol as the older software, so users didn't need to change their client software.
  • Scalable: It could handle hundreds of simultaneous internet connections, something the old PC-based clusters couldn't dream of.
  • Open: It allowed the community to contribute and extend the software.

Today, DXSpider powers a vast majority of the world's DX Cluster nodes, silently processing millions of spots a year and keeping the global amateur radio community connected. 9M2PJU-DXSpider-Docker is simply the next step in this evolution, packaging this history into a container for the future.


Contributing

We love community involvement!

  1. Fork it.
  2. Create your feature branch (git checkout -b feature/cool-thing).
  3. Commit your changes.
  4. Push to the branch.
  5. Create a Pull Request.

Tip

Every PR is automatically smoke-tested by CI. The cluster must boot and listen on port 7300 before images are published.


License

Distributed under the GNU General Public License v3.0. See LICENSE for more information.


Enjoying the project? Star us on GitHub!


β˜• Support

If you find this project useful, you can support its development:

Buy Me A Coffee Β Β  Wise



πŸ“§ Contact: 9m2pju@hamradio.my Β |Β  🌐 Website: hamradio.my


Designed with care by 9M2PJU 73 and Good DX!

About

Transforming DXSpider deployment into a seamless experience for the global amateur radio community πŸ“‘

Topics

Resources

Stars

13 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages