ipauth
all systems live
Sign in
// HOW IT WORKS

Two URLs. One allowlist that follows you.

Every IPAuth flow has the same two parts. You click an auth URL from your browser whenever your IP changes. Your server polls a server URL on a cron and updates its firewall to match. That's the whole product.

// THE MODEL

Allowlist by default. The low-cost path to Zero Trust.

Zero Trust comes down to one habit: deny everything, then allow only what you can currently verify. The hard part was never the deny. It is keeping the allow current as people and devices move, which is why teams reach for a platform. IPAuth does that with a bookmark and a cron. Default-deny your SSH, your staging, your API, your admin panel, then let each person's live IP flow in through IPAuth and out to the edge you already run.

DEFAULT DENY

Every port and path starts closed. Nothing is reachable until a verified IP is on the list.

PER-PERSON IDENTITY

Each person or service is a named pair you can add, audit, and revoke on its own.

CONTINUOUSLY RE-VERIFIED

The allowlist refreshes every 2 minutes and a stale IP drops itself after 24 hours. No pruning.

No agent, no per-seat license, no vendor stack. Zero Trust posture on an operator budget.

// SYSTEM BOUNDARIES

IPAuth never touches your server.

Both connections initiate from your side. Your browser hits IPAuth. Your server polls IPAuth. We never push anything inbound. The firewall change happens entirely inside your own boundary, by code you control.

IPAuth system boundaries diagram Three boxes: your laptop on the left, ipauth.net in the middle, and your server on the right with a local firewall below it. Arrow 1 goes from laptop to ipauth.net (you click the auth URL). Arrow 2 goes from your server to ipauth.net (server polls for IP). Arrow 3 stays inside your server, going down to the local firewall. A dashed boundary around the server and firewall indicates "your infrastructure". IPAuth never crosses that line. YOUR INFRASTRUCTURE Your laptop browser roams networks ipauth.net /whitelist/?key=... /serverquery/?key=... relay only, no push Your server cron / scheduled task polls every 2 min Local firewall ufw / pf / netsh allow rule for your IP ① click auth URL HTTPS GET ② poll for IP HTTPS GET ③ update rule local exec
① outbound from you

Clicking the auth URL is a normal HTTPS GET from your browser. IPAuth sees your public IP and stores it under your key.

② outbound from your server

Cron polls the server URL on a schedule you choose. Reads the IP IPAuth has stored. Nothing on your box accepts incoming connections from IPAuth.

③ entirely local

Your shell script updates ufw / pf / Windows Firewall. The change never leaves the server. Your control plane stays yours.

// USE CASES · PICK ONE

Six ways teams use IPAuth today.

Choose one on the left. Each is a real pattern we or our customers run. Want the deeper story behind any of them, the problem it solves and how people handle it today, follow the write-up link in each.

Lock SSH to your laptop, even on the road.

You run 5+ servers. Exposing port 22 means constant brute-force noise in auth.log and the risk that a stolen key gets used from anywhere. IPAuth locks 22 to a single IP (yours), and follows you when you move.

Before IPAuth

Open SSH + key auth

  • Port 22 open to 0.0.0.0/0
  • Constant scanner traffic in auth.log
  • fail2ban does some work, but the surface is still global
  • Lost key = global compromise window until you notice
With IPAuth

Port 22 closed except your current IP

  • ufw default-deny on 22
  • One bookmark to click when networks change (coffee shop, hotel, home)
  • Within 2 minutes, ufw allows your new IP
  • Brute-force surface drops to one IP. Your own.

The script (Linux + ufw)

#!/bin/sh
SERVER_URL="https://ipauth.net/serverquery/?key=YOUR_KEY"
STATE=/var/cache/ipauth-last

CURIP=$(curl --max-time 5 -fsS "$SERVER_URL" | grep -oE '"ipaddress":"[0-9.]+' | cut -d'"' -f4)
[ -z "$CURIP" ] && exit 0

OLDIP=$(cat "$STATE" 2>/dev/null)
[ "$CURIP" = "$OLDIP" ] && exit 0
[ -n "$OLDIP" ] && ufw delete allow from "$OLDIP" to any port 22 proto tcp >/dev/null 2>&1
ufw allow from "$CURIP" to any port 22 proto tcp comment "ipauth"
echo "$CURIP" > "$STATE"

Drop it in cron every 2 minutes. The state file at /var/cache/ipauth-last lets the script delete the prior allow before adding the new one, so your firewall never grows. Combine with a bastion failsafe rule (a stable IP you control as a backup recovery path) so you never lock yourself out.

Gate dev / staging HTTPS without a VPN.

