denyfirst.

Porch by denyfirst

Look closer.
Know what answers.

What your infrastructure presents to the outside world: the TLS handshake and certificate, how the site is reached, and what the domain's DNS says about its mail. Each finding cites the rule behind it, and what could not be measured is said.

TLS & certificatesWeb reachMail policyDNSName inventory

How it works

Try itLive

Our domain.
A real result.

Domain

denyfirst.dev — this server

Checks
Names which names under the domain its certificates, its own records and its zone publish informational

This deployment checks only the domains this project runs. To check yours, run Porch yourself.

How it works

From connection
to clarity.

Here it checks our own domain. Run it yourself for the infrastructure you are responsible for.

01 / Connect

Ask what a client asks.

Handshakes at each TLS version, one request for the front page, and the DNS records a mail server reads. Nothing is sent that a browser or a mail server would not send.

02 / Examine

Grade against a named rule set.

Each check has its own rule set, and every finding cites the standard it rests on. Where no standard sets a line, the fact is reported rather than graded.

03 / Understand

Start with what matters.

Each check leads with its verdict and its findings, with the tables and limits underneath. Your own copy lets you save every report.

Get started

Your own copy,
in three steps.

Docker on the server, and nothing else. The image is named by its digest, and the compose file that names it is signed.

  1. Get it

    One paste puts the compose file shown below on the server, with its signed checksums, and checks both. It carries the release key rather than fetching it. The last line has to print Good "file" signature with the key SHA256:ut6bginhZ4lZINMSXNDv3vJ6fyvmDHhtnoBJH0/Nr9Y and docker-compose.yml: OK. If a check fails, the compose file is removed and the next step has nothing to start. What each check proves.

    on the server
    mkdir -p porch && cd porch
    for f in docker-compose.yml SHA256SUMS SHA256SUMS.sig; do curl -fsSLO "https://github.com/denyfirst/porch/releases/latest/download/${f}"; done
    echo 'releases@denyfirst.dev ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDD7Ie9zRf76RynH052/Abkv5k2nzosQd2DihyQMixVR' > allowed_signers
    ssh-keygen -Y verify -f allowed_signers -I releases@denyfirst.dev -n file -s SHA256SUMS.sig < SHA256SUMS && sha256sum --ignore-missing -c SHA256SUMS || { rm -f docker-compose.yml; echo 'STOP: docker-compose.yml did not verify and was removed'; }
  2. Start it

    Make the data directory and start it. Proof of control and a password are always on.

    on the server
    mkdir -p porch-data && sudo chown 65534:65534 porch-data
    docker compose up -d
  3. Open it

    It listens only on the server itself. Reach it through SSH, then open http://localhost:8080.

    on your computer
    ssh -L 8080:127.0.0.1:8080 you@your-server

What you are about to run: docker-compose.yml

What step 1 puts on your server, to read before it runs. Nothing to copy here: the copy that runs is the one step 1 checked.

docker-compose.yml
services:
  porch:
    image: ghcr.io/denyfirst/porch@sha256:a2af6b0c8c7f940961f14a653aafdf99ee96dfcac63dcb17d01564ab43fd0a18
    command:
      - "-listen"
      - "0.0.0.0:8080"
      - "-verification-secret-file"
      - "/data/secret"
      - "-access-file"
      - "/data/access"
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - /etc/ssl/certs:/etc/ssl/certs:ro
      - ./porch-data:/data
    environment:
      SSL_CERT_DIR: /etc/ssl/certs
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    restart: unless-stopped
  scan:
    image: ghcr.io/denyfirst/porch@sha256:a2af6b0c8c7f940961f14a653aafdf99ee96dfcac63dcb17d01564ab43fd0a18
    profiles: ["cli"]
    entrypoint: ["/porch-scan", "-verification-secret-file", "/data/secret"]
    volumes:
      - /etc/ssl/certs:/etc/ssl/certs:ro
      - ./porch-data:/data:ro
    environment:
      SSL_CERT_DIR: /etc/ssl/certs
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL

To upgrade, run step 1 again in the same directory, then docker compose up -d. To remove it, docker compose down --rmi all, then delete the directory and the DNS record. Everything else is in the self-hosting guide.

For your own infrastructure

Run Porch where you work.

Self-hosted, with proof of control for every domain, and nothing sent to us.

Self-hosting guide