Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docker_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.tar1090
file: Dockerfile
platforms: linux/arm64
push: false
load: true
Expand Down
44 changes: 13 additions & 31 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
FROM debian:bullseye-slim
FROM ghcr.io/sdr-enthusiasts/docker-tar1090:latest

RUN apt-get update && apt-get install -y \
nginx \
lighttpd \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js for our adsb.lol proxy
RUN apt-get update && apt-get install -y nodejs npm && rm -rf /var/lib/apt/lists/*

RUN mkdir -p /usr/local/share/tar1090/html
# Copy our proxy server (reads from file, avoids circular dependency)
COPY proxy/server.js /opt/proxy/server.js

COPY html/ /usr/local/share/tar1090/html/
COPY *.conf /usr/local/share/tar1090/
COPY *.sh /usr/local/share/tar1090/
RUN chmod +x /usr/local/share/tar1090/*.sh
# Runtime nginx config injection - runs AFTER 07-nginx-configure regenerates config
# Must be numbered > 07 to run after nginx config is generated
# (Build-time sed doesn't persist because tar1090 regenerates nginx config at startup)
COPY docker/08-inject-proxy-config /etc/s6-overlay/startup.d/08-inject-proxy-config
RUN chmod +x /etc/s6-overlay/startup.d/08-inject-proxy-config

COPY docker/lighttpd-tar1090.conf /etc/lighttpd/conf-available/89-tar1090.conf
RUN lighttpd-enable-mod tar1090

RUN sed -i 's/server.port\s*=.*/server.port = 8504/' /etc/lighttpd/lighttpd.conf && \
sed -i 's|server.document-root\s*=.*|server.document-root = "/usr/local/share/tar1090/html/"|' /etc/lighttpd/lighttpd.conf

COPY <<'EOF' /usr/local/bin/start.sh
#!/bin/bash
set -e

echo "Starting tar1090 web interface on port 8504..."
lighttpd -D -f /etc/lighttpd/lighttpd.conf
EOF

RUN chmod +x /usr/local/bin/start.sh

EXPOSE 8504

CMD ["/usr/local/bin/start.sh"]
# Run proxy as a proper s6-overlay service (auto-restart, logging, graceful shutdown)
COPY docker/services.d/proxy /etc/services.d/proxy
RUN chmod +x /etc/services.d/proxy/run
18 changes: 0 additions & 18 deletions Dockerfile.tar1090

This file was deleted.

45 changes: 13 additions & 32 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,52 +1,33 @@
services:
readsb:
image: ghcr.io/sdr-enthusiasts/docker-readsb-protobuf:latest
container_name: readsb
hostname: readsb
tar1090:
build:
context: .
dockerfile: Dockerfile
container_name: tar1090
hostname: tar1090
restart: unless-stopped
network_mode: host
environment:
- TZ=UTC
# readsb config (built into docker-tar1090)
- READSB_DEVICE_TYPE=none
- READSB_NET_ENABLE=true
- READSB_NET_CONNECTOR=${READSB_NET_CONNECTOR:-}
- READSB_LAT=${RECEIVER_LAT:-0}
- READSB_LON=${RECEIVER_LON:-0}
- READSB_ALT=${RECEIVER_ALT:-0}
- READSB_RX_LOCATION_ACCURACY=2
- READSB_STATS_RANGE=true
- READSB_NET_ENABLE=true
- DISABLE_WEBAPP=true
- READSB_NET_CONNECTOR=192.168.8.183,30005,beast_in
volumes:
- readsb-autogain:/run/autogain
- readsb-collectd:/run/collectd
tmpfs:
- /var/log:size=32M