You're running staging.mycompany.com on ports 80/443 for previews. A half-built feature your QA team wants to see, a customer demo, a marketing review URL. You don't want it indexed, scraped, or screenshotted by anyone outside the team. A VPN feels heavy. IPAuth gives each team member a personal auth URL; the staging server allows only their current IPs.

Common alternatives

VPN, basic auth, manual allowlist

  • VPN: heavy setup, license costs, agent installs, support burden when it breaks
  • Basic auth: still indexable, password gets shared / leaks, browser-blocking prompts
  • Manual IP list: goes stale the moment anyone hops networks
With IPAuth

Self-service team allowlist

  • Each team member generates their own pair
  • Server's firewall rule for 80/443 is driven by an ipset / multi-IP table
  • Anyone who hops networks just clicks their auth URL. Back in within 2 min.
  • No browser prompt, no shared password, no VPN client

Multi-user variant: ipset + iptables

Each team member has their own pair. The script reads all their server URLs and rebuilds an ipset that's referenced by an iptables rule on ports 80 + 443. Replace the KEYS list with each member's server key.

#!/bin/sh
SET=ipauth_team
KEYS="key_alice key_bob key_carol"

ipset create $SET hash:ip -exist
ipset flush $SET

for K in $KEYS; do
    IP=$(curl --max-time 5 -fsS "https://ipauth.net/serverquery/?key=$K" \
         | grep -oE '"ipaddress":"[0-9.]+' | cut -d'"' -f4)
    [ -n "$IP" ] && ipset add $SET "$IP" -exist
done

Reference the set once in iptables (paired with a default-deny for those ports):

iptables -I INPUT -m set --match-set ipauth_team src \
  -p tcp -m multiport --dports 80,443 -j ACCEPT

Cron every 2 minutes. Works the same way with nftables sets, pf tables, or Windows Firewall remote-address lists. Pick the primitive your stack uses.

Give individuals roving access to a gated resource.

You're a product owner. You want one specific person (your engineering lead, a customer, a contractor) to reach a gated URL behind your firewall or CDN. You don't want to expose the resource publicly, and you don't want to manually paste their current IP every time they switch networks. IPAuth issues each person a private bookmark, bundles them in an access group, and exposes one endpoint your sync script pulls from to keep your allowlist current.

Common alternatives

Open it up, or hand-edit allowlists

  • Public + auth: the URL is still indexable / scannable; auth becomes the only thing standing between you and a bad day
  • VPN per recipient: overkill for one person; license + onboarding pain
  • Manual CDN allowlist: works once, then they hop networks and you're back in the dashboard pasting IPs
  • Cloudflare Access / Zero Trust: powerful but pulls you into a vendor stack you may not want
With IPAuth Access Groups

Per-person bookmark, one allowlist endpoint

  • Create a key-pair named after each person (e.g. "Daniel"); email them the auth URL
  • Bundle their pairs into an access group; the group exposes a single /api/g/<token>/ips.txt endpoint
  • Your local sync script polls that endpoint every 2 min and pushes the IP list to your firewall, CDN, or WAF, replacing the previous set so it stays clean
  • Add / remove people without touching the sync script. Audit log records every action.

The sync script (bash + curl)

Pulls the group's plain-text IP list, stores it in a state file, and only pushes downstream when the set changes. Replaces the prior set, so your firewall never accumulates stale entries even as users hop networks.

#!/bin/sh
GROUP_URL="https://ipauth.net/api/g/YOUR_GROUP_TOKEN/ips.txt"
STATE=/var/cache/ipauth-group.last

NEW=$(curl --max-time 10 -fsS "$GROUP_URL" | tr '\n' ' ' | xargs)
OLD=$(cat "$STATE" 2>/dev/null)
[ "$NEW" = "$OLD" ] && exit 0    # unchanged → no-op

# REPLACE downstream allowlist with current set.
# Example for NOC.org CDN. Swap for your firewall / CDN / WAF.
curl -fsS "https://my.noc.org/api?apikey=$NOC_KEY&action=cdn/set/whitelistedips&website=$DOMAIN&value=$(echo $NEW | jq -sRr @uri)"

echo "$NEW" > "$STATE"

Same pattern works for ufw, iptables, Cloudflare rulesets, AWS security groups, pf tables. Only the downstream push command changes. Keep your firewall lean: always replace, never append.

Gate a page like /login, no VPN, no accounts.

You can't leave /login or /register open to the whole internet, but your users roam between networks and you don't want to hand each of them an account. Drop a small middleware in front of the page. Invite each user once; they click their personal bookmark, which marks that browser as a safe browser with a short-lived signed cookie, and the page opens. It follows the browser, not the IP, so it works from anywhere, and you can revoke any one browser from the dashboard.

Before IPAuth

