YOUR_API_KEY with your ipk_ key.<!-- IP Check widget — cloud.mkntw.org --> <div id="ipmk-widget"> <div class="ipmk-head"> <span>your ip</span> <a href="https://cloud.mkntw.org" target="_blank" rel="noopener">cloud.mkntw.org</a> </div> <div class="ipmk-body"> <span class="ipmk-ip">—</span> <span class="ipmk-flag"></span> </div> <div class="ipmk-meta"></div> <div class="ipmk-sub"></div> <div class="ipmk-tags"></div> </div> <style> #ipmk-widget{font-family:ui-monospace,'SF Mono',Menlo,monospace;background:#14161b;color:#e4e6ea; border:1px solid rgba(255,255,255,.09);padding:18px 20px;max-width:420px;display:flex;flex-direction:column;gap:10px} #ipmk-widget .ipmk-head{display:flex;justify-content:space-between;font-size:9px;letter-spacing:.08em; text-transform:uppercase;color:#80848c;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,.09)} #ipmk-widget .ipmk-head a{color:#3ad577;text-decoration:none} #ipmk-widget .ipmk-body{display:flex;align-items:baseline;gap:12px;min-height:28px} #ipmk-widget .ipmk-ip{font-size:24px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums} #ipmk-widget .ipmk-flag{font-size:22px;line-height:1} #ipmk-widget .ipmk-meta{font-size:11px;color:#a8acb5} #ipmk-widget .ipmk-sub{font-size:10px;color:#80848c;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} #ipmk-widget .ipmk-tags{display:flex;gap:6px;flex-wrap:wrap;margin-top:4px} #ipmk-widget .ipmk-tag{padding:2px 7px;border:1px solid rgba(255,255,255,.09);font-size:9px; color:#80848c;text-transform:uppercase;letter-spacing:.04em} #ipmk-widget .ipmk-tag.on{border-color:rgba(255,98,98,.4);color:#ff6262} #ipmk-widget .ipmk-tag.warn{border-color:rgba(245,183,64,.4);color:#f5b740} #ipmk-widget .ipmk-tag.ok{border-color:rgba(58,213,119,.4);color:#3ad577} @media(prefers-color-scheme:light){ #ipmk-widget{background:#fff;color:#1a1d24;border-color:rgba(0,0,0,.11)} #ipmk-widget .ipmk-head{color:#6a6f78;border-color:rgba(0,0,0,.11)} #ipmk-widget .ipmk-head a{color:#008a3e} #ipmk-widget .ipmk-meta{color:#4a4f58} #ipmk-widget .ipmk-sub{color:#6a6f78} #ipmk-widget .ipmk-tag{border-color:rgba(0,0,0,.11);color:#6a6f78} #ipmk-widget .ipmk-tag.on{border-color:rgba(184,48,48,.4);color:#b83030} #ipmk-widget .ipmk-tag.warn{border-color:rgba(138,92,0,.4);color:#8a5c00} #ipmk-widget .ipmk-tag.ok{border-color:rgba(0,138,62,.4);color:#008a3e} } </style> <script> (function(){ var KEY = 'YOUR_API_KEY'; // replace with your ipk_... key var r = document.getElementById('ipmk-widget'); function q(s){return r.querySelector(s)} fetch('https://cloud.mkntw.org/api/v1/lookup',{headers:{'X-API-Key':KEY}}) .then(function(x){return x.json()}) .then(function(d){ if(d.error){q('.ipmk-ip').textContent='error';q('.ipmk-meta').textContent=d.error;return} q('.ipmk-ip').textContent = d.ip || '—'; q('.ipmk-flag').textContent = d.flag || ''; q('.ipmk-meta').textContent = [d.city,d.country].filter(Boolean).join(', '); q('.ipmk-sub').textContent = d.isp || d.org || ''; var tags = q('.ipmk-tags'); function t(txt,cls){var s=document.createElement('span');s.className='ipmk-tag'+(cls?' '+cls:'');s.textContent=txt;tags.appendChild(s)} if(d.is_vpn||d.is_proxy) t('VPN','on'); else if(d.is_hosting) t('HOSTING','warn'); else t('DIRECT','ok'); if(d.is_mobile) t('MOBILE'); }) .catch(function(){q('.ipmk-ip').textContent='error'}); })(); </script>
<script src="https://cloud.mkntw.org/embed.js" defer></script> <div data-ipcheck data-theme="auto" data-key="ipk_your_key" data-height="180"></div>
<iframe src="https://cloud.mkntw.org/embed?theme=dark" width="420" height="180" frameborder="0"></iframe>
X-API-Key header or ?key= query* any originX-RateLimit-Limit, X-RateLimit-Remainingconst res = await fetch('https://cloud.mkntw.org/api/v1/lookup', { headers: { 'X-API-Key': 'ipk_your_key_here' } }); const data = await res.json(); console.log(data.ip, data.country, data.is_vpn);
curl https://cloud.mkntw.org/api/v1/lookup \
-H "X-API-Key: ipk_your_key_here"
{ "ip": "1.2.3.4", "country": "Germany", "country_code": "DE", "flag": "🇩🇪", "region": "Berlin", "city": "Berlin", "timezone": "Europe/Berlin", "isp": "Deutsche Telekom AG", "asn": "AS3320", "is_vpn": false, "is_proxy": false, "is_hosting": false, "is_mobile": false, "cached": true, "server_time": "2026-04-07T16:30:00.000Z" }
<script> tag. Visitors matching a rule get a modal, a redirect, or a custom handler.
curl -X POST https://cloud.mkntw.org/api/v1/register \ -H "Content-Type: application/json" \ -d '{"domain":"yoursite.com","name":"My Site"}'
{ "token": "tok_abc123...", "domain": "yoursite.com", "quota_daily": 10000 }
curl -X POST https://cloud.mkntw.org/api/v1/rules \ -H "X-Project-Token: tok_abc123..." \ -H "Content-Type: application/json" \ -d '{"type":"block_country","value":"RU","reason":"regional restriction"}'
block_ipExact IPv4 match, e.g. 1.2.3.4block_countryISO 2-letter code, e.g. RU, CN, IRblock_cityCity name, case-insensitive, e.g. Moscowblock_regionRegion/state name, e.g. Californiablock_asnASN format AS12345block_ispISP substring match, e.g. DigitalOceanblock_vpnBlock all proxy/VPN detected traffic (boolean)block_hostingBlock traffic from hosting providers/datacentersblock_mobileBlock mobile carrier trafficallow_ipWhitelist IP (overrides all block rules)<head>. That's it.
<script src="https://cloud.mkntw.org/guard.js" data-token="tok_your_token_here" defer></script>
.env / process.env for production.
<script src="https://cloud.mkntw.org/guard.js" data-token="tok_..." defer></script>
<Helmet> <script src="https://cloud.mkntw.org/guard.js" data-token={process.env.REACT_APP_IPMK} defer /> </Helmet>
import Script from 'next/script'; <Script src="https://cloud.mkntw.org/guard.js" data-token={process.env.NEXT_PUBLIC_IPMK} strategy="afterInteractive" />
onMounted(() => { const s = document.createElement('script'); s.src = 'https://cloud.mkntw.org/guard.js'; s.dataset.token = import.meta.env.VITE_IPMK; document.head.appendChild(s); });
useHead({ script: [{ src: 'https://cloud.mkntw.org/guard.js', 'data-token': useRuntimeConfig().public.ipmk, defer: true }] });
<svelte:head> <script src="https://cloud.mkntw.org/guard.js" data-token={import.meta.env.VITE_IPMK} defer></script> </svelte:head>
add_action('wp_head', function() { echo '<script src="https://cloud.mkntw.org/guard.js" data-token="' . getenv('IPMK_TOKEN') . '" defer></script>'; });
{{-- resources/views/layouts/app.blade.php --}} <script src="https://cloud.mkntw.org/guard.js" data-token="{{ env('IPMK_TOKEN') }}" defer></script>
{# templates/base.html #} <script src="https://cloud.mkntw.org/guard.js" data-token="{{ IPMK_TOKEN }}" defer></script>
app.use(async (req, res, next) => { const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.ip; const d = await fetch(`https://cloud.mkntw.org/api/v1/check?ip=${ip}`, { headers: { 'X-Project-Token': process.env.IPMK } }).then(r => r.json()); d.allowed ? next() : res.status(403).send('Blocked'); });
export default { async fetch(req, env) { const ip = req.headers.get('cf-connecting-ip'); const d = await fetch(`https://cloud.mkntw.org/api/v1/check?ip=${ip}`, { headers: { 'X-Project-Token': env.IPMK } }).then(r => r.json()); return d.allowed ? fetch(req) : new Response('Blocked', { status: 403 }); } };
@app.before_request def guard(): ip = request.headers.get('X-Forwarded-For', request.remote_addr).split(',')[0] r = requests.get(f'https://cloud.mkntw.org/api/v1/check?ip={ip}', headers={'X-Project-Token': os.environ['IPMK']}).json() if not r.get('allowed'): abort(403)
IPMK_TOKEN=tok_... in your environment file. Server-side integrations keep the token private. Client-side tokens are safe to expose — they are domain-bound & rate-limited.
<script src="https://cloud.mkntw.org/guard.js" data-token="tok_..." data-mode="modal" data-title="Sorry, access denied" data-message="This content is not available in your region." defer></script>
?reason=...&country=...&ip=...).
<script src="https://cloud.mkntw.org/guard.js" data-token="tok_..." data-mode="redirect" data-redirect="/blocked.html" defer></script> // See /blocked-demo for a ready-made blocked page template // URL params sent: ?reason=block_country&country=RU&ip=1.2.3.4
data-ipmk-verdict="blocked" on <html>. Use CSS or JS to handle it.
<script src="https://cloud.mkntw.org/guard.js" data-token="tok_..." data-mode="silent" defer></script> <style> html[data-ipmk-verdict=blocked] .premium-content { display: none; } html[data-ipmk-verdict=blocked] .blocked-notice { display: block; } </style>
<script> window.handleBlock = function(verdict) { console.log('blocked:', verdict); // verdict.ip, verdict.country_code, verdict.matched_rule... alert('Blocked from ' + verdict.country); }; </script> <script src="https://cloud.mkntw.org/guard.js" data-token="tok_..." data-mode="callback" data-on-block="handleBlock" defer></script>
ipmk:allowed and ipmk:blocked events on window.
window.addEventListener('ipmk:allowed', function(e) { console.log('Access allowed:', e.detail.ip); }); window.addEventListener('ipmk:blocked', function(e) { console.log('Blocked:', e.detail.matched_rule); // e.detail = full verdict object });
{"domain":"...","name":"..."}X-Project-TokenX-Project-Token{"type":"...","value":"...","reason":"..."}X-Project-TokenX-Project-Token?ip= (optional — uses client IP by default)allowed: bool, matched_rule, geo datalocalStorage so you can come back later. Use it with guard.js on your own site.
data-mode="redirect", blocked users land on a page with ?reason=...&country=...&ip=... query params. We ship a demo at /blocked-demo — you can use it as-is or copy the HTML to your own /blocked.html.
guard.js installed. Each verified session receives a unique verification ID like ipmk-a1b2c3 for tracking and stats.
/api/v1/check with your token{allowed: bool, matched_rule: ..., ip, country, ...}data-mode/challenge → PoW + fingerprint collectionverification_id issued, cookie set, auto-redirect back/api/v1/challenge/check increments hit_count{active_sessions, total_issued, total_hits, banned_ips}ipmk_session or X-Session headerverification_id, issued_at, hit_count, fp_boundcurl -X POST https://cloud.mkntw.org/api/v1/register \ -H "Content-Type: application/json" \ -d '{"domain":"safevpn.su","name":"SafeVPN production"}' # Response: {"token":"tok_xxx","domain":"safevpn.su","quota_daily":10000,...}
# block all hosting providers (blocks 99% of bots) curl -X POST https://cloud.mkntw.org/api/v1/rules \ -H "X-Project-Token: tok_xxx" \ -H "Content-Type: application/json" \ -d '{"type":"block_hosting","value":"true","reason":"datacenter bots"}' # whitelist your own server IP so admin tools work curl -X POST https://cloud.mkntw.org/api/v1/rules \ -H "X-Project-Token: tok_xxx" \ -H "Content-Type: application/json" \ -d '{"type":"allow_ip","value":"YOUR_SERVER_IP","reason":"admin"}'
<!-- Callback handler: redirect to challenge on block --> <script> window.__ipmkBlocked = function(v) { console.warn('[ipmk] blocked:', v); // Redirect to challenge, return to current URL after success location.href = 'https://cloud.mkntw.org/challenge?to=https://yoursite.com' + encodeURIComponent(location.pathname + location.search); }; </script> <script src="https://cloud.mkntw.org/guard.js" data-token="tok_your_token" data-mode="callback" data-on-block="__ipmkBlocked" defer></script> </head>
allowed: true → page renders normallymatched_rule: block_hosting → __ipmkBlocked() → redirect to /challengeverification_id issued# Public aggregate stats (no PII) curl https://cloud.mkntw.org/api/v1/session/stats # → {"active_sessions":42,"total_issued":1280,"banned_ips":3,...} # Your project rules + hit stats curl -H "X-Project-Token: tok_xxx" \ https://cloud.mkntw.org/api/v1/rules # → {"total_rules":2,"stats":{"total_checks":847,"total_blocks":62,...}}
/challenge?to=/original{challenge, signature, difficulty, issued_at}{challenge, signature, solution}{session, expires_at, expires_in}X-Session or ?session=sess_...{valid: bool} — locked to IP + UA{bot_score: 0-100, verdict: bot|suspicious|likely_human}/challenge using cookie check in nginx:
server { listen 443 ssl; server_name yoursite.com; # Gate premium pages behind challenge location /premium/ { if ($cookie_ipmk_session = "") { return 302 https://cloud.mkntw.org/challenge?to=$scheme://$host$request_uri; } # Serve normal content proxy_pass http://backend; } }
// Check session on page load, redirect to challenge if missing if (!document.cookie.includes('ipmk_session=')) { location.href = 'https://cloud.mkntw.org/challenge?to=' + encodeURIComponent(location.href); }
app.use(async (req, res, next) => { const sid = req.cookies.ipmk_session; if (!sid) { return res.redirect(`https://cloud.mkntw.org/challenge?to=${encodeURIComponent(req.originalUrl)}`); } const r = await fetch(`https://cloud.mkntw.org/api/v1/challenge/check`, { headers: { 'X-Session': sid, 'User-Agent': req.headers['user-agent'] } }).then(r => r.json()); r.valid ? next() : res.redirect('https://cloud.mkntw.org/challenge'); });
# Drop into /etc/ssh/sshd_config.d/hardening.conf PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes KbdInteractiveAuthentication no ChallengeResponseAuthentication no PermitEmptyPasswords no MaxAuthTries 3 LoginGraceTime 30 ClientAliveInterval 300 ClientAliveCountMax 2 AllowUsers deploy # replace with your user Protocol 2 # Apply: sudo sshd -t && sudo systemctl restart ssh
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp # ssh sudo ufw allow 80/tcp # http sudo ufw allow 443/tcp # https sudo ufw limit 22/tcp # rate limit ssh attempts sudo ufw enable sudo ufw status verbose
sudo apt install -y fail2ban # /etc/fail2ban/jail.local cat <<EOF | sudo tee /etc/fail2ban/jail.local [DEFAULT] bantime = 1h findtime = 10m maxretry = 3 backend = systemd [sshd] enabled = true [nginx-http-auth] enabled = true [nginx-botsearch] enabled = true EOF sudo systemctl enable --now fail2ban sudo fail2ban-client status
sudo apt install -y unattended-upgrades apt-listchanges sudo dpkg-reconfigure -plow unattended-upgrades # Verify config: cat /etc/apt/apt.conf.d/50unattended-upgrades | grep -E 'Automatic-Reboot|Mail'
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d yoursite.com -d www.yoursite.com sudo certbot renew --dry-run # verify auto-renewal # Strong DH params (generate once, takes ~5 min): sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
# /etc/nginx/conf.d/security.conf add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; add_header X-Frame-Options "DENY" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always; add_header Content-Security-Policy "default-src 'self'" always; # Rate limit zones limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s; # Usage in server block: # location /api/ { limit_req zone=api burst=20 nodelay; } # location /login { limit_req zone=login burst=5; } # Hide nginx version server_tokens off;
# Create .env with strict permissions touch /opt/myapp/.env chmod 600 /opt/myapp/.env chown myapp:myapp /opt/myapp/.env # Generate strong random secrets: openssl rand -hex 32 # 256-bit for JWT/HMAC openssl rand -base64 48 # 384-bit for sessions # systemd service: load from file, not exposed # EnvironmentFile=/opt/myapp/.env # NoNewPrivileges=true # ProtectSystem=strict # PrivateTmp=true
services:
app:
image: myapp
user: "1000:1000"
read_only: true
tmpfs: [ /tmp, /run ]
cap_drop: [ ALL ]
security_opt:
- no-new-privileges:true
restart: unless-stopped
ports: [ "127.0.0.1:8080:8080" ] # bind to localhost only
# Disable SMBv1 (legacy, insecure) Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart # Disable weak TLS versions, enforce TLS 1.2+ New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Force Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" Enabled 0 # Windows Firewall: default block inbound Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block New-NetFirewallRule -DisplayName "Allow RDP" -Direction Inbound -LocalPort 3389 -Protocol TCP -Action Allow -RemoteAddress "1.2.3.4" New-NetFirewallRule -DisplayName "Allow HTTPS" -Direction Inbound -LocalPort 443 -Protocol TCP -Action Allow # Enable Windows Defender features Set-MpPreference -DisableRealtimeMonitoring $false Set-MpPreference -PUAProtection Enabled Set-MpPreference -MAPSReporting Advanced # Account lockout after 5 failed logins net accounts /lockoutthreshold:5 /lockoutduration:30 /lockoutwindow:30
argon2id for passwords, never md5/sha1 alonecrypto.randomBytes(), never Math.random()api_key_required — missing X-API-Key headerinvalid_key — key not in storeinvalid_key_format — must start with ipk_revoked — key was revokedquota_exceeded — daily quota reached, see reset_atburst_limit — 60 req/min per IP exceededgeo_lookup_failed — upstream geo service error