tar1090:
build:
context: .
dockerfile: Dockerfile.tar1090
container_name: tar1090
hostname: tar1090
restart: unless-stopped
network_mode: host
depends_on:
- readsb
environment:
- TZ=UTC
- BEASTHOST=127.0.0.1
- BEASTPORT=30005
# tar1090 map config
- LAT=${RECEIVER_LAT:-0}
- LONG=${RECEIVER_LON:-0}
- TAR1090_DEFAULTCENTERLAT=${RECEIVER_LAT:-0}
- TAR1090_DEFAULTCENTERLON=${RECEIVER_LON:-0}
- READSB_URL=http://127.0.0.1:80/data/aircraft.json
# adsb.lol proxy config
- ADSBLOL_ENABLED=${ADSBLOL_ENABLED:-false}
- RECEIVER_LAT=${RECEIVER_LAT:-0}
- RECEIVER_LON=${RECEIVER_LON:-0}
- ADSBLOL_RADIUS=${ADSBLOL_RADIUS:-40}
- PROXY_PORT=3005

volumes:
readsb-autogain:
readsb-collectd:
tmpfs:
- /var/log:size=32M
22 changes: 22 additions & 0 deletions docker/08-inject-proxy-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/command/with-contenv bash
# Inject proxy location block AFTER tar1090's 07-nginx-configure runs
# This must run at startup (not build time) because 07-nginx-configure regenerates the config

echo "[08-inject-proxy-config] Injecting adsb.lol proxy config into nginx..."

# Add proxy location for aircraft.json
sed -i '/include \/etc\/nginx\/nginx-tar1090-webroot.conf;/i\ location = /data/aircraft.json { proxy_pass http://127.0.0.1:3005/data/aircraft.json; }' \
/etc/nginx/sites-enabled/tar1090

# Disable binCraft in receiver.json so frontend uses JSON format (required for adsb.lol)
# Uses nginx sub_filter to modify the response on-the-fly
sed -i '/include \/etc\/nginx\/nginx-tar1090-webroot.conf;/i\ location = /data/receiver.json { alias /run/readsb/receiver.json; sub_filter_types application/json; sub_filter '\''\"binCraft\": true'\'' '\''\"binCraft\": false'\''; sub_filter '\''\"zstd\": true'\'' '\''\"zstd\": false'\''; sub_filter_once off; }' \
/etc/nginx/sites-enabled/tar1090

# Verify the injection worked
if grep -q "proxy_pass" /etc/nginx/sites-enabled/tar1090; then
echo "[08-inject-proxy-config] Proxy config injected successfully"
else
echo "[08-inject-proxy-config] ERROR: Failed to inject proxy config"
exit 1
fi
20 changes: 0 additions & 20 deletions docker/entrypoint.sh

This file was deleted.

7 changes: 0 additions & 7 deletions docker/lighttpd-proxy.conf

This file was deleted.

20 changes: 0 additions & 20 deletions docker/lighttpd-tar1090.conf

This file was deleted.

2 changes: 2 additions & 0 deletions docker/services.d/proxy/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/command/with-contenv bash
exec node /opt/proxy/server.js
81 changes: 57 additions & 24 deletions proxy/server.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const http = require('http');
const https = require('https');
const fs = require('fs').promises;

const READSB_URL = process.env.READSB_URL || 'http://127.0.0.1:80/data/aircraft.json';
const LOCAL_DATA_PATH = process.env.LOCAL_DATA_PATH || '/run/readsb/aircraft.json';
const ADSBLOL_ENABLED = process.env.ADSBLOL_ENABLED === 'true';
const RECEIVER_LAT = parseFloat(process.env.RECEIVER_LAT || '0');
const RECEIVER_LON = parseFloat(process.env.RECEIVER_LON || '0');
const ADSBLOL_RADIUS = parseInt(process.env.ADSBLOL_RADIUS || '40');
const PORT = parseInt(process.env.PROXY_PORT || '3000');
const PORT = parseInt(process.env.PROXY_PORT || '3005');

const ADSBLOL_API = `https://api.adsb.lol/v2/lat/${RECEIVER_LAT}/lon/${RECEIVER_LON}/dist/${ADSBLOL_RADIUS}`;

Expand Down Expand Up @@ -80,31 +81,58 @@ function convertAdsbLolToReadsb(adsbLolData) {
};
}

