feat: expand help center and harden website SEO

This commit is contained in:
KoalaDev
2026-07-28 07:29:41 +02:00
parent fc005c0c88
commit 2c5e2a7cc3
13 changed files with 500 additions and 130 deletions
+7
View File
@@ -137,6 +137,12 @@ jobs:
npm ci
npm run build:extension
- name: Generate extension checksums
run: |
cd dist
sha256sum koalasync-chrome.zip koalasync-firefox.zip > SHA256SUMS
cat SHA256SUMS
- name: Generate artifact attestation for extensions
uses: actions/attest@v4
with:
@@ -158,6 +164,7 @@ jobs:
files: |
dist/koalasync-chrome.zip
dist/koalasync-firefox.zip
dist/SHA256SUMS
name: Release ${{ github.ref_name }}
generate_release_notes: true
draft: false
+9 -2
View File
@@ -50,7 +50,7 @@ The easiest and safest way to install KoalaSync is directly through the official
<a href="https://microsoftedge.microsoft.com/addons/detail/koalasync/gefnlpeoagcjfbmmfjjildkmofekbibg"><img src="https://img.shields.io/badge/Edge-Download-0078D7?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48IS0tISBGb250IEF3ZXNvbWUgRnJlZSA3LjMuMSBieSBAZm9udGF3ZXNvbWUgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbSBMaWNlbnNlIC0gaHR0cHM6Ly9mb250YXdlc29tZS5jb20vbGljZW5zZS9mcmVlIChJY29uczogQ0MgQlkgNC4wLCBGb250czogU0lMIE9GTCAxLjEsIENvZGU6IE1JVCBMaWNlbnNlKSBDb3B5cmlnaHQgMjAyNiBGb250aWNvbnMsIEluYy4gLS0%2BPHBhdGggZmlsbD0iI2ZmZiIgZD0iTTEyMC4xIDM3LjRjNDEtMjUuMiA4Ny42LTM4LjIgMTM0LjktMzcuNCAxNjggMCAyNTcgMTIzLjggMjU3IDIxOS41LS4xIDMyLjctMTMgNjMuOS0zNS45IDg3LjItMjIuOSAyMy4yLTU0IDM2LjUtODYuNyAzNy03NS4yIDAtOTEuNS0yMy4xLTkxLjUtMzIgMC0zLjggMS4yLTYuMiA0LjgtOS40bDEtMS4yIC40LTEuNmMxMC41LTExLjUgMTUuOS0yNi4yIDE1LjktNDEuNiAwLTc4LjctODIuMi0xNDIuNy0xODQtMTQyLjctMzcuNS0uMy03NC41IDguOS0xMDcuNSAyNi45IDI3LTU3LjUgODIuNy05Ny42IDkxLjMtMTAzLjggLjgtLjYgLjMtLjggLjMtLjh6bTE1LjYgMzE4LjFjLTEuNCAzMCA0LjYgNjAgMTYuNCA4Ny4yIDEzLjYgMjYuNCAzMi43IDUxIDU2LjUgNjkuMy01OS41LTExLjUtMTExLjUtNDMuOS0xNDkuNC04OS4zLTM4LjEtNDYuNC01OS4yLTEwNC4zLTU5LjItMTY0LjggMC01MS4yIDYyLjQtOTQuNCAxMzYtOTQuNCAzNi42LS42IDcyLjQgMTAuOSAxMDEuOCAzMi43bC0zLjYgMS4yYy01MS41IDE3LjYtOTguNSA5MC43LTk4LjUgMTU4LjF6TTQ2OS44IDQwMGwtLjcgLjFjLTExLjggMTguOC0yNS45IDM1LjEtNDIuMiA0OS41LTMwLjggMjgtNjguMSA0NS41LTEwOC44IDQ5LjktMTguNiAuMy0zNi44LTMuMi01My44LTExLjQtMjUuNi0xMC4zLTQ3LjEtMzAtNjEuNi01My0xNC40LTIzLjktMjEuMS01MS43LTE5LTc5LjYtLjYtMjAuMSA1LjQtNDAuMyAxNS01OC4yIDEzLjkgMzMuMSAzNy41IDYxLjMgNjcuNiA4MC44czY1LjUgMjkuNSAxMDEuNCAyOC42YzMxIC4zIDYyLjEtNi43IDkwLjItMjAuNWwxLjktLjljMy45LTIuMyA3LjctMy45IDExLjYgMCA0LjUgNC45IDEuOCA5LjItMS4yIDE0LS4yIC4yLS4zIC41LS40IC43eiIvPjwvc3ZnPg%3D%3D&style=for-the-badge" alt="Microsoft Edge Add-on"></a>
</p>
*(For manual offline installation: Download the latest `.zip` from the [Releases](https://github.com/Shik3i/KoalaSync/releases) page and load it as an "Unpacked Extension" in Developer Mode).*
*(For manual offline installation: Download the latest `.zip` from the [Releases](https://github.com/Shik3i/KoalaSync/releases) page, extract it, and load the extracted browser package using your browser's developer or manual extension installation process.)*
**How to use:**
1. **Create a Room:** Click the Koala icon in your browser and hit `+ Create New Room`.
@@ -112,7 +112,14 @@ To verify your relay is reachable from outside, visit `https://your-domain.com`
#### Supply Chain Security (v2.2.2+)
All official release artifacts (Docker images and extension binaries) are published with signed [artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations) to prove they were built from this repository's source code.
Extension ZIPs attached to GitHub Releases and Docker images published to GitHub Container Registry receive signed [artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations). These attestations connect an artifact's exact digest to this repository, its release tag and commit, and the public GitHub Actions workflow that built it.
Each new GitHub Release also includes `SHA256SUMS` for a quick checksum comparison:
```bash
sha256sum --check SHA256SUMS
```
Checksums detect a changed or incomplete download. Signed provenance additionally verifies where the artifact came from and which workflow built it. Neither check guarantees that the software contains no bugs or vulnerabilities. These attestations cover the GitHub release ZIPs and GHCR images; they do not by themselves prove that browser-store packages are byte-for-byte identical.
**Verify a Docker image:**
```bash
+1 -1
View File
@@ -24,7 +24,7 @@ When you push a Git tag matching `v*` (e.g., `v2.5.1`), the GitHub Actions relea
- `README.md` (updates badge and announcement banner)
- `website/sitemap.xml` (updates `lastmod` dates)
3. **Commits and pushes** these version updates back to the `main` branch automatically with the commit message `chore(release): update versions to vX.X.X [skip ci]`.
4. **Builds the extension** for both Chrome and Firefox and publishes the zipped archives.
4. **Builds the extension** for both Chrome and Firefox and publishes the zipped archives with a `SHA256SUMS` checksum file and signed provenance attestations.
5. **Builds the website** and uploads website artifacts.
6. **Builds and publishes** the Docker image for the relay server to the GitHub Container Registry (`ghcr.io`).
+8 -1
View File
@@ -15,6 +15,10 @@
# root * /var/www/koalasync/website/www
# encode zstd gzip
#
# # Keep one canonical URL for indexable support pages.
# redir /help.html /help 308
# redir /site-access-help.html /site-access-help 308
#
# # Clean URLs support (resolves /join to join.html, etc.)
# try_files {path} {path}.html {path}/
# file_server
@@ -61,6 +65,10 @@ sync.koalastuff.net {
encode zstd gzip
root * /var/www/koalasync/website/www
# Keep one canonical URL for indexable support pages.
redir /help.html /help 308
redir /site-access-help.html /site-access-help 308
# Clean URLs: Resolves paths without .html in the URL
try_files {path} {path}.html {path}/
file_server
@@ -96,4 +104,3 @@ syncserver.koalastuff.net {
encode zstd gzip
reverse_proxy KoalaSync:3000
}
+11 -3
View File
@@ -102,6 +102,7 @@ if (!llmsText.includes(`Current website release: ${websiteVersion}`)) {
throw new Error(`llms.txt release must match website/version.json (${websiteVersion})`);
}
const requiredSupportSocialMetadata = [
'<link rel="canonical" href="https://sync.koalastuff.net/site-access-help">',
'name="twitter:card" content="summary_large_image"',
'name="twitter:title"',
'name="twitter:description"',
@@ -132,12 +133,12 @@ for (const metadata of requiredHelpMetadata) {
}
}
if (!llmsText.includes('[Help Center](https://sync.koalastuff.net/help)')
|| !llmsText.includes('[Website access guide](https://sync.koalastuff.net/site-access-help.html)')) {
|| !llmsText.includes('[Website access guide](https://sync.koalastuff.net/site-access-help)')) {
throw new Error('llms.txt must expose the Help Center and website-access guide');
}
if (!websiteBuild.includes("['log', '-1', '--format=%cs', '--', ...sourceFiles]")
|| !websiteBuild.includes("lastmod(['website/help.html', 'website/styles/support.css'])")
|| !websiteBuild.includes("lastmod(['website/site-access-help.html'])")
|| !websiteBuild.includes("lastmod(['website/help.html', 'website/styles/support.css', 'website/app.js'])")
|| !websiteBuild.includes("lastmod(['website/site-access-help.html', 'website/app.js'])")
|| !websiteBuild.includes("['rev-parse', '--is-shallow-repository']")
|| !websiteBuild.includes("['diff', '--name-only', '--']")
|| !websiteBuild.includes("['diff', '--cached', '--name-only', '--']")
@@ -145,6 +146,9 @@ if (!websiteBuild.includes("['log', '-1', '--format=%cs', '--', ...sourceFiles]"
|| !websiteBuild.includes('sourceFiles.some(file => dirtySourceFiles.has(file))')) {
throw new Error('Sitemap lastmod values must come from the mapped source files in Git');
}
if (websiteBuild.includes('<changefreq>') || websiteBuild.includes('<priority>')) {
throw new Error('Sitemap must not emit ignored changefreq or priority hints');
}
const documentedRelayUrls = [...llmsText.matchAll(/`(wss:\/\/[^`\s]+)`/g)].map(([, value]) => new URL(value));
const hasCanonicalPublicRelay = documentedRelayUrls.some((url) => (
url.protocol === 'wss:' &&
@@ -179,6 +183,10 @@ for (const value of requiredSelfHostingValues) {
if ((selfHostingExamples.match(/localhost:3000/g) || []).length !== 2 || selfHostingExamples.includes('KoalaSync:3000')) {
throw new Error('Both Caddy examples must match the compose loopback port binding');
}
if ((selfHostingExamples.match(/\/help\.html \/help 308/g) || []).length !== 2
|| (selfHostingExamples.match(/\/site-access-help\.html \/site-access-help 308/g) || []).length !== 2) {
throw new Error('Both Caddy examples must redirect legacy support-page URLs to their clean canonicals');
}
const landingStylesheet = landingStylesheets[0][0];
if (!/href="\{\{ASSET_PATH\}\}landing\.min\.css"/.test(landingStylesheet)) {
+2
View File
@@ -73,6 +73,8 @@ Minimal static-site block:
```caddy
sync.koalastuff.net {
root * /var/www/koalasync/website/www
redir /help.html /help 308
redir /site-access-help.html /site-access-help 308
try_files {path} {path}.html {path}/
file_server
encode zstd gzip
+48 -13
View File
@@ -235,20 +235,55 @@ document.addEventListener('DOMContentLoaded', () => {
// Auto-update URL hash as user scrolls through sections
// (preserves position across language switches)
if ('IntersectionObserver' in window) {
const sectionObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
if (entry.target.id === 'top') {
history.replaceState(null, null, window.location.pathname + window.location.search);
} else {
history.replaceState(null, null, '#' + entry.target.id);
}
if (forestGreet) forestGreet();
}
const trackedSections = [...document.querySelectorAll('section[id], header[id]')];
if (trackedSections.length > 0) {
let hashUpdateFrame = null;
let hashNavigationTimer = null;
let hashNavigationInProgress = false;
const updateSectionHash = () => {
hashUpdateFrame = null;
const readingLine = 112;
const activeSection = trackedSections.reduce((closest, section) => {
const distance = Math.abs(section.getBoundingClientRect().top - readingLine);
const closestDistance = Math.abs(closest.getBoundingClientRect().top - readingLine);
return distance < closestDistance ? section : closest;
});
}, { threshold: 0.3 });
document.querySelectorAll('section[id], header[id]').forEach(el => sectionObserver.observe(el));
const nextHash = activeSection.id === 'top' ? '' : '#' + activeSection.id;
if (window.location.hash === nextHash) return;
if (nextHash === '') {
history.replaceState(null, null, window.location.pathname + window.location.search);
} else {
history.replaceState(null, null, nextHash);
}
if (forestGreet) forestGreet();
};
const scheduleSectionHashUpdate = () => {
if (hashUpdateFrame !== null) return;
hashUpdateFrame = requestAnimationFrame(updateSectionHash);
};
const finishHashNavigation = () => {
hashNavigationTimer = null;
hashNavigationInProgress = false;
scheduleSectionHashUpdate();
};
const beginHashNavigation = () => {
hashNavigationInProgress = true;
if (hashNavigationTimer !== null) clearTimeout(hashNavigationTimer);
hashNavigationTimer = setTimeout(finishHashNavigation, 250);
};
const handleSectionScroll = () => {
if (!hashNavigationInProgress) {
scheduleSectionHashUpdate();
return;
}
if (hashNavigationTimer !== null) clearTimeout(hashNavigationTimer);
hashNavigationTimer = setTimeout(finishHashNavigation, 180);
};
window.addEventListener('hashchange', beginHashNavigation);
window.addEventListener('scroll', handleSectionScroll, { passive: true });
if (window.location.hash) beginHashNavigation();
else scheduleSectionHashUpdate();
}
// Navbar scroll effect (class-based so it follows the active theme)
+18 -17
View File
@@ -109,12 +109,22 @@ function stageFlagFontSubset(websiteDir, wwwDir) {
function copyDirSync(src, dest) {
fs.mkdirSync(dest, { recursive: true });
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
if (entry.name === '.DS_Store') continue;
const s = path.join(src, entry.name);
const d = path.join(dest, entry.name);
entry.isDirectory() ? copyDirSync(s, d) : fs.copyFileSync(s, d);
}
}
function removeBuildMetadata(dir) {
if (!fs.existsSync(dir)) return;
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const entryPath = path.join(dir, entry.name);
if (entry.name === '.DS_Store') fs.rmSync(entryPath, { force: true });
else if (entry.isDirectory()) removeBuildMetadata(entryPath);
}
}
function sha8(buf) { return crypto.createHash('sha256').update(buf).digest('hex').slice(0, 8); }
function sha384(buf) { return 'sha384-' + crypto.createHash('sha384').update(buf).digest('base64'); }
@@ -164,6 +174,7 @@ async function compile() {
const websiteDir = __dirname;
const wwwDir = path.join(websiteDir, 'www');
fs.mkdirSync(wwwDir, { recursive: true });
removeBuildMetadata(wwwDir);
// ── 0. Auto-generate website logo sizes and sync favicons ──
console.log('Generating responsive website logos...');
@@ -796,34 +807,24 @@ function generateSitemap(websiteDir, wwwDir) {
xml += `
<url>
<loc>https://sync.koalastuff.net/privacy</loc>${lastmod(['website/privacy.html'])}
<changefreq>monthly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://sync.koalastuff.net/help</loc>${lastmod(['website/help.html', 'website/styles/support.css'])}
<changefreq>weekly</changefreq>
<priority>0.8</priority>
<loc>https://sync.koalastuff.net/help</loc>${lastmod(['website/help.html', 'website/styles/support.css', 'website/app.js'])}
</url>
<url>
<loc>https://sync.koalastuff.net/site-access-help.html</loc>${lastmod(['website/site-access-help.html'])}
<changefreq>weekly</changefreq>
<priority>0.8</priority>
<loc>https://sync.koalastuff.net/site-access-help</loc>${lastmod(['website/site-access-help.html', 'website/app.js'])}
</url>
<url>
<loc>https://sync.koalastuff.net/de/datenschutz</loc>${lastmod(['website/datenschutz-de.html'])}
<changefreq>monthly</changefreq>
<priority>0.3</priority>
</url>`;
function addPage(relativePath, changefreq, priority, templateSource) {
function addPage(relativePath, templateSource) {
for (const lang of languages) {
const loc = `https://sync.koalastuff.net/${lang.prefix}${relativePath}`;
const sourceFiles = [templateSource, `website/locales/${lang.code}.json`];
xml += `
<url>
<loc>${loc}</loc>${lastmod(sourceFiles)}
<changefreq>${changefreq}</changefreq>
<priority>${priority}</priority>`;
<loc>${loc}</loc>${lastmod(sourceFiles)}`;
for (const alt of languages) {
const altHref = `https://sync.koalastuff.net/${alt.prefix}${relativePath}`;
xml += `
@@ -836,8 +837,8 @@ function generateSitemap(websiteDir, wwwDir) {
}
}
addPage('', 'weekly', '1.0', 'website/template.html');
addPage('alternatives', 'weekly', '0.7', 'website/alternatives/index.html');
addPage('', 'website/template.html');
addPage('alternatives', 'website/alternatives/index.html');
const subpages = [
['alternatives/teleparty', 'website/alternatives/teleparty.html'],
@@ -848,7 +849,7 @@ function generateSitemap(websiteDir, wwwDir) {
['alternatives/twoseven', 'website/alternatives/twoseven.html']
];
for (const [sub, templateSource] of subpages) {
addPage(sub, 'weekly', '0.7', templateSource);
addPage(sub, templateSource);
}
xml += `\n</urlset>\n`;
+218 -46
View File
@@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KoalaSync Help | Setup, Video Detection & Troubleshooting</title>
<meta name="description" content="Get KoalaSync working: understand browser permissions, restore website access, find missing video tabs, diagnose video detection, fix sync issues, and report reproducible bugs.">
<title>KoalaSync Help | Setup, Chat, Privacy & Troubleshooting</title>
<meta name="description" content="Get KoalaSync working, fix invite and chat problems, understand supported devices and data handling, and verify official open-source releases.">
<meta name="robots" content="index, follow">
<link rel="preload" href="style.min.css" as="style">
<link rel="stylesheet" href="style.min.css">
@@ -16,7 +16,7 @@
<meta property="og:type" content="website">
<meta property="og:url" content="https://sync.koalastuff.net/help">
<meta property="og:title" content="KoalaSync Help">
<meta property="og:description" content="Setup help, browser permissions, video detection, synchronization checks, and reproducible bug reports.">
<meta property="og:description" content="Setup help, invite troubleshooting, encrypted chat, supported devices, privacy, open-source releases, and reproducible bug reports.">
<meta property="og:image" content="https://sync.koalastuff.net/assets/og-image.png">
<meta property="og:image:width" content="1280">
<meta property="og:image:height" content="640">
@@ -25,7 +25,7 @@
<meta property="og:site_name" content="KoalaSync">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="KoalaSync Help">
<meta name="twitter:description" content="Setup help, browser permissions, video detection, synchronization checks, and reproducible bug reports.">
<meta name="twitter:description" content="Setup help, invite troubleshooting, encrypted chat, supported devices, privacy, open-source releases, and reproducible bug reports.">
<meta name="twitter:image" content="https://sync.koalastuff.net/assets/og-image.png">
<meta name="twitter:image:alt" content="KoalaSync browser extension">
<meta name="theme-color" content="#10190e">
@@ -51,8 +51,8 @@
"@type": ["CollectionPage", "FAQPage"],
"@id": "https://sync.koalastuff.net/help#webpage",
"name": "KoalaSync Help",
"headline": "KoalaSync Help: Setup, Video Detection and Troubleshooting",
"description": "Help for granting browser access, finding missing video tabs, diagnosing video detection, fixing playback synchronization, and reporting reproducible bugs.",
"headline": "KoalaSync Help: Setup, Chat, Privacy and Troubleshooting",
"description": "Help for joining rooms, granting browser access, fixing encrypted room chat and playback synchronization, understanding data handling, and verifying official releases.",
"url": "https://sync.koalastuff.net/help",
"datePublished": "2026-07-28",
"dateModified": "2026-07-28",
@@ -68,6 +68,14 @@
"text": "KoalaSync works with video players across many websites. It uses access on the video tab you actively select to find and control the video element, synchronize playback, and display optional room chat. Open tab titles populate the tab selector; KoalaSync does not create a general browsing or watch history."
}
},
{
"@type": "Question",
"name": "Why does a KoalaSync invite link not join the room?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Open the complete invite link in the same desktop browser profile where KoalaSync is installed. If the invite page was already open when the extension was installed or enabled, reload it. Confirm that the browser allows KoalaSync to run on sync.koalastuff.net, then ask the sender for a newly copied invite if the link is incomplete."
}
},
{
"@type": "Question",
"name": "Why does a video tab not appear in KoalaSync?",
@@ -84,6 +92,14 @@
"text": "Select the tab containing the visible player and start playback once. Check Video Debug Info in the Status tab, reload after permission changes, and temporarily disable extensions that modify the player. Some protected or non-HTML5 players may need site-specific support."
}
},
{
"@type": "Question",
"name": "Why does KoalaSync room chat not work for everyone?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Room chat requires KoalaSync 3.0.0 or newer. The room creator receives a chat encryption secret when creating a new room, and every friend must join through that room's current invite link to receive the same secret. Manual room entry and old invite links can still join playback synchronization, but do not provide chat access."
}
},
{
"@type": "Question",
"name": "Why are connected KoalaSync participants not synchronized?",
@@ -91,6 +107,38 @@
"@type": "Answer",
"text": "Confirm that everyone uses the same KoalaSync version and selected the correct local video tab. Reload after website-access changes, test play, pause, and seeking separately, and collect a debug report from each affected participant."
}
},
{
"@type": "Question",
"name": "Does KoalaSync stream the video to other participants?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. KoalaSync does not stream, upload, proxy, share, or bypass access to video content. Everyone watches locally in their own browser and needs their own access to the website or streaming service. KoalaSync only synchronizes playback actions such as play, pause, and seeking."
}
},
{
"@type": "Question",
"name": "Which devices and browsers support KoalaSync?",
"acceptedAnswer": {
"@type": "Answer",
"text": "KoalaSync is a desktop browser extension for Chrome, Firefox, Edge, and compatible Chromium-based browsers on Windows, macOS, Linux, and ChromeOS. It does not currently provide a mobile app or Safari extension. Website compatibility also depends on the site's video player."
}
},
{
"@type": "Question",
"name": "What data does KoalaSync send from the browser?",
"acceptedAnswer": {
"@type": "Answer",
"text": "While you are in a room, KoalaSync sends the room, peer, and playback data needed for live synchronization. Display names and, depending on privacy settings, tab or media titles may be shared with room participants. Chat text is encrypted in the extension before transmission. KoalaSync does not create a persistent chat, browsing, synchronization, or watch history."
}
},
{
"@type": "Question",
"name": "How can official KoalaSync releases be verified?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The extension, relay server, build scripts, release workflow, and Dockerfile are public under the MIT License. Extension ZIPs on GitHub Releases and Docker images on GitHub Container Registry receive signed provenance attestations that bind their exact digest to this repository, a release tag and commit, and the public GitHub Actions workflow."
}
}
]
},
@@ -147,50 +195,76 @@
<main id="main-content" class="support-content">
<header class="support-hero">
<span class="support-status">Help center</span>
<h1>How can we help?</h1>
<p class="support-lead">Start with the symptom you see. These checks cover browser access, missing tabs, video detection, playback synchronization, and the information needed for a useful bug report.</p>
<h1>KoalaSync Help & Troubleshooting</h1>
<p class="support-lead">Start with the problem or question you have. These guides cover invites, browser access, video detection, encrypted chat, playback synchronization, supported devices, privacy, and release verification.</p>
</header>
<section aria-labelledby="start-title">
<h2 id="start-title" class="support-section-title">Choose your problem</h2>
<div class="support-grid">
<a class="support-card support-card-link" href="site-access-help.html">
<span class="support-card-icon" aria-hidden="true">🔒</span>
<span class="support-eyebrow">Browser access</span>
<h3>KoalaSync cannot access the video site</h3>
<p>Restore “read and change site data” access in Chrome, Edge, Brave, Opera, or Vivaldi.</p>
<span class="support-card-cta">Open access guide →</span>
</a>
<a class="support-card support-card-link" href="#missing-tab">
<span class="support-card-icon" aria-hidden="true">🗂️</span>
<span class="support-eyebrow">Tab list</span>
<h3>The video tab is missing</h3>
<p>Test the clutter filter, reload the page, and identify domains that KoalaSync hides by mistake.</p>
<span class="support-card-cta">Check missing tabs →</span>
</a>
<a class="support-card support-card-link" href="#video-detection">
<span class="support-card-icon" aria-hidden="true">🎬</span>
<span class="support-eyebrow">Video detection</span>
<h3>The tab appears, but no video is found</h3>
<p>Check the selected tab, player state, Shadow DOM diagnostics, and conflicting extensions.</p>
<span class="support-card-cta">Diagnose the player →</span>
</a>
<a class="support-card support-card-link" href="#sync-problems">
<span class="support-card-icon" aria-hidden="true">↔️</span>
<span class="support-eyebrow">Synchronization</span>
<h3>Play, pause, or seeking does not sync</h3>
<p>Compare versions, selected tabs, room state, and debug reports from every participant.</p>
<span class="support-card-cta">Check synchronization →</span>
</a>
<section class="support-topic-index" aria-labelledby="start-title">
<h2 id="start-title" class="support-section-title">Choose a help topic</h2>
<div class="support-topic-grid">
<article class="support-card support-topic-group">
<header class="support-topic-header">
<h3>Get connected</h3>
<p>Join a room and give KoalaSync the access it needs.</p>
</header>
<div class="support-topic-links" role="navigation" aria-label="Get connected help">
<a href="#invite-problems">The invite opens, but nothing happens</a>
<a href="site-access-help">KoalaSync cannot access the video site</a>
<a href="#missing-tab">The video tab does not appear</a>
</div>
</article>
<article class="support-card support-topic-group">
<header class="support-topic-header">
<h3>Playback & chat</h3>
<p>Fix the selected player, room chat, or synchronization.</p>
</header>
<div class="support-topic-links" role="navigation" aria-label="Playback and chat help">
<a href="#video-detection">The tab appears, but KoalaSync finds no usable video</a>
<a href="#room-chat">Chat does not work, or one person cannot see it</a>
<a href="#sync-problems">Everyone is connected, but playback does not sync</a>
</div>
</article>
<article class="support-card support-topic-group">
<header class="support-topic-header">
<h3>Using KoalaSync</h3>
<p>Understand what the extension does and supports.</p>
</header>
<div class="support-topic-links" role="navigation" aria-label="Using KoalaSync help">
<a href="#video-access">Does KoalaSync send the video to my friends?</a>
<a href="#supported-devices">Which devices and browsers are supported?</a>
</div>
</article>
<article class="support-card support-topic-group">
<header class="support-topic-header">
<h3>Privacy & trust</h3>
<p>See what is shared and how official builds are verified.</p>
</header>
<div class="support-topic-links" role="navigation" aria-label="Privacy and trust help">
<a href="#permissions">Why does the browser show such a broad warning?</a>
<a href="#data-handling">What data leaves my browser?</a>
<a href="#trust">Why should I trust KoalaSync?</a>
</div>
</article>
</div>
</section>
<section id="permissions" class="support-card support-anchor-section" aria-labelledby="permissions-title">
<span class="support-eyebrow">Privacy & permissions</span>
<h2 id="permissions-title">Why does the browser show such a broad warning?</h2>
<p>Browsers may say that KoalaSync can “read and change all your data on all websites.” The wording is broad because KoalaSync is designed to work with video players across many different websites instead of a short fixed list.</p>
<p>KoalaSync injects its synchronization script into the video tab you actively select. On that tab it needs to find and control the video element, synchronize play, pause, and seeking, and display the optional room chat overlay. Open tab titles are read to populate the tab selector. KoalaSync does not create a general browsing or watch history.</p>
<p><a class="support-link" href="privacy#extension-permissions">Read the complete permission and data-handling explanation</a></p>
<section id="invite-problems" class="support-card support-anchor-section" aria-labelledby="invite-problems-title">
<span class="support-eyebrow">Invite links</span>
<h2 id="invite-problems-title">The invite opens, but nothing happens</h2>
<ol class="support-steps">
<li>Open the invite in the same desktop browser profile where KoalaSync is installed. Extensions installed in another browser or profile cannot receive the join request.</li>
<li>If you installed, enabled, or updated KoalaSync after opening the invite, reload the invite page once so the extension can connect to it.</li>
<li>Confirm that KoalaSync is allowed to run on <code>sync.koalastuff.net</code>. If the browser blocks access, follow the <a class="support-link" href="site-access-help">site-access guide</a>, then reload the invite.</li>
<li>Ask the sender to open KoalaSync and copy the invite link again. Use the complete link without removing anything after <code>#</code>; that part contains the room credentials and current chat secret.</li>
<li>Wait for the join page to report success. Joining the room does not select a video automatically, so open KoalaSync afterward and choose your local video tab under <strong>Sync</strong>.</li>
</ol>
<div class="support-callout" role="note">
<span class="support-callout-icon" aria-hidden="true">i</span>
<div>
<strong>The extension must be detected on the invite page.</strong>
<p>If the page still offers an install button even though KoalaSync is installed, the usual causes are a different browser profile, blocked website access, or a page that was opened before the extension became available.</p>
</div>
</div>
</section>
<section id="missing-tab" class="support-card support-anchor-section" aria-labelledby="missing-tab-title">
@@ -201,7 +275,7 @@
<li>Close and reopen the KoalaSync popup, then check <strong>Select Video</strong> again.</li>
<li>Open KoalaSync <strong>Settings</strong> and turn off <strong>Hide Clutter Tabs</strong>.</li>
<li>Return to the tab selector. If the tab now appears, the site was filtered as clutter by mistake.</li>
<li>If the tab is still missing, verify website access using the <a class="support-link" href="site-access-help.html">site-access guide</a>.</li>
<li>If the tab is still missing, verify website access using the <a class="support-link" href="site-access-help">site-access guide</a>.</li>
</ol>
<div class="support-callout" role="note">
<span class="support-callout-icon" aria-hidden="true">i</span>
@@ -225,6 +299,26 @@
</ul>
</section>
<section id="room-chat" class="support-card support-anchor-section" aria-labelledby="room-chat-title">
<span class="support-eyebrow">Room chat</span>
<h2 id="room-chat-title">Chat does not work, or one person cannot see it</h2>
<p>Room chat was introduced in KoalaSync 3.0.0. Every participant who wants to send or read chat messages needs version 3.0.0 or newer. Older versions can still join a room and synchronize playback, but they do not support room chat.</p>
<ol class="support-steps">
<li>Update KoalaSync in every browser. Open the extension and check the version in the top-right corner. Each participant needs version <strong>3.0.0 or newer</strong>.</li>
<li>After updating, the room creator should leave the old room and click <strong>Create New Room</strong>. This creates a new chat encryption secret and includes it in the new invite link.</li>
<li>Send that newly copied invite link to your friends. Each friend must leave the old room and join through the link so their extension receives the same chat encryption secret.</li>
<li>Do not join by typing only the room ID and password, and do not reuse an old invite link beginning with <code>#join:</code>. Both can connect playback synchronization, but neither contains the chat secret.</li>
<li>Each participant must select their local video tab, then open <strong>Settings → Room Chat</strong> and turn on <strong>Enable Room Chat</strong>. The chat appears on the selected video page, not inside the extension popup.</li>
</ol>
<div class="support-callout" role="note">
<span class="support-callout-icon" aria-hidden="true">i</span>
<div>
<strong>Chat is live only.</strong>
<p>There is no server-side message history. Someone who joins later sees only messages sent after they joined. Keep the invite link private: it contains the chat secret used to decrypt messages in that room.</p>
</div>
</div>
</section>
<section id="sync-problems" class="support-card support-anchor-section" aria-labelledby="sync-problems-title">
<span class="support-eyebrow">Synchronization</span>
<h2 id="sync-problems-title">Everyone is connected, but playback does not sync</h2>
@@ -237,6 +331,84 @@
</ol>
</section>
<section id="video-access" class="support-card support-anchor-section" aria-labelledby="video-access-title">
<span class="support-eyebrow">Video access</span>
<h2 id="video-access-title">Does KoalaSync send the video to my friends?</h2>
<p>No. KoalaSync does not stream, upload, proxy, download, or redistribute video content. It only sends the live room and playback events needed to keep actions such as play, pause, and seeking synchronized.</p>
<ul>
<li>Everyone watches the video locally in their own browser on the original website.</li>
<li>Each participant needs their own valid access to the website or streaming service.</li>
<li>KoalaSync does not bypass subscriptions, logins, DRM, regional restrictions, or platform rules.</li>
<li>Subtitles, audio tracks, fullscreen, and video quality remain local choices when the video player supports them.</li>
</ul>
</section>
<section id="supported-devices" class="support-card support-anchor-section" aria-labelledby="supported-devices-title">
<span class="support-eyebrow">Compatibility</span>
<h2 id="supported-devices-title">Which devices and browsers are supported?</h2>
<p>KoalaSync is currently a desktop browser extension. It supports Google Chrome, Mozilla Firefox, Microsoft Edge, Opera, Brave, Vivaldi, and other compatible Chromium-based desktop browsers on Windows, macOS, Linux, and ChromeOS.</p>
<ul>
<li>There is currently no KoalaSync mobile app for phones or tablets.</li>
<li>There is currently no Safari extension.</li>
<li>Website compatibility depends on the browser and the site's video player. Websites can change their players, DRM behavior, or browser restrictions at any time.</li>
<li>Protected, customized, or non-HTML5 players may need site-specific support even in a supported browser.</li>
</ul>
</section>
<section id="permissions" class="support-card support-anchor-section" aria-labelledby="permissions-title">
<span class="support-eyebrow">Privacy & permissions</span>
<h2 id="permissions-title">Why does the browser show such a broad warning?</h2>
<p>Browsers may say that KoalaSync can “read and change all your data on all websites.” The wording is broad because KoalaSync is designed to work with video players across many different websites instead of a short fixed list.</p>
<p>KoalaSync injects its synchronization script into the video tab you actively select. On that tab it needs to find and control the video element, synchronize play, pause, and seeking, and display the optional room chat overlay. Open tab titles are read to populate the tab selector. KoalaSync does not create a general browsing or watch history.</p>
<p><a class="support-link" href="privacy#extension-permissions">Read the complete permission and data-handling explanation</a></p>
</section>
<section id="data-handling" class="support-card support-anchor-section" aria-labelledby="data-handling-title">
<span class="support-eyebrow">Privacy</span>
<h2 id="data-handling-title">What data leaves my browser?</h2>
<p>KoalaSync only connects to a relay while you are actively in a room. During that session, the relay temporarily processes the data required to connect participants and synchronize playback.</p>
<ul>
<li><strong>Room and presence:</strong> room ID, peer ID, display name, connection state, and the information needed to join the room.</li>
<li><strong>Playback synchronization:</strong> actions and state such as play, pause, seeking, and the current playback position.</li>
<li><strong>Titles:</strong> tab or media titles may be shared with room participants depending on your title privacy settings. They can be limited or disabled.</li>
<li><strong>Room chat:</strong> message text is encrypted in the extension before transmission. The relay receives ciphertext and delivery metadata, but not the chat secret or readable message text.</li>
<li><strong>Stored locally:</strong> preferences, current room credentials, and the chat secret are stored in the browser. The chat secret is not sent to the relay. Decrypted chat entries remain only in the current page overlay and are not written to browser storage.</li>
<li><strong>Operational logs:</strong> the relay may log technical connection and security information such as IP addresses, protocol versions, socket or peer identifiers, and shortened room identifiers. Retention depends on the server infrastructure and configuration.</li>
</ul>
<p>KoalaSync does not create a persistent browsing, room, synchronization, chat, or watch history. Browser or operating-system notifications may retain notification text according to their own settings.</p>
<p><a class="support-link" href="privacy">Read the complete privacy policy</a></p>
</section>
<section id="trust" class="support-card support-anchor-section" aria-labelledby="trust-title">
<span class="support-eyebrow">Trust & verification</span>
<h2 id="trust-title">Why should I trust KoalaSync?</h2>
<p>Trust should not depend on promises alone. The KoalaSync browser extension, relay server, build scripts, release workflow, and Dockerfile used for official GitHub releases are public under the MIT License.</p>
<p>Official extension ZIPs on GitHub Releases and Docker images on GitHub Container Registry are built by the public GitHub Actions release workflow. Signed SLSA provenance attestations connect each artifact's exact digest to this repository, its release tag and commit, and the workflow that built it.</p>
<p>You can install KoalaSync from an official browser store, download the Chrome or Firefox ZIP from GitHub Releases, build the extension yourself, or run your own relay server. Manual ZIP installation uses your browser's developer or manual extension installation process.</p>
<div class="support-actions support-actions-trust">
<a class="btn btn-secondary" href="https://github.com/Shik3i/KoalaSync" target="_blank" rel="noopener">View source code</a>
<a class="btn btn-secondary" href="https://github.com/Shik3i/KoalaSync/releases/latest" target="_blank" rel="noopener">Download releases</a>
<a class="btn btn-secondary" href="https://github.com/Shik3i/KoalaSync/blob/main/.github/workflows/release.yml" target="_blank" rel="noopener">View release workflow</a>
<a class="btn btn-secondary" href="./#self-hosting">Self-host the relay</a>
</div>
<details class="support-details">
<summary>Advanced: verify signed build provenance</summary>
<p>Install the GitHub CLI, download the release ZIP, and run:</p>
<pre><code>gh attestation verify koalasync-chrome.zip \
--repo Shik3i/KoalaSync</code></pre>
<p>To verify the current Docker image:</p>
<pre><code>gh attestation verify oci://ghcr.io/shik3i/koalasync:latest \
--repo Shik3i/KoalaSync</code></pre>
</details>
<div class="support-callout support-callout-warning" role="note">
<span class="support-callout-icon" aria-hidden="true">!</span>
<div>
<strong>What an attestation proves, and what it does not.</strong>
<p>An attestation proves the origin and build workflow of the GitHub release ZIP or GHCR image with that exact digest. It does not guarantee that software has no bugs or vulnerabilities. It also does not by itself prove that a package downloaded from a browser store is byte-for-byte identical to a GitHub release ZIP.</p>
</div>
</div>
</section>
<section id="report-issue" class="support-card support-anchor-section" aria-labelledby="report-issue-title">
<span class="support-eyebrow">Still not working?</span>
<h2 id="report-issue-title">Create a useful GitHub issue</h2>
+1 -1
View File
@@ -79,7 +79,7 @@ Compatibility depends on each website's player implementation and can change whe
## Help and troubleshooting
- [Help Center](https://sync.koalastuff.net/help): Browser permissions, missing tabs, video detection, synchronization checks and safe bug reports
- [Website access guide](https://sync.koalastuff.net/site-access-help.html): Restore access when Chrome, Edge, Brave, Opera or Vivaldi blocks KoalaSync on a video site
- [Website access guide](https://sync.koalastuff.net/site-access-help): Restore access when Chrome, Edge, Brave, Opera or Vivaldi blocks KoalaSync on a video site
- If a video tab is missing, disable `Hide Clutter Tabs` temporarily. If the tab then appears, report the affected domain so the filter can be corrected.
- If a listed tab has no detected video, start playback once and inspect `Status` → `Video Debug Info`.
- GitHub issues are public. Remove private page URLs, titles, room or peer identifiers, participant names, custom server URLs, credentials and session parameters before publishing logs.
+6 -6
View File
@@ -9,11 +9,11 @@
<link rel="preload" href="style.min.css" as="style">
<link rel="stylesheet" href="style.min.css">
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32x32.png">
<link rel="canonical" href="https://sync.koalastuff.net/site-access-help.html">
<link rel="alternate" hreflang="en" href="https://sync.koalastuff.net/site-access-help.html">
<link rel="alternate" hreflang="x-default" href="https://sync.koalastuff.net/site-access-help.html">
<link rel="canonical" href="https://sync.koalastuff.net/site-access-help">
<link rel="alternate" hreflang="en" href="https://sync.koalastuff.net/site-access-help">
<link rel="alternate" hreflang="x-default" href="https://sync.koalastuff.net/site-access-help">
<meta property="og:type" content="website">
<meta property="og:url" content="https://sync.koalastuff.net/site-access-help.html">
<meta property="og:url" content="https://sync.koalastuff.net/site-access-help">
<meta property="og:title" content="Fix KoalaSync website access">
<meta property="og:description" content="Quick browser-specific steps for reconnecting KoalaSync to a video tab.">
<meta property="og:image" content="https://sync.koalastuff.net/assets/og-image.png">
@@ -35,10 +35,10 @@
"datePublished": "2026-07-15T10:24:59Z",
"dateModified": "2026-07-19T19:20:05Z",
"inLanguage": "en",
"url": "https://sync.koalastuff.net/site-access-help.html",
"url": "https://sync.koalastuff.net/site-access-help",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://sync.koalastuff.net/site-access-help.html"
"@id": "https://sync.koalastuff.net/site-access-help"
},
"author": {
"@type": "Organization",
+163 -40
View File
@@ -79,8 +79,7 @@
}
.support-content > .support-card + .support-card,
.support-grid + .support-card,
.support-card + .support-grid,
.support-card + .support-topic-grid,
.support-callout + .support-card {
margin-top: 1.25rem;
}
@@ -130,62 +129,109 @@
margin-top: 0.6rem;
}
.support-grid {
.support-topic-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.25rem;
margin-top: 1.25rem;
}
.support-topic-index {
margin-bottom: 2.75rem;
}
.support-section-title {
margin: 0 0 0.25rem;
margin: 0 0 0.4rem;
color: var(--text);
text-align: center;
font-size: clamp(1.45rem, 3vw, 1.9rem);
}
.support-card-link {
.support-topic-group {
position: relative;
overflow: hidden;
padding: 0;
border-top-color: color-mix(in oklch, var(--accent) 55%, var(--card-border));
}
.support-topic-group::before {
content: '';
position: absolute;
inset: 0 0 auto;
height: 2px;
background: linear-gradient(90deg, var(--accent), color-mix(in oklch, var(--accent) 12%, transparent) 72%, transparent);
}
.support-topic-header {
min-height: 7.4rem;
padding: 1.55rem 1.6rem 1.25rem;
}
.support-topic-header h3 {
margin: 0 0 0.45rem;
color: var(--text);
font-size: 1.2rem;
letter-spacing: -0.015em;
}
.support-topic-header p {
max-width: 34rem;
margin: 0;
color: var(--text-muted);
font-size: 0.9rem;
line-height: 1.55;
}
.support-topic-links {
display: block;
color: inherit;
border-top: 1px solid var(--card-border);
}
.support-topic-links a {
display: flex;
min-height: 3.85rem;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.9rem 1.6rem;
color: var(--text);
font-size: 0.94rem;
font-weight: 700;
line-height: 1.4;
text-decoration: none;
transition: transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
transition: background-color 160ms ease, color 160ms ease, padding-left 160ms ease;
}
.support-card-link:hover,
.support-card-link:focus-visible {
transform: translateY(-3px);
border-color: color-mix(in oklch, var(--accent) 55%, transparent);
box-shadow: 0 24px 65px rgba(0, 0, 0, 0.2);
.support-topic-links a + a {
border-top: 1px solid color-mix(in oklch, var(--card-border) 78%, transparent);
}
.support-card-link:focus-visible {
outline: 3px solid color-mix(in oklch, var(--accent) 45%, transparent);
outline-offset: 3px;
}
.support-card-link .support-eyebrow {
margin-bottom: 1rem;
}
.support-card-icon {
float: right;
display: grid;
place-items: center;
width: 2.8rem;
height: 2.8rem;
margin-left: 0.75rem;
border: 1px solid color-mix(in oklch, var(--accent) 25%, transparent);
border-radius: 14px;
background: color-mix(in oklch, var(--accent) 9%, var(--card));
font-size: 1.3rem;
}
.support-card-cta {
display: inline-block;
margin-top: 1rem;
.support-topic-links a::after {
content: '';
flex: 0 0 auto;
color: var(--accent);
font-weight: 800;
font-size: 1.45rem;
font-weight: 500;
line-height: 1;
transition: transform 160ms ease;
}
.support-topic-links a:hover {
padding-left: 1.75rem;
background: color-mix(in oklch, var(--accent) 9%, transparent);
color: color-mix(in oklch, var(--text) 88%, var(--accent));
}
.support-topic-links a:hover::after {
transform: translateX(3px);
}
.support-topic-links a:focus-visible {
position: relative;
z-index: 1;
outline: 3px solid color-mix(in oklch, var(--accent) 50%, transparent);
outline-offset: -3px;
background: color-mix(in oklch, var(--accent) 12%, transparent);
}
.support-anchor-section {
@@ -283,28 +329,105 @@
.support-actions .btn {
min-width: 180px;
justify-content: center;
text-align: center;
}
.support-actions-trust {
margin: 1.5rem 0;
}
.support-details {
margin-top: 1.25rem;
border: 1px solid var(--card-border);
border-radius: 16px;
background: color-mix(in oklch, var(--card) 82%, transparent);
}
.support-details summary {
padding: 1rem 1.15rem;
color: var(--text);
cursor: pointer;
font-weight: 800;
}
.support-details summary:focus-visible {
outline: 3px solid color-mix(in oklch, var(--accent) 45%, transparent);
outline-offset: 3px;
border-radius: 14px;
}
.support-details[open] {
padding-bottom: 1rem;
}
.support-details[open] summary {
margin-bottom: 0.25rem;
}
.support-details p,
.support-details pre {
margin: 0.75rem 1.15rem 0;
}
.support-details pre {
overflow-x: auto;
border: 1px solid color-mix(in oklch, var(--accent) 22%, var(--card-border));
border-radius: 12px;
background: color-mix(in oklch, var(--bg) 82%, black);
padding: 1rem;
color: var(--text);
font-size: 0.82rem;
line-height: 1.6;
}
.support-details code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
html.theme-light .support-card,
html.theme-light .support-callout {
html.theme-light .support-callout,
html.theme-light .support-details {
background-color: var(--card-surface);
box-shadow: 0 18px 45px rgba(44, 62, 37, 0.1);
}
html.theme-light .support-details pre {
background: color-mix(in oklch, var(--bg) 92%, white);
}
@media (max-width: 720px) {
.support-content {
width: min(100% - 1rem, 980px);
padding-top: 7.5rem;
}
.support-grid {
.support-topic-grid {
grid-template-columns: 1fr;
}
.support-topic-index {
margin-bottom: 2.25rem;
}
.support-card {
border-radius: 18px;
}
.support-topic-header {
min-height: 0;
padding: 1.35rem 1.3rem 1rem;
}
.support-topic-links a {
min-height: 3.65rem;
padding: 0.85rem 1.3rem;
}
.support-topic-links a:hover {
padding-left: 1.4rem;
}
.support-callout {
grid-template-columns: 1fr;
}
+8
View File
@@ -1418,6 +1418,10 @@
<span class="t-key">root</span> <span class="t-val">*</span> <span class="t-str">/var/www/koalasync/website/www</span>
<span class="t-key">encode</span> <span class="t-val">zstd gzip</span>
<span class="t-comment"># Redirect legacy support-page URLs to their canonical clean URLs</span>
<span class="t-key">redir</span> <span class="t-val">/help.html /help 308</span>
<span class="t-key">redir</span> <span class="t-val">/site-access-help.html /site-access-help 308</span>
<span class="t-comment"># Clean URLs support (no .html required)</span>
<span class="t-key">try_files</span> <span class="t-val">{path} {path}.html {path}/</span>
<span class="t-key">file_server</span>
@@ -1450,6 +1454,10 @@
<span class="t-key">encode</span> <span class="t-val">zstd gzip</span>
<span class="t-key">root</span> <span class="t-val">*</span> <span class="t-str">/var/www/koalasync/website/www</span>
<span class="t-comment"># Redirect legacy support-page URLs to their canonical clean URLs</span>
<span class="t-key">redir</span> <span class="t-val">/help.html /help 308</span>
<span class="t-key">redir</span> <span class="t-val">/site-access-help.html /site-access-help 308</span>
<span class="t-comment"># Clean URLs: Resolves paths without .html in the URL</span>
<span class="t-key">try_files</span> <span class="t-val">{path} {path}.html {path}/</span>
<span class="t-key">file_server</span>