Web-Check is useful when you want to see your website the way the outside world sees it.

Point it at a domain and it collects public-facing signals: TLS, DNS, HTTP headers, cookies, trackers, mail records, redirects, open ports, sitemap, social tags, server status, technology fingerprints, screenshots, and more.

That makes it a good homelab tool before exposing a new service through a reverse proxy or tunnel.

It also means you should self-host it carefully. Web-Check is not just a dashboard. It performs outbound checks against user-supplied targets.

What is Web-Check?

Web-Check is an open-source website intelligence and inspection tool by Alicia Sykes.

The project describes itself as:

Comprehensive, on-demand open source intelligence for any website.

I inspected:

repo: https://github.com/lissy93/web-check
commit: b4b8a97ed36cde83a0e484fc4f7472b5e2f87af5
package version: 2.3.2
latest GitHub release observed: 2.3.0
license: MIT

The small version mismatch is intentional to mention: the cloned source has 2.3.2 in package.json, and the Docker registry has a matching 2.3.2 image tag. The GitHub Releases page I checked still listed 2.3.0 as the latest release.

What Does It Check?

Web-Check groups its checks into practical website categories:

  • Security: TLS, certificates, headers, cookie flags, DNSSEC, HSTS, CAA, security.txt, threats, block lists, firewall signals, open ports.
  • Domain and DNS: DNS records, TXT records, nameservers, WHOIS/domain info, subdomains, DNS server details.
  • Server: IP, hosting location, server status, traceroute, open ports, technology stack.
  • Email: MX, SPF, DKIM, DMARC, mail-related DNS configuration.
  • SEO: robots.txt, sitemap, redirects, linked pages, social tags, rank, archives.
  • Performance: Lighthouse/PageSpeed-style quality checks, response timing, carbon estimate.
  • Privacy: cookies, trackers, third-party technology, WHOIS exposure, threat-list signals.

It is not a continuous monitor. It is an on-demand inspection workbench.

Think of it as a public-surface review tool: “what does this domain reveal right now?”

Tech Overview

The current Web-Check source is a modern JavaScript web app:

Layer Technology
Frontend/pages Astro 7, React 19, Svelte 5
Server Node.js 22 and Express 5
API checks Individual JavaScript handlers under api/
Browser automation Puppeteer and Chromium
Detection Wappalyzer, Ghostery tracker data, Cheerio, whoiser
Deployment Docker, Node server, Vercel, Netlify, Render

The Docker image is self-contained. It serves the frontend and all /api endpoints from one Node process.

At runtime, the flow is:

browser UI -> /api/{check}?url=target -> Express -> api/*.js -> JSON result -> result cards

The main server file dynamically registers every JavaScript check handler under api/. It also provides /healthz, optional rate limiting, CORS settings, and a single /api route that can run all checks together.

The frontend job registry decides which API endpoint powers each result card. A separate analyzer registry turns raw results into findings and advisories.

Self-Hosting Web-Check with Docker

There was already a Home-Lab webcheck folder, but it was using an unpinned image and had no scanner-specific guardrails.

I updated it to:

  • pin ghcr.io/lissy93/web-check:2.3.2;
  • keep the existing host port 6160;
  • enable API rate limiting;
  • set a 30 second API timeout;
  • block loopback, private, link-local, and CGNAT address ranges by default;
  • keep optional API keys empty unless supplied through the environment.

The reusable Home-Lab config is here:

services:
##Web Info
  webcheck:
    container_name: Web-Check
    image: lissy93/web-check
    mem_limit: 4g
    cpu_shares: 768
    security_opt:
      - no-new-privileges:true
    restart: on-failure:5
    ports:
      - 6160:3000

Start it:

docker compose up -d

Then open:

http://localhost:6160

The Home-Lab compose maps host port ${WEB_CHECK_PORT:-6160} to container port 3000, so the UI is on http://localhost:6160 unless you override WEB_CHECK_PORT in a local .env file.

Stop it:

docker compose down

Optional API Keys

Web-Check works without keys, but some checks are limited or unavailable without external services.

Useful optional variables:

Variable What it helps with
GOOGLE_CLOUD_API_KEY PageSpeed Insights and Safe Browsing style checks
SHODAN_API_KEY host, server, and vulnerability information
CLOUDMERSIVE_API_KEY Cloudmersive threat scan
TRANCO_USERNAME / TRANCO_API_KEY Tranco ranking limits
GITHUB_TOKEN GitHub rate limit for social presence
CERTSPOTTER_TOKEN CertSpotter rate limit for subdomain discovery

Do not put real keys in the public compose file. Use a local .env file on the machine that runs the container.

Safe Exposure Notes

This is the most important operational point.

Web-Check makes outbound requests based on a target supplied by the user. A public instance can become an externally-triggerable scanner if you expose it without controls.

For a private LAN tool, the default Home-Lab compose is enough to start experimenting.

For anything public:

  • put it behind authentication;
  • keep API_ENABLE_RATE_LIMIT=true;
  • keep API_BLOCKED_HOSTS configured;
  • consider disabling ports and trace-route;
  • set a realistic PUBLIC_API_TIMEOUT_LIMIT;
  • use a reverse proxy or tunnel with request limits;
  • do not allow it to reach private infrastructure.

The inspected source includes skip logic for disabled checks, enabled-only checks, blocked hosts, public-only checks against private targets, and a global instance disable switch. Those controls are useful, but they only help if you configure them intentionally.

Field Test

I tested the pinned container through the updated Home-Lab compose.

Validation command:

docker compose config

Start command:

docker compose up -d

Health check:

curl -fsS http://127.0.0.1:6160/healthz

Observed response:

{"status":"ok","ready":true,"version":"2.3.2","uptime":2,"timestamp":"2026-10-06T08:19:51.507Z"}

Basic public status check:

curl -fsS 'http://127.0.0.1:6160/api/status?url=https%3A%2F%2Fexample.com'

Observed response:

{"isUp":true,"responseCode":200,"responseTime":33,"timings":{"dns":5,"connect":4,"tls":11,"wait":13,"download":0}}

Then I stopped the test container:

docker compose down

That confirms the image starts, registers API handlers, serves /healthz, and can run a basic public HTTPS check.

How It Compares

Web-Check sits between a few tool categories.

It is broader than a single SSL checker or HTTP header checker because it combines DNS, TLS, headers, email records, SEO metadata, trackers, screenshots, technology detection, and external reputation signals.

It is not the same as LinkChecker. LinkChecker is better for crawling a site and finding broken internal links, missing assets, bad anchors, and redirect noise.

It is not the same as Uptime Kuma or Checkmate. Those tools repeatedly monitor whether something is up. Web-Check answers a different question: what does this website reveal when inspected on demand?

It is also not a replacement for a serious vulnerability scanner. It can surface public indicators, but it does not authenticate into your app or prove exploitability.

Conclusion

Web-Check is a practical tool to keep around if you self-host websites, expose services through tunnels, manage domains, or care about public security posture.

I like it most as a pre-flight check: run it before and after changing DNS, TLS, reverse proxy headers, email records, or public exposure.

Just treat it with the respect you would give any scanner. On a trusted LAN, it is convenient. On the public internet, it needs authentication, rate limits, blocked private targets, and a clear idea of which checks you want to allow.

FAQ

Is Web-Check self-hostable?

Yes.

The simplest path is Docker:

docker run -p 3000:3000 lissy93/web-check

For a reusable homelab setup, use Compose and pin the image tag instead of running latest.

Can Web-Check be deployed as a static site?

Not with full functionality.

The UI can be built as frontend assets, and the project supports serverless-style deployments on Vercel and Netlify, but the checks require backend API handlers. The Docker deployment runs a Node/Express server so the API and GUI work together locally.

Does Web-Check need a database?

No.

There is no Postgres, Redis, SQLite, or object storage service in the default self-hosted setup. The Docker image is a single application container.

Does Web-Check need API keys?

No for the basic experience.

Some checks use third-party services or have better rate limits with keys. Shodan, Google, Tranco, GitHub, CertSpotter, and Cloudmersive are optional integrations, not required core infrastructure.

For the Home-Lab compose, put those values in a local .env file next to docker-compose.yml, for example:

cd webcheck
cp .env.sample .env

Then edit .env locally. Do not commit real keys.

Variable What it unlocks
GOOGLE_CLOUD_API_KEY PageSpeed/quality checks and Google Safe Browsing inside the threats check
SHODAN_API_KEY Shodan-backed host names, server info, and vulnerability findings
CLOUDMERSIVE_API_KEY Cloudmersive website threat scan
TRANCO_USERNAME / TRANCO_API_KEY Higher Tranco rank-check limits
GITHUB_TOKEN Higher GitHub rate limits for social-presence checks
CERTSPOTTER_TOKEN Higher CertSpotter rate limits for subdomain discovery

Without those keys, Web-Check still runs the core local checks: status, headers, TLS, SSL certificate, DNS records, WHOIS, HSTS, DNSSEC lookup, mail records, cookies, trackers, mixed content, sitemap, robots.txt, social tags, open ports, block-list checks, and similar public probes. The exact set can vary by version and network conditions.

Can I expose Web-Check publicly?

You can, but do not expose it casually.

Because users can submit targets for scanning, a public instance should sit behind authentication and rate limiting. Keep API_BLOCKED_HOSTS configured so users cannot point the scanner at private networks or local services.

How did I use Web-Check locally for fossengineer.com?

I started the Home-Lab compose file, opened the UI at http://localhost:6160, called Web-Check’s local API on 127.0.0.1:6160, and then stopped the container afterwards:

docker compose up -d
curl -fsS http://127.0.0.1:6160/healthz
curl -fsS 'http://127.0.0.1:6160/api/status?url=https%3A%2F%2Ffossengineer.com'
curl -fsS 'http://127.0.0.1:6160/api/ssl?url=https%3A%2F%2Ffossengineer.com'
curl -fsS 'http://127.0.0.1:6160/api/headers?url=https%3A%2F%2Ffossengineer.com'
docker compose down

That quick local check showed Web-Check itself was healthy on version 2.3.2, fossengineer.com returned HTTP 200, TLS validation passed, and the certificate was issued for fossengineer.com by Google Trust Services. The headers check also confirmed Cloudflare was in front of the site and returned security headers such as content-security-policy, strict-transport-security, x-content-type-options, and x-frame-options.

That was not the same as running the full Web-Check UI report. The hosted UI can run dozens of jobs, including DNS records, WHOIS, server location, open ports, DNSSEC, CAA, email configuration, crawler rules, sitemap, screenshot, carbon estimate, social tags, and third-party checks. My local curl run only asked for a small subset of endpoints.

To get the richer report locally, start the container, open http://localhost:6160, enter the target domain, and let the UI finish its job queue. Results should be broadly comparable to the hosted Web-Check demo when using the same Web-Check version, but external API keys, network location, rate limits, and optional integrations can change some panels.

I treated the command-line run as a smoke test, not a formal security audit. It proved that the local Web-Check container could inspect a real public site and that the target was reachable with valid TLS and readable response headers.

What did the full local Web-Check run find for fossengineer.com?

I also ran the aggregate endpoint locally:

docker compose up -d
curl -fsS --max-time 120 'http://127.0.0.1:6160/api?url=https%3A%2F%2Ffossengineer.com' \
  -o fossengineer-webcheck-full.json
docker compose down

That /api?url=... command is the command-line equivalent of asking the self-hosted API to run all registered checks for a target. The browser UI at http://localhost:6160 is usually easier for reading the results, while the aggregate API is useful when you want a JSON artifact.

Can I curl the hosted Web-Check service instead?

Sometimes, but do not build your workflow around it.

The hosted https://web-check.xyz service exposes the public Web-Check UI and links to API documentation, but direct curl requests to hosted API routes may be blocked, rate-limited, or protected by the hosting provider. When I tried this from my local machine:

curl -i 'https://web-check.xyz/api/status?url=https%3A%2F%2Ffossengineer.com'
curl -i 'https://web-check.xyz/api?url=https%3A%2F%2Ffossengineer.com'

both returned HTTP 403. Adding a browser-like User-Agent did not change that result.

For repeatable command-line usage, self-host the Docker container and curl your own instance:

curl -fsS 'http://127.0.0.1:6160/api?url=https%3A%2F%2Ffossengineer.com'

That avoids hosted-service limits, lets you choose which optional API keys are configured, and keeps your scans under your own operational controls.

That local aggregate run returned 40 registered API checks: 36 completed, 3 were skipped, and 1 returned an error. The skipped checks were expected because the local compose did not include optional SHODAN_API_KEY or GOOGLE_CLOUD_API_KEY values. The CAA check returned a DNS SERVFAIL from the resolver path used by that local run, while the hosted UI reported no CAA records.

The useful findings were:

  • Availability: HTTP 200, with Web-Check measuring a 342 ms response from the local run.
  • TLS: valid Google Trust Services certificate, TLS 1.3, TLS_AES_256_GCM_SHA384, HTTP/2 via ALPN, forward secrecy enabled, and the certificate valid from 2 October 2026 to 31 December 2026.
  • HSTS: enabled with max-age=31536000; includeSubDomains; preload, and Web-Check marked it compatible with the HSTS preload list.
  • Cloudflare: detected as the CDN/WAF provider. The location result reflected Cloudflare’s anycast edge from the local vantage point, so it differed from the hosted run’s Toronto edge.
  • DNS and mail: Cloudflare nameservers, Proton Mail MX records, SPF present, DMARC present, and DANE detected for the Proton Mail hosts.
  • HTTP security headers: CSP, HSTS, x-content-type-options, x-frame-options, and referrer-policy were present. Web-Check also noted missing permissions-policy, cross-origin-opener-policy, cross-origin-resource-policy, and cross-origin-embedder-policy.
  • Gaps to consider: no security.txt, DNSSEC not enabled, no llms.txt, and no CAA record result from the local run.
  • Content and SEO signals: Hugo 0.161.0 detected, canonical URL set to https://fossengineer.com/, sitemap parsed with 255 URLs, 35 internal links found on the homepage, and no external homepage links in that check.
  • Privacy and third parties: no cookies detected in that run, Cloudflare Insights detected as the only tracker family, and one third-party script without SRI was reported.
  • Reputation/blocking: no domain breaches were found, PhishTank did not list the domain, and common DNS block-list resolvers did not block it. Google Safe Browsing was not checked locally because no Google API key was configured.
  • Ports: Web-Check reported ports 80, 443, and 8080 open on the Cloudflare-fronted target. Interpret that as Cloudflare edge exposure, not necessarily the origin server.
  • Carbon estimate: initial HTML was about 32 KB, adjusted transfer size about 8.6 KB, with an estimated 1.19 mg CO2 for the initial load.

So yes, the local Docker instance can produce the same style of report as the hosted Web-Check UI. The exact panels and values can differ because of API keys, resolver behavior, Cloudflare anycast location, external service rate limits, and whether you run the UI job queue or the aggregate API endpoint.

Should I disable any checks?

For a private LAN instance, probably not at first.

For a public instance, consider disabling ports and trace-route, or use API_ENABLED_CHECKS to allow only the checks you actually need.

Is Web-Check the same as LinkChecker?

No.

Web-Check inspects a target’s public website, DNS, TLS, headers, email, SEO, privacy, and infrastructure signals. LinkChecker recursively checks links and assets across pages. They complement each other well.