Sakxu-Docs
16 min read · Updated Oct 1, 2026
Sakxu Docs — Setup & User Guide
Sakxu Docs is a self-hosted documentation website with a built-in admin panel. Visitors read and search your docs; you manage everything (pages, guides, features, FAQ, changelog, media, SEO, analytics, users) from /admin.
Contents
What you need
Quick start (run it on your computer)
Set up MongoDB
Environment variables
Deploy to the internet (Vercel)
First login
Using the admin panel
Login options (email, Discord, registration)
Discord login setup
Discord bot setup
Email (SMTP) setup and templates
Bot protection (Cloudflare Turnstile)
Domain and Cloudflare (optional)
SEO setup
Analytics and privacy
Backups and updates
Security checklist
Troubleshooting
Current limitations
Getting help
1. What you need
Needed Why Cost
Node.js 18.17 or newer (20 LTS recommended) Runs the project Free
MongoDB Atlas account Stores all content, users and uploaded files Free tier available
GitHub account Holds your code so Vercel can deploy it Free
Vercel account Hosts the website Free tier available
A domain name Your own address (optional at first) ~$10/year
Optional: Discord application Discord login and the Discord bot Free
Optional: An SMTP email service Verification, password-reset and invite emails Many have free tiers
Optional: Cloudflare account DNS, caching, Turnstile bot protection Free tier available
2. Quick start (run it on your computer)
Unzip the project and open a terminal inside the Sakxu Docs folder.
(The folder name has a space, so use quotes: cd "Sakxu Docs".)Install dependencies:
npm install
Copy the example settings file:
cp .env.example .env
(On Windows PowerShell: copy .env.example .env)
Open .env and fill in at least these four (details in sections 3 and 4):
MONGODB_URI=...
NEXTAUTH_SECRET=...
NEXT_PUBLIC_SITE_URL=http://localhost:3000
ADMIN_PASSWORD=choose-a-strong-password
Create the starter data and your Owner account:
npm run seed
Start the site:
npm run dev
Open http://localhost:3000 for the public site and http://localhost:3000/login to sign in.
3. Set up MongoDB
Go to mongodb.com/atlas, create an account and choose Build a database → Free (M0). Pick a region close to where you'll host the site.
Create a database user (username + password). Use letters and numbers only, or the password will need URL-encoding in the connection string.
Network Access → Add IP Address → Allow access from anywhere (0.0.0.0/0). Vercel doesn't use fixed IP addresses, so this is required for it to connect. Your database is still protected by the username and password.
Click Connect → Drivers and copy the connection string. Replace <password> with your password and add a database name before the ?:
mongodb+srv://myuser:mypassword@cluster0.abcde.mongodb.net/sakxudocs?retryWrites=true&w=majority
Paste it as MONGODB_URI.
Uploaded files live in MongoDB too (there is no separate file storage service to set up). Optionally keep them in a different database by setting MONGODB_CDN_URI to a second connection string (for example one ending /sakxudocs_files). If you leave it empty, files are stored in your main database.
The Atlas free tier has 512 MB of storage. Every image, PDF and video you upload counts toward it. If you plan to upload a lot, use a paid tier or a separate database for files.
4. Environment variables
Set these in .env locally and in the Vercel dashboard when deployed.
Variable Required What it is
MONGODB_URI Yes Main database connection string
MONGODB_CDN_URI No Separate database for uploaded files (defaults to the main one)
NEXTAUTH_SECRET Yes Secret used to sign login sessions. 16+ random characters. Keep private.
NEXT_PUBLIC_SITE_URL Yes Your public address, e.g. https://docs.example.com (no trailing slash)
ADMIN_EMAIL First run Email for the Owner account created by npm run seed
ADMIN_PASSWORD First run Password for the Owner account (see warning below)
DISCORD_CLIENT_ID For Discord Discord application ID
DISCORD_CLIENT_SECRET For Discord login Discord OAuth secret
DISCORD_PUBLIC_KEY For the bot Discord application public key
DISCORD_BOT_TOKEN For the bot Used only by the command-registration script
DISCORD_GUILD_ID No Your Discord server ID (makes bot commands appear instantly)
TURNSTILE_SITE_KEY For Turnstile Cloudflare Turnstile site key
TURNSTILE_SECRET_KEY For Turnstile Cloudflare Turnstile secret
SMTP_HOST For email Mail server address
SMTP_PORT For email Usually 587 (or 465 for SSL)
SMTP_USER For email Mail account username
SMTP_PASSWORD For email Mail account password
SMTP_FROM For email Sender, e.g. Sakxu Docs <no-reply@example.com>
ANALYTICS_RETENTION_DAYS No How long raw visit sessions are kept (default 90)
Create a NEXTAUTH_SECRET (works on any computer with Node):
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
Important about ADMIN_PASSWORD: every time you run npm run seed while ADMIN_EMAIL and ADMIN_PASSWORD are set, the Owner account's password is reset to that value. After your first successful seed, delete ADMIN_PASSWORD from .env and change your password from the Account page.
Variables starting with NEXT_PUBLIC_ are baked in when the site is built. If you change NEXT_PUBLIC_SITE_URL, redeploy.
Never share your .env file or post secrets publicly.
5. Deploy to the internet (Vercel)
Put the code on GitHub. Create a new private repository and push the project to it. The included .gitignore keeps .env out of the repository; check that it is not uploaded.
Go to vercel.com → Add New → Project and import the repository. Vercel detects Next.js automatically.
Open Environment Variables and add every variable from section 4 that you are using. Set NEXT_PUBLIC_SITE_URL to your final address (you can use the temporary https://your-project.vercel.app address first).
Click Deploy.
Create the starter data in your live database. On your own computer, put the live MONGODB_URI, ADMIN_EMAIL and ADMIN_PASSWORD in .env and run npm run seed once. (The build itself doesn't need the database; the seed does.)
Add your domain: Vercel → Project → Settings → Domains → add it and follow the DNS instructions. Then update NEXT_PUBLIC_SITE_URL to https://your-domain and redeploy.
Any host that runs Node.js also works: npm run build then npm start.
6. First login
Go to https://your-domain/login and sign in with ADMIN_EMAIL and ADMIN_PASSWORD.
(The public header has no "Log in" link by default, on purpose, so the site looks clean to visitors. You can turn the link on under Admin → Security.)You land on the admin dashboard (/admin/dashboard).
Click your name at the bottom of the sidebar → Account & password and set your own password.
Remove ADMIN_PASSWORD from your environment (see section 4).
7. Using the admin panel
The left sidebar groups everything. You only see the items your role allows.
Content
Documents (/admin/documents) and Guides (/admin/guides)
Click New document.
Fill in: Title, Slug (the end of the URL; leave empty to generate it), Section (Docs, Guide or API), Category, Description, Status, Order.
Write in the editor: headings, lists, quotes, links, images, code blocks (choose a language), dividers and four coloured boxes (info, warning, success, error).
Set Status = published to make it visible. Drafts are hidden from visitors.
Optional: Hide from sidebar, and SEO title / description at the bottom.
Where pages appear:
Section Docs → /docs/your-slug
Section Guide → /guides/your-slug
Section API → /api/your-slug
A page shows in the sidebar only if it is published, has a category, and the category's section matches the page's section. Pages are ordered by their Order number (lowest first).
Categories — the groups in the sidebar (e.g. "Getting Started"). Choose the section each belongs to and set an order.
Pages — free-form pages such as /about or /downloads. Tick Show in header navigation to add them to the top menu. Slugs the site already uses (docs, guides, api, features, faq, changelog, community, login, privacy, terms, and so on) are blocked.
Features — cards on the homepage and /features. Use any Lucide icon name (e.g. Zap, Shield, Layers).
FAQ — questions and answers with animated accordions. "Show on homepage" puts them on the home page.
Changelog — one entry per release. In Changes write one per line like added: New search (types: added, changed, fixed, removed, security).
Announcements — a banner across the top of the site. Choose type (info/success/warning/error), optional link, start and end dates, and whether visitors can dismiss it.
Media — upload images, PDFs, ZIPs, MP4 and WebM files (max 25 MB each). Each file gets a link (/cdn/…); use the copy buttons for URL, Markdown or HTML. Add alt text for accessibility and SEO.
Insights
Analytics — visitors, page views, sessions, documentation views, searches, top pages, referrers, devices, countries, a daily chart, per-page statistics, search terms (including searches that found nothing) and a live "who is online" view. Use the date buttons (Today, 7 days, 30 days, 90 days, 1 year, Custom).
SEO — global settings, per-page overview, an audit and redirects (section 14).
Site
Branding — site name, short description, logo URL, favicon URL, Discord invite, GitHub URL, footer text, extra header links and footer links (one per line: Label | /path or Label | https://link).
Appearance — accent colours (light and dark), border radius, content width and font.
Email templates — edit the emails the site sends (section 11).
Access & system
Users — create users, change roles, delete users (section below).
Roles — shows what each role can do.
Security — login options (section 8).
Discord bot — turn the bot on or off and see setup status (section 10).
Audit logs — a record of important admin actions (who did what and when).
Creating users and roles
Users → + Create user. Enter email, name, role and either:
an initial password (use Generate, then Copy it before saving; it can't be shown again), or
leave the password empty to email them an invite link to choose their own (needs email set up, section 11).
Role Can do
Owner Everything
Administrator Content, media, analytics, SEO, users, settings
Editor Create/edit/publish documents and features, upload media
Moderator Edit documents, view users
Viewer No admin access (this is what public sign-ups get)
Only the Owner can create or change an Owner. You can't change or delete your own account from the Users page, and the Owner account can't be deleted.
8. Login options (email, Discord, registration)
Admin → Security controls how people sign in:
Setting Default Effect
Email & password login On Login form, forgot password, change password
Discord login Off "Continue with Discord" button
Allow new registrations Off Shows "Create account" and /register. When off, the register page doesn't exist and unknown people can't create accounts
Show "Log in" link in header Off Adds a Log in link to the top menu
Cloudflare Turnstile Off Bot check on login, register and password forms
For a personal or owner-only site, leave registration off. You create any other users yourself.
You can enable email and Discord together. The panel refuses changes that would lock you out (for example, turning off email login before your own Discord account is linked).
9. Discord login setup
Go to discord.com/developers/applications → New Application.
Open OAuth2. Copy the Client ID and Client Secret into DISCORD_CLIENT_ID and DISCORD_CLIENT_SECRET.
Under Redirects, add exactly:
https://your-domain/api/auth/discord/callback
(For local testing also add http://localhost:3000/api/auth/discord/callback.)
Make sure NEXT_PUBLIC_SITE_URL is set, then redeploy.
In Admin → Security, turn on Discord login and save.
Link your own account: sign in with email, open Account, click Link Discord account. After that you can sign in with Discord.
Notes:
With registration off, only Discord accounts already linked to a user (or whose verified Discord email matches an existing verified account) can sign in.
The site stores your Discord ID, username, avatar and your verified Discord email.
10. Discord bot setup
The bot answers /docs commands using the same content as your website. It runs as a webhook, so no extra server is needed.
In the Discord Developer Portal, open your application:
General Information → copy Public Key into DISCORD_PUBLIC_KEY and the Application ID into DISCORD_CLIENT_ID.
Bot → create a bot and copy its token into DISCORD_BOT_TOKEN (used only on your computer in step 3).
Deploy the site with these variables, then in General Information set Interactions Endpoint URL to:
https://your-domain/api/discord/interactions
Discord checks it immediately, so the site must already be live.
On your computer (with .env filled in) register the commands:
npm run discord:register
Set DISCORD_GUILD_ID first if you want the commands to appear instantly in your server (otherwise global commands can take up to an hour).
Invite the bot: OAuth2 → URL Generator, tick scope applications.commands, open the generated link and add it to your server.
Commands:
/docs search <query>
/docs page <page>
/docs feature <feature>
/docs faq <query>
Turn the bot on or off any time in Admin → Discord bot. While off, the commands reply that the bot is turned off.
11. Email (SMTP) setup and templates
Emails are used for: verifying new registrations, password resets, user invites and password-changed notices.
Set up sending. Get SMTP details from an email provider (for example Brevo, Mailgun, Resend, SendGrid, Amazon SES, or your hosting provider's mail) and set:
SMTP_HOST=smtp.your-provider.com
SMTP_PORT=587
SMTP_USER=your-username
SMTP_PASSWORD=your-password
SMTP_FROM="Sakxu Docs <no-reply@your-domain.com>"
Use a sender address on your own domain, and add the provider's SPF/DKIM DNS records so mail isn't marked as spam. Redeploy after changing variables.
Edit the emails: Admin → Email templates. There are four: Verify email, Password reset, User invite and Password changed notice. Change the subject and message, using variables such as {{name}}, {{siteName}}, {{link}}, {{expires}} and {{role}}. Put {{link}} on its own line to show it as a button. Messages are plain text; a styled HTML version is created automatically using your accent colour.
Each template has a preview, Send test to me (sent only to your own address) and Restore default.
Forgot password: works for any account with an email on file, including the verified email that came from a linked Discord account. The page only exists while email login is turned on.
Without SMTP, no email is sent. (In local development the email text is printed in the terminal instead.) Registration and email-invite users can't be used until SMTP works; you can still create users with a password.
12. Bot protection (Cloudflare Turnstile)
In Cloudflare → Turnstile → Add widget. Add your domain.
Copy the Site key and Secret key into TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY, then redeploy.
Admin → Security → turn on Turnstile.
It then protects the login, register, forgot-password and reset-password forms.
13. Domain and Cloudflare (optional)
Domain only: add the domain in Vercel (section 5) and set the DNS records Vercel shows you.
With Cloudflare: add your domain to Cloudflare, point your registrar's nameservers to Cloudflare, and add the DNS record Vercel asks for. Set SSL/TLS to Full (strict). Using Cloudflare's proxy is optional.
If you use Cloudflare's proxy, uploaded files (/cdn/*) are cached at its edge automatically (they are served with one-year cache headers), and visitor country appears in analytics.
14. SEO setup
Set NEXT_PUBLIC_SITE_URL to your real https:// address (the audit flags a missing or localhost address).
Admin → SEO → Global: site title, description, default social-sharing image, author, organization and X/Twitter handle.
Google Search Console: add your site, choose the HTML-tag method, and paste only the content value of the tag into Google Search Console verification token. Then submit https://your-domain/sitemap.xml.
For each page, fill the SEO title and SEO description at the bottom of the editor (the SEO → Pages list shows which pages still use automatic ones).
Run SEO → Audit regularly. It checks titles, descriptions, headings, canonical links, social images, image alt text, URLs, indexing, structured data and internal links.
SEO → Redirects: when you rename or remove a page, add a redirect from the old path to the new one (301 permanent or 302 temporary).
The site automatically provides: a sitemap, robots.txt, canonical URLs, Open Graph/Twitter tags, and structured data (breadcrumbs, articles, FAQ). Good SEO can't be guaranteed, but this covers the technical basics.
15. Analytics and privacy
Analytics are built in: no third-party service and no tracking cookies.
IP addresses are not stored. A random per-tab ID and a daily-changing hash group page views into visits. Visitors whose browser sends "Do Not Track" are not counted.
Raw visit sessions are deleted after ANALYTICS_RETENTION_DAYS (default 90). Daily totals are kept. Set this variable before the first visit is recorded, because the deletion rule is created at that moment.
"Visitors" are unique per day. A total over several days counts a returning visitor once per day.
/privacy and /terms are template pages. Read them and adapt them to your business and local law. They are text in the project files (src/app/(site)/privacy/page.js and .../terms/page.js).
16. Backups and updates
Backups. Your content, users, settings and uploaded files are all in MongoDB.
Atlas paid tiers include automatic backups. The free tier does not.
Free option: install MongoDB Database Tools and run mongodump --uri "YOUR_MONGODB_URI" regularly (and again for MONGODB_CDN_URI if you use it). Store the output somewhere safe.
Updating. When you receive a new version: replace the project files, keep your .env, run npm install, test locally, then push to GitHub so Vercel redeploys.
17. Security checklist
☐︎ Strong, unique Owner password; ADMIN_PASSWORD removed from the environment after the first seed
☐︎ NEXTAUTH_SECRET is long and random, and never shared
☐︎ .env is not in GitHub (private repository)
☐︎ Registration is off unless you really want public accounts
☐︎ Turnstile enabled if the login page gets abuse
☐︎ SMTP/Discord/Turnstile secrets only live in environment variables
☐︎ Only trusted people have Administrator or Editor roles
☐︎ Regular database backups
☐︎ Review Audit logs now and then
Built-in protections include hashed passwords, signed login cookies, login rate limiting, server-side permission checks on every action, checked file uploads (real file contents are verified, and only images, PDF, ZIP, MP4 and WebM are accepted), and escaped email content.
18. Troubleshooting
Problem Fix
Can't log in Make sure you ran npm run seed against the same database the site uses, with ADMIN_EMAIL set. Check NEXTAUTH_SECRET is set and at least 16 characters.
"Database not connected" / empty site Check MONGODB_URI (password correct, database name added, Atlas Network Access allows your host).
Site is empty after deploy Run npm run seed against the live database (section 5, step 5).
I can't find a Log in link By design. Go to /login, or enable the link in Admin → Security.
/register shows "not found" Registration is off (the default). Turn it on in Admin → Security only if you want it.
Discord says "Invalid redirect URI" The redirect in the Developer Portal must exactly match https://your-domain/api/auth/discord/callback.
Discord login button missing Set the Discord variables, redeploy, then enable Discord login in Security.
Discord rejects the Interactions Endpoint URL The site must be live, DISCORD_PUBLIC_KEY must be correct and deployed, and the URL must be exactly /api/discord/interactions.
Bot commands don't appear Run npm run discord:register; set DISCORD_GUILD_ID for instant updates; make sure the bot was invited with the applications.commands scope.
Emails don't arrive Check all SMTP_* variables and redeploy; use Email templates → Send test to me; check spam; add SPF/DKIM records for your sender domain.
Upload fails Files must be under 25 MB and one of the allowed types. Check the database has free space (Atlas free tier is 512 MB).
Images from before a move are broken Uploaded files are stored in the database in use when they were uploaded; keep MONGODB_CDN_URI the same.
Changed a NEXT_PUBLIC_… variable but nothing changed Redeploy; these are applied at build time.
A page isn't in the sidebar It must be published, have a category, and the category's section must match the page's section.
Color/appearance change not visible Reload the page (clear cache if needed).
19. Current limitations
The top menu has fixed items (Docs, Guides, API, Features, Changelog, FAQ, Community). You add more with Pages → Show in header navigation or Branding → Extra header links. There is no drag-and-drop menu builder. Sidebar order uses the Order numbers.
The editor does not include tables, tabs, accordions, video embeds or drag-to-reorder blocks yet.
Built-in roles have fixed permissions. Custom roles can't be created from the admin panel.
The Privacy and Terms pages must be edited in code.
Login rate limiting is kept per server instance.
Features don't have their own detail pages (they appear as cards on /features).
20. Getting help
Contact: [add your support email or link here]
When asking for help, include: what you were doing, the exact error message, and (without secrets) which variables you have set.