async function getAircraftData() {
async function fetchAdsbLol() {
console.log('Fetching from adsb.lol...');
const adsbLolData = await fetchUrl(ADSBLOL_API);
const convertedData = convertAdsbLolToReadsb(adsbLolData);
console.log(`adsb.lol: ${convertedData.aircraft?.length || 0} aircraft`);

// Write to local file so tar1090's backend process can read it
try {
console.log('Attempting to fetch from local readsb...');
const localData = await fetchUrl(READSB_URL);
console.log(`✓ Local readsb: ${localData.aircraft?.length || 0} aircraft`);
return { data: localData, source: 'local' };
await fs.writeFile(LOCAL_DATA_PATH, JSON.stringify(convertedData));
} catch (err) {
console.log(`Warning: Could not write to ${LOCAL_DATA_PATH}: ${err.message}`);
}

return { data: convertedData, source: 'adsb.lol' };
}

async function readLocalFile() {
try {
const data = await fs.readFile(LOCAL_DATA_PATH, 'utf8');
return JSON.parse(data);
} catch (error) {
console.log(`✗ Local readsb failed: ${error.message}`);
return null;
}
}

if (!ADSBLOL_ENABLED) {
console.log('✗ adsb.lol fallback disabled');
throw new Error('Local feed unavailable and fallback disabled');
}
async function getAircraftData() {
// Try local file first (readsb writes to /run/readsb/aircraft.json)
const localData = await readLocalFile();

if (localData && localData.aircraft?.length > 0) {
console.log(`Local file: ${localData.aircraft.length} aircraft`);
return { data: localData, source: 'local' };
}

// Try adsb.lol fallback if enabled
if (ADSBLOL_ENABLED) {
const reason = localData ? '0 aircraft from local' : 'local file not found';
console.log(`Falling back to adsb.lol (${reason})...`);
try {
console.log('Attempting fallback to adsb.lol...');
const adsbLolData = await fetchUrl(ADSBLOL_API);
const convertedData = convertAdsbLolToReadsb(adsbLolData);
console.log(`✓ adsb.lol fallback: ${convertedData.aircraft?.length || 0} aircraft`);
return { data: convertedData, source: 'adsb.lol' };
return await fetchAdsbLol();
} catch (fallbackError) {
console.log(`✗ adsb.lol fallback failed: ${fallbackError.message}`);
throw new Error('Both local and fallback feeds unavailable');
console.log(`adsb.lol fallback failed: ${fallbackError.message}`);
}
}

// Return local data even if empty (if we got a response)
if (localData) {
return { data: localData, source: 'local' };
}

// No data sources available
throw new Error('No data sources available');
Comment thread
Sol455 marked this conversation as resolved.
}

const server = http.createServer(async (req, res) => {
Expand All @@ -118,11 +146,16 @@ const server = http.createServer(async (req, res) => {
});
res.end(JSON.stringify(data));
} catch (error) {
res.writeHead(503, { 'Content-Type': 'application/json' });
console.log(`Data fetch failed: ${error.message}`);
res.writeHead(200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'X-Data-Source': 'none'
});
res.end(JSON.stringify({
error: error.message,
aircraft: [],
now: Date.now() / 1000
now: Date.now() / 1000,
messages: 0,
aircraft: []
}));
}
} else if (req.url === '/health') {
Expand All @@ -136,7 +169,7 @@ const server = http.createServer(async (req, res) => {

server.listen(PORT, () => {
console.log(`Aircraft data proxy listening on port ${PORT}`);
console.log(`Local feed: ${READSB_URL}`);
console.log(`Local data file: ${LOCAL_DATA_PATH}`);
console.log(`adsb.lol fallback: ${ADSBLOL_ENABLED ? 'enabled' : 'disabled'}`);
if (ADSBLOL_ENABLED) {
console.log(`adsb.lol API: ${ADSBLOL_API}`);
Expand Down