This repository hosts nossl.sh, an Express + EJS diagnostic page that reports
client IP, headers, and connection details. It also exposes JSON endpoints,
honeypot stats, shared report links (Redis), a Redis-backed beacon lookup with
client-side 404 retries to wait for DNS/Redis propagation, SQLite-backed IP
records for /api/request-info and /api/beacon, and optional GeoIP/ASN
enrichment.
- Install deps:
npm install - Dev server (nodemon):
npm run dev(defaulthttp://localhost:8080) - Production:
npm start
There is no automated test suite. If you need to validate changes, run the app and manually verify endpoints relevant to your edit (see "Key routes" below).
/main HTML diagnostics page/api/request-infoJSON diagnostics/free-geo-ipfree GeoIP + ASN lookup page/api/ipGeoIP + ASN JSON lookup (use?ip=)/api/beaconbeacon payload lookup via<uniq>.r.nossl.shhost (Redis)/healthzhealth check/status/:codereturn any HTTP status (optional?location=)/honeypotHTML summary,/api/honeypotJSON summary/ssservice status page with request counters and updates/asNNNASN detail HTML (requires ASN info DB)/api/asNNNASN detail JSON (requires ASN info DB)/report/:idshared report (requires Redis)
PORT(default8080) andLISTEN_ADDRESS(default127.0.0.1)SQLDBpath for counters/honeypot/IP-records SQLite DB (defaultcounters.db)MAX_HONEYPOTrecord limit (default1024)MAX_IP_RECORDSmax unique IP rows per tracked endpoint (default100000)GEOIP_DB_PATHpath to GeoIP country DB (defaultip-to-country.mmdb)ASNIP_DB_PATHpath to ASN DB (defaultip-to-asn.mmdb)ASN_INFO_DB_PATHpath to ASN info SQLite DB (enables ASN detail pages)REDIS_URL(defaultredis://127.0.0.1:6379)REPORT_TTL_SECONDSTTL for shared reports (default86400)TEST_IPoverrides detected client IP for debugging
server.jsExpress entry point and route wiringcomponets/feature modules (note the folder name is intentionally spelled)templates/EJS views,templates/partials/shared fragmentsstatic/CSS, icons, and robots filesinfra/dagster/definitions.pyDagsterDefinitionsentrypoint (defs)infra/dagster/build_data_job.pyDagster geofeed and PeeringDB ops/jobs (geofeed_finder_job,pdb_asn_geo_job) and sharedpathsresourceinfra/dagster/build_asn_data_job.pyDagster ASN pipeline job (build_asn_data_job)infra/dagster/build_geo_database_job.pyDagster GEO pipeline job (build_geo_database_job)infra/dagster/common_ops.pyshared Dagster ops (for examplebuild_date_tag)infra/dagster/utils.pyshared Dagster helpers and utilities (paths access, guarded temp-dir cleanup, symlink update, and failure-hook factories)infra/scripts/Python data tooling (ASN aggregation, domain population, rDNS pipelines)infra/configs/config and rule files (rdns_geo_rules.json,*.conf, geofeed lists)infra/beacon/Go service that ingests dnstap and storesbeacon:<uniq>in Redisinfra/mmdb-builder/Go toolchain for building the ASN MMDB from per-ASNaggregated.jsonfilesdeploy-nossl.shproduction deployment script (systemd + nginx)
- Definitions entrypoint:
infra/dagster/definitions.py(packageinfra.dagsteralso exportsdefs). - Job modules:
infra/dagster/build_data_job.pyforgeofeed_finder_jobandpdb_asn_geo_jobinfra/dagster/build_asn_data_job.pyforbuild_asn_data_jobinfra/dagster/build_geo_database_job.pyforbuild_geo_database_job
- Jobs:
geofeed_finder_jobrunsgeofeed_finderpdb_asn_geo_jobrunspdb_asn_geobuild_asn_data_jobrunsbuild_date_tag->clone_asn_repo->aggregate_asn->populate_asn_domains->build_asn_mmdb->update_asn_latest_symlink->cleanup_asn_temp_dirbuild_geo_database_jobrunsbuild_date_tag->clone_ip_geo_repo->build_geo_mmdb->run_rdns_geo->patch_geo_mmdb_with_rdns->update_geo_latest_symlink->cleanup_geo_temp_dir
- Resource:
pathswith config keyswork_dirandbin_dir; both directories are created if missing. geofeed_finderexecutesgeofeed-finder-linux-x64, parses[stats] ... total=<n>from output, and fails if: missing stats line,geofeed_limit < 0, ortotal < geofeed_limit.geofeed_limitis optional op config with default5000.enable_pgsqlis optional op config with defaultfalse; when enabled it appends--pgsqltogeofeed-finder.enable_insecureis optional op config with defaultfalse; when enabled it appends--insecuretogeofeed-finder.- On success,
geofeed_finderemits output and metadata withtotalandmin_totalfor observability. pdb_asn_geoexecutes./bin/pdb_asn_geo.py --api-key <PDB_KEY> --clean --asn-db asn.sqlite3 --limit 500 --dump-geofeed .cache/pdbdump.txt.pdb_asn_georequires environment variablePDB_KEY; it fails fast if missing.clone_asn_repocloneshttps://github.com/ipverse/asn-ipinto<work_dir>/.tmp-ipverse-asn/asn-ip(URL is hardcoded in the op).clone_ip_geo_repocloneshttps://github.com/ipverse/country-ip-blocksinto<work_dir>/.tmp-ipverse-geo/country-ip-blocks(URL is hardcoded in the op).aggregate_asnexecutespython3 <bin_dir>/aggregate_asns.py --as-dir <asn-repo>/as --output <work_dir>/asn.sqlite3.populate_asn_domainsexecutespython3 <bin_dir>/populate_asn_domains.py --database <work_dir>/asn.sqlite3.build_date_tagcaptures a singleYYYYMMDDtag per run, used for MMDB output filenames.build_asn_mmdbexecutes<bin_dir>/build_mmdb --as-dir <asn-repo>/as --asn-out <work_dir>/ip2asn-nossl-sh-<date>.mmdb, and removes an existing target file first.build_geo_mmdbexecutes<bin_dir>/build_mmdb --country-dir <country-repo>/country --country-out <work_dir>/ip2geo-nossl-sh-<date>.mmdb --geofeed-dir <work_dir>, and removes an existing target file first.run_rdns_georuns<bin_dir>/rdns_geo.pywith--db <ips_db>whenips_dbop config is set; PostgreSQL passthrough is intentionally not used.patch_geo_mmdb_with_rdnsruns<bin_dir>/build_mmdb --patch-mmdb <geo-mmdb> --patch-geofeed <work_dir>/rdns_geo.csvwhen rDNS output is present.update_asn_latest_symlinkandupdate_geo_latest_symlinkupdateip2asn-latest.mmdbandip2geo-latest.mmdb.clone_asn_repoperforms a safe cleanup of<work_dir>/.tmp-ipverse-asnbefore cloning;clone_ip_geo_repodoes the same for<work_dir>/.tmp-ipverse-geo.cleanup_asn_temp_dirandcleanup_geo_temp_dirremove temp dirs at the end of successful runs.build_asn_data_jobandbuild_geo_database_jobhave failure hooks that also remove their temp dirs on failed runs.
- Go entry point:
infra/mmdb-builder/build_mmdb.go - Inputs:
as/<ASN>/aggregated.jsondirectories (parsed for ASN metadata and IPv4/IPv6 prefixes) - Optional country inputs:
<country-dir>/<code>/aggregated.jsondirectories (parsed for country name/code and IPv4/IPv6 prefixes) - Output: ASN MMDB file (
-asn-out, defaultnossl-sh-ip-to-asn.mmdb) - Optional output: country MMDB file (
-country-out, defaultnossl-sh-ip-to-country.mmdb) - Flags:
-as-dir(defaultas),-asn-out,-country-dir,-country-out, and-test-mmdb
- ES modules only (
import/export), no CommonJS. - Keep the
componets/directory name unchanged; other files import it. - When adjusting routes, update both server handlers and template links.
- Preserve no-cache headers on privacy-sensitive endpoints.
- Beacon resolver lookups retry on 404 and reuse the same
uniq; keep this in sync with the client script. - Endpoint IP records are written after responses finish; keep logging non-blocking.
- Service status updates are hardcoded in
templates/service-status.ejs; keep 10 or fewer items and prune older entries. - Prefer analyzing and reusing existing functions; extend minimally, and only add new functionality if existing helpers are insufficient.
- Use existing utility/helper functions directly when they already provide needed normalization/validation; avoid adding thin wrapper helpers that only forward to existing checks.
- For rDNS geo matcher rules, prefer generalized delimiter-bounded location token patterns (for example
.lon.,-lon-,_lon_) with provider/domain scoping when needed; avoid exact-host/service-specific rules unless no safe generalized rule exists. - Avoid editing local data files (
*.mmdb,*.sqlite3,counters.db) unless the task explicitly requires it.