Infrastructure
· 17 checks — DNS, redirects, IPv6, crawlability, URL variants, and domain intelligence rolled into one auditable list.FRedirect ChainAction4 redirect(s), 1184 ms totalFIX
https://mindmx.org
270 ms · HTTP/1.1
https://desk.mindmx.org/
112 ms · HTTP/1.1
https://auth.mindmx.org/application/o/au...
350 ms · HTTP/1.1
https://auth.mindmx.org/flows/-/default/...
303 ms · HTTP/1.1
https://auth.mindmx.org/if/flow/default-...
150 ms · HTTP/1.1 FINAL
| # | URL | Status | Time | Protocol | Server |
|---|---|---|---|---|---|
| 1 | https://mindmx.org | 301 | 270 ms | HTTP/1.1 | cloudflare |
| 2 | https://desk.mindmx.org/ | 302 | 112 ms | HTTP/1.1 | cloudflare |
| 3 | https://auth.mindmx.org/application/o/au... | 302 | 350 ms | HTTP/1.1 | cloudflare |
| 4 | https://auth.mindmx.org/flows/-/default/... | 302 | 303 ms | HTTP/1.1 | cloudflare |
| 5 | https://auth.mindmx.org/if/flow/default-... | 200 | 150 ms | HTTP/1.1 | cloudflare |
See the visual redirect chain in the HTTP Probe tab →
Each redirect adds latency. Try to minimize the chain to 1 hop.
Redirect chain — each hop adds latency; combine into one redirect where possible.
Source: Google Search Central / web.dev
If permanent, use 301 instead.
302 (Found) is for genuinely temporary redirects — if this redirect is permanent, switch to 301 to preserve SEO equity.
Learn more ▾ ▴
Search engines treat 302 as temporary, keeping the original URL indexed and not transferring full link equity to the destination. Use 301 (Moved Permanently) for permanent redirects (HTTP→HTTPS, www-vs-non-www, URL restructures).
Source: Google Search Central
BCAA RecordsNo CAA records (any CA may issue certificates)REVIEW
CReverse DNSAction0/4 IPs match cert SANREVIEW
CCrawlabilityActionrobots.txt present, sitemap with 0 URLsREVIEW
Search engines may not be able to parse the sitemap. Fix XML validation errors.
An unparseable sitemap is silently ignored by Google — the URLs it advertises are never queued for crawl.
Learn more ▾ ▴
Google's sitemap parser is strict about XML validity. A single unescaped `&` or unclosed tag invalidates the whole file. Run your sitemap through a validator (Search Console's Sitemaps report flags it) and fix the offending entry. Most generators escape correctly; mistakes usually come from manually-written entries.
Source: sitemaps.org / Google Search Central
An empty sitemap provides no value. Add <url> entries for your pages.
An empty sitemap signals 'no content to index' to Google — actively harmful versus having no sitemap at all.
Learn more ▾ ▴
Google compares URLs in the sitemap against URLs it has crawled. An empty sitemap on a site with thousands of pages signals abandonment. Either populate it correctly (most CMSes auto-generate) or delete the file and let Google crawl normally.
Source: Google Search Central / sitemaps.org
Add a 'Sitemap:' directive to robots.txt so search engines can discover your sitemap.
robots.txt omits Sitemap: directive — crawlers must fetch /sitemap.xml by convention; reliable but missing the explicit hint.
Source: sitemaps.org
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>desk.mindmx</title>
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
<link rel="shortcut icon" href="/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="desk.mindmx" />
<link rel="manifest" href="/favicon/site.webmanifest" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
<link href="https://cdn.jsdelivr.net/npm/quill@2.0.2/dist/quill.snow.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.2/dist/quill.js"></script>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0d0d0f;
--bg2: #111114;
--bg3: #16161a;
--bg4: #1e1e24;
--bg5: #26262e;
--line: rgba(255,255,255,0.06);
--line2: rgba(255,255,255,0.10);
--text: #c8c8d0;
--text-dim: #666676;
--text-bright:#f0f0f4;
--accent: #00d4ff;
--accent-dim: rgba(0,212,255,0.12);
--accent-glow:rgba(0,212,255,0.25);
--vpn: #e8922a;
--vpn-dim: rgba(232,146,42,0.15);
--admin-c: #e05555;
--admin-dim: rgba(224,85,85,0.15);
--mfa: #5b8dee;
--mfa-dim: rgba(91,141,238,0.15);
--green: #3dba6e;
--red: #e05555;
--radius: 12px;
--radius-sm: 6px;
--header-h: 56px;
--font: 'Outfit', sans-serif;
--font-body: 'Inter', sans-serif;
--header-bg: rgba(13,13,15,0.85);
--card-bg: linear-gradient(135deg,rgba(255,255,255,0.04) 0%,rgba(255,255,255,0.02) 100%);
--card-shine: rgba(255,255,255,0.06);
--card-hover-shadow: 0 8px 32px rgba(0,0,0,0.4), 0 0 0 1px rgba(0,212,255,0.18);
--card-hover-border: rgba(0,212,255,0.22);
--avatar-text: #fff;
--scrollbar-thumb: #26262e;
}
html, body { width:100%; height:100%; background:var(--bg); color:var(--text); font-family:var(--font-body); overflow:hidden; transition: background 0.3s, color 0.3s; }
#root { width:100%; height:100%; }
::-webkit-scrollbar { width:5px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--scrollbar-thumb); border-radius:3px; }
@keyframes fadeUp { from{opacity:0;transform:translateY(14px)} to{opacity:1;transform:translateY(0)} }
@keyframes fadeIn { from{opacity:0} to{opacity:1} }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
@keyframes slideRight { from{transform:translateX(100%);opacity:0} to{transform:translateX(0);opacity:1} }
@keyframes slideLeft { from{transform:translateX(0);opacity:1} to{transform:translateX(100%);opacity:0} }
.fade-up { animation: fadeUp 0.45s cubic-bezier(0.16,1,0.3,1) both; }
.fade-in { animation: fadeIn 0.3s ease both; }
.slide-in { animation: slideRight 0.35s cubic-bezier(0.16,1,0.3,1) both; }
.app-card {
transition: transform 0.2s cubic-bezier(0.16,1,0.3,1), box-shadow 0.2s ease, border-color 0.2s ease;
}
.app-card:hover {
transform: translateY(-3px) scale(1.01);
box-shadow: var(--card-hover-shadow);
border-color: var(--card-hover-border) !important;
}
.app-card:active { transform:translateY(0) scale(0.99); }
.status-online { animation: pulse 2.5s ease-in-out infinite; }
.dropdown-enter { animation: fadeUp 0.2s cubic-bezier(0.16,1,0.3,1) both; }
.header-blur { backdrop-filter:blur(20px) saturate(1.4); -webkit-backdrop-filter:blur(20px) saturate(1.4); }
.menu-item {
display:flex; align-items:center; gap:10px;
padding:9px 14px; text-decoration:none;
color:var(--text); font-size:13px; font-family:var(--font);
border-bottom:1px solid var(--line); transition:background 0.1s; cursor:pointer;
background:transparent; border-left:0; border-right:0; border-top:0; width:100%; text-align:left;
}
.menu-item:hover { background:var(--bg4); }
.menu-item:last-child { border-bottom:none; }
.pref-overlay {
position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:200;
animation: fadeIn 0.2s ease both;
}
.pref-panel {
position:fixed; top:0; right:0; bottom:0; width:360px;
background:var(--bg3); border-left:1px solid var(--line2);
display:flex; flex-direction:column; z-index:201;
box-shadow:-24px 0 64px rgba(0,0,0,0.5);
}
.pref-panel.open { animation: slideRight 0.35s cubic-bezier(0.16,1,0.3,1) both; }
/* Quill editor overrides for dark theme */
.ql-toolbar.ql-snow { border-color: var(--line2) !important; background: var(--bg4); border-radius: 8px 8px 0 0; }
.ql-container.ql-snow { border-color: var(--line2) !important; background: var(--bg2); border-radius: 0 0 8px 8px; font-family: var(--font-body); font-size: 13px; color: var(--text); min-height: 150px; }
.ql-editor { color: var(--text); min-height: 150px; }
.ql-editor.ql-blank::before { color: var(--text-dim); font-style: normal; }
.ql-snow .ql-stroke { stroke: var(--text-dim) !important; }
.ql-snow .ql-fill { fill: var(--text-dim) !important; }
.ql-snow .ql-picker-label { color: var(--text-dim) !important; }
.ql-snow .ql-picker-options { background: var(--bg3) !important; border-color: var(--line2) !important; }
.ql-snow .ql-picker-item { color: var(--text) !important; }
.ql-snow button:hover .ql-stroke, .ql-snow button.ql-active .ql-stroke { stroke: var(--accent) !important; }
.ql-snow button:hover .ql-fill, .ql-snow button.ql-active .ql-fill { fill: var(--accent) !important; }
/* Editor modal */
.editor-overlay { position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:300; animation: fadeIn 0.2s ease both; display:flex; align-items:center; justify-content:center; }
.editor-modal { width:700px; max-width:95vw; max-height:90vh; background:var(--bg3); border:1px solid var(--line2); border-radius:16px; display:flex; flex-direction:column; box-shadow:0 32px 80px rgba(0,0,0,0.5); animation: fadeUp 0.3s cubic-bezier(0.16,1,0.3,1) both; overflow:hidden; }
.editor-field { display:flex; flex-direction:column; gap:6px; }
.editor-field label { font-size:11px; font-weight:600; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.08em; font-family:var(--font); }
.editor-input { padding:8px 12px; border-radius:8px; border:1px solid var(--line2); background:var(--bg2); color:var(--text); font-size:13px; font-family:var(--font-body); outline:none; transition:border-color 0.15s; }
.editor-input:focus { border-color:var(--accent); }
.editor-input::placeholder { color:var(--text-dim); }
select.editor-input { cursor:pointer; }
.editor-btn { padding:8px 18px; border-radius:8px; border:none; font-size:12px; font-weight:600; font-family:var(--font); cursor:pointer; transition:all 0.15s; }
.editor-btn-primary { background:var(--accent); color:#000; }
.editor-btn-primary:hover { filter:brightness(1.1); }
.editor-btn-danger { background:var(--admin-dim); color:var(--admin-c); border:1px solid rgba(224,85,85,0.3); }
.editor-btn-danger:hover { background:rgba(224,85,85,0.25); }
.editor-btn-ghost { background:transparent; color:var(--text-dim); border:1px solid var(--line2); }
.editor-btn-ghost:hover { background:var(--bg4); color:var(--text); }
/* Confirm dialog */
.confirm-overlay { position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:400; animation: fadeIn 0.15s ease both; display:flex; align-items:center; justify-content:center; }
.confirm-dialog { width:400px; max-width:90vw; background:var(--bg3); border:1px solid var(--line2); border-radius:14px; padding:28px; box-shadow:0 24px 64px rgba(0,0,0,0.5); animation: fadeUp 0.25s cubic-bezier(0.16,1,0.3,1) both; }
/* Tag input */
.tag-chip { display:inline-flex; align-items:center; gap:4px; padding:3px 8px; border-radius:4px; background:var(--bg4); border:1px solid var(--line2); font-size:11px; color:var(--text); font-family:var(--font); }
.tag-chip button { background:none; border:none; color:var(--text-dim); cursor:pointer; font-size:12px; padding:0; line-height:1; }
.tag-chip button:hover { color:var(--admin-c); }
/* Ann action buttons */
.ann-action { background:transparent; border:1px solid var(--line2); border-radius:6px; padding:4px 8px; cursor:pointer; font-size:11px; color:var(--text-dim); transition:all 0.15s; }
.ann-action:hover { background:var(--bg4); color:var(--text); }
</style>
<meta name="x-authentik-groups" content="" /><meta name="x-authentik-username" content="" /><meta name="x-authentik-name" content="" /><meta name="x-authentik-email" content="" /></head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect, useRef, useCallback, useMemo } = React;
// ── AUTHENTIK USER FROM META TAGS ────────────────────────────────────────────
function getAuthentikUser() {
const getMeta = (name) => {
const el = document.querySelector(`meta[name="${name}"]`);
if (!el) return '';
const val = el.getAttribute('content') || '';
// nginx sub_filter injects $http_x_authentik_* which is empty string if header absent
if (val.startsWith('$http_') || val === '') return '';
return val;
};
const rawGroups = getMeta('x-authentik-groups');
const username = getMeta('x-authentik-username');
const fullName = getMeta('x-authentik-name');
const email = getMeta('x-authentik-email');
// Parse groups: Authentik sends pipe-separated or comma-separated list
const groups = rawGroups
? rawGroups.split(/[|,]/).map(g => g.trim().toLowerCase()).filte
BTLS Certificate Expiry & Recommendations75 days until leaf cert expires — 2 issues to addressREVIEW
Certificate validity
Recommended actions
- Submit your domain to hstspreload.org to be added to the Chrome preload list
- Enable OCSP stapling on your TLS server to remove a CA roundtrip and protect user privacy
BOperational Status PageNo status page link detectedREVIEW
A+DNS Records2 A records, 41 ms lookupPASS
| A | 172.67.183.52, 104.21.56.90 |
| AAAA | 2606:4700:3030::6815:385a, 2606:4700:3032::ac43:b734 |
| CNAME | — |
| NS | harlan.ns.cloudflare.com, anastasia.ns.cloudflare.com |
| MX | 10 inbound-smtp.eu-west-1.amazonaws.com |
| TXT | — |
| CAA | Lookup not available with standard resolver |
SPF helps prevent email spoofing. Add a TXT record starting with 'v=spf1'.
Without SPF, receiving servers can't validate sending IPs — your domain is easier to spoof in phishing.
Learn more ▾ ▴
SPF complements DMARC. Both should be published. SPF records list authorized sending IPs (e.g., `v=spf1 include:_spf.google.com ~all` for Google Workspace). After publishing, verify in Google Postmaster Tools or mxtoolbox.
Source: RFC 7208 (SPF)
A+Subdomain TakeoverNo subdomain takeover risk detectedPASS
A+DNSSECSigned and validatingPASS
A+Multi-Resolver DNS SpeedMean 22ms across 3 resolvers (spread 13ms)PASS
A+IPv6 ReadinessIPv6 reachable (3 ms)PASS
A+URL Variantswww/non-www, trailing slash, HTTP→HTTPSPASS
www / non-www
HTTP → HTTPS
Consistent
A+Domain Intelligencemindmx.org — via Cloudflare, Inc., 2 months oldPASS
284 days
March 7, 2027
75 days
Issued by Let's Encrypt
2 months
Registered March 7, 2026
Enabled
Protects against DNS spoofing
Unknown
2606:4700:3030::6815:385a
Cloudflare, Inc.
Expiry timeline
Recommended actions
- Newly registered domain — build backlinks and content to establish SEO trust
- Enable registrar lock (clientTransferProhibited) to block unauthorized domain transfers
Newly registered domains may face SEO trust challenges. Search engines generally give more authority to older domains. This is informational — not a problem to fix.
Informational: domain age. Newer domains may have lower trust signals in spam/security filters.
The domain can be transferred without an unlock step. Enable registrar lock (clientTransferProhibited) in your registrar's control panel to protect against unauthorized or accidental transfers.
Without registrar lock, an attacker who phishes your registrar credentials can transfer the domain in minutes — total brand hijack.
Learn more ▾ ▴
Registrar lock (clientTransferProhibited, clientUpdateProhibited, clientDeleteProhibited) requires extra verification before any transfer/update/delete. Every major registrar offers it free. Combined with 2FA on your registrar account, it's the strongest defense against domain hijacking.
Source: ICANN / domain-security best practice