Login / admin page open to the world

  • Anyone can reach /login and probe it
  • IP allowlists break every time a user changes networks
  • A VPN or full SSO rollout is heavy for a handful of people
  • Giving everyone an account is more surface, not less
With IPAuth

Safe-browser cookie at the page

  • Middleware checks for a signed IPAuth cookie. No cookie, no page.
  • Each invited user clicks their bookmark once to authorize the browser
  • Protect one path (/login) or the whole app
  • See every active browser and revoke any one in a click

The middleware (PHP example)

One file, no dependencies beyond PHP's built-in crypto. Turn it on for the whole app without touching your code:

# php-fpm (Apache or nginx): a .user.ini in your web root
auto_prepend_file=/var/www/ipauth-gate.php

Register the app in your dashboard, link a group, and it hands you the file and the exact config. References ship for PHP and FastAPI, and the same signed-cookie check drops into nginx, any framework, or the NOC edge with no app code.

We run this

Keep your API closed to the world, open to your devs as they roam.

Our own API sits behind NOC, our CDN and WAF. The edge is default-deny. Every developer has an IPAuth pair, bundled into one access group. A cron pushes the group's live IP list to NOC's allowlist for the API hostname every 2 minutes. A dev moves from the office to home to a hotel, clicks one bookmark, and their new IP is allowed at the edge within 2 minutes. To everyone else the API does not answer.

Static edge allowlist

Goes stale the moment anyone moves

  • Hand-pasted dev IPs in the CDN rule
  • Someone hops networks and gets locked out, or you leave it wide
  • Offboarding means hunting for the right line to delete
IPAuth group to NOC

The allowlist follows the team

  • Each dev is a named pair in one group
  • NOC allowlist for the API is rebuilt from the group's live IPs every 2 min
  • Add or revoke a dev in the dashboard, the edge follows
  • API key plus allowlisted IP: two factors, not one

The sync (IPAuth group to NOC allowlist)

#!/bin/sh
GROUP_URL="https://ipauth.net/api/g/YOUR_GROUP_TOKEN/ips.txt"
STATE=/var/cache/ipauth-noc.last

NEW=$(curl --max-time 10 -fsS "$GROUP_URL" | tr '\n' ' ' | xargs)
OLD=$(cat "$STATE" 2>/dev/null)
[ "$NEW" = "$OLD" ] && exit 0      # unchanged, no-op

# Replace NOC's allowlist for the API hostname with the current set.
curl -fsS "https://my.noc.org/api?apikey=$NOC_KEY&action=cdn/set/whitelistedips&website=$API_DOMAIN&value=$(echo $NEW | jq -sRr @uri)"

echo "$NEW" > "$STATE"

Always replace, never append, so the edge stays lean as devs roam. The same pattern protects the IPAuth API itself, and swaps cleanly for Cloudflare, a WAF rule, or a cloud security group.

An API credential that is useless when stolen.

Your provisioning box or CI runner holds one IPAuth API key to register servers and manage allowlists. API keys leak: a committed env file, a CI log, a screenshot. IPAuth lets you bind a key's second factor, its allowed origin, to a roving IP that IPAuth itself tracks. The box reports its IP through a bookmark, and the key then authenticates only from whatever IP that bookmark currently reports. The allowed origin follows the box automatically, and a stale IP stops authorizing on its own after 24 hours.

A normal API key

One secret, works anywhere

  • Leaks into a log or repo and it works from any IP on earth
  • You find out after it is abused, then scramble to rotate
  • Broad scopes plus global reach is the worst pairing
A key locked to a roving IP

Dead from anywhere but your box

  • Key authenticates only from the IP its bookmark currently reports
  • The allowed origin follows your provisioning box as it moves
  • Leaked key from any other IP gets a 403 on arrival
  • This is how we register every new server in our fleet

Provision from the locked box

Mint the key in the dashboard with "lock to a roving IP" ticked. From the box, register each new server as a pair and read back the poll URL. The same key from anywhere else fails closed.

#!/bin/sh
# Runs on your provisioning box, whose IP IPAuth tracks via the key's bookmark.
curl -fsS https://ipauth.net/api/v1/pairs \
  -H "Authorization: Bearer $IPAUTH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"web-prod-07"}'
# 201 with the server poll URL. From any unlisted IP: 403 forbidden_origin.
// THE FLOW

Same three steps for any use case.

You click the auth URL

From any browser. IPAuth records the IP that hit it.

Your server polls the server URL

Cron / scheduled task hits it every few minutes. Reads the current registered IP.

The firewall updates

Your shell script swaps the allow rule. Any port you choose, any service.

// READY

Give it a try. It's free.

Generate a pair and wire up your first server in under 5 minutes.

Create a key pair