Buy JustDocs

Introduction Last updated recently

JustDocs is a self-hosted documentation platform. Your customers write their docs in it, publish them, and their readers get a fast, searchable site, with its own domain if they want one.

# How it fits together

You run one JustDocs installation. Your customers create workspaces in it. A workspace holds a team and one or more docs sites. Each site has spaces (the tabs readers see, such as Guides and API), pages written in a block editor, and releases: every publish takes a snapshot of the pages and puts it live. Readers open the published docs at https://your-domain.example/docs/site-name or at the customer's own domain.

LayerLooked after byWhat lives there
PlatformYou and your administratorsBranding, email, storage, security, payments and plans, the platform's AI key, analytics, the GitHub App, custom-domain certificates, updates.
WorkspaceThe workspace owner and their membersMembers and roles, sites, who can read what, plan and billing, the workspace's own AI key.
SiteEditors and admins of the workspaceSpaces and pages, the editor, releases and history, Customize, custom domains, versions, languages, Git sync, Insights.
Published docsJustDocsThe reader: search, light and dark mode, languages, Ask AI, Markdown pages and an MCP server for AI tools, ratings, feeds, PDF.

Drafts and the live site are separate. Editing a page never changes what readers see until someone publishes, and every earlier release can be put back live.

# What you look after

  • Host the application securely and keep PHP, the database, and the TLS certificate current.
  • Keep the scheduler running. JustDocs has no queue worker: everything that happens in the background runs from the scheduler, once a minute.
  • Configure email, storage, security, sign-in, and, if you sell plans, payments and the plans themselves.
  • Decide what the platform offers on its own keys and accounts: the AI providers behind Ask AI and the writing and translation helpers, country lookups for analytics, the GitHub App, and HTTPS for customers' domains.
  • Watch the admin panel: new workspaces, AI spend, transactions, storage, deletion requests, and the application log.
  • Publish your terms and privacy pages, and support your customers.
This guide is written for the owner of a JustDocs installation. The sections under Workspaces & sites and Editor & publishing describe what your customers do, so you can support them.

Requirements

Check the server before uploading the package. The web installer checks the PHP side; the scheduler, HTTPS and outbound access are yours to arrange.

RequirementMinimum or recommended setup
Web serverApache with mod_rewrite, Nginx, or LiteSpeed. Point the document root at public/.
PHPPHP 8.3 or newer, for the website and for the command line that runs the scheduler.
PHP extensionsBCMath, Ctype, Fileinfo, JSON, Mbstring, OpenSSL, PDO, Tokenizer, XML, cURL, exif, GD and intl.
PHP settingallow_url_fopen enabled.
DatabaseMySQL 5.7.7+ or MariaDB 10.3.17+, with the PDO MySQL driver. Search in the published docs uses the database's full-text search.
Writable pathsstorage/ and bootstrap/cache/ writable by the web server user.
SchedulerA cron job that runs php artisan schedule:run every minute.
HTTPSRequired. Customers' domains, Git webhooks and sign-in with Google all depend on it.
Outbound accessHTTPS to the services you turn on: your mail provider, cloud storage, AI providers, GitHub or GitLab, Cloudflare, the country database.

What you don't need. There is no queue worker to keep alive, no Redis, no WebSocket server and no Node.js on the server. Publishing runs inside the request as one database transaction, and everything else runs from the scheduler. Shared hosting works as long as it can run a cron job every minute and serve public/ as the document root.

Redis can take over the cache later if a very busy install wants it; a setting in the configuration is enough, nothing in the product assumes it.

Installation

# Files setup

  1. Download the product archive from your Envato downloads.
  2. Upload the archive to the directory that will contain the application and extract it on the server. Extracting on the server keeps hidden files from being skipped.
  3. Copy the contents of the package's Script directory into the application directory.
  4. Confirm that hidden files such as .env and .htaccess are present.
  5. Allow the web server user to write to storage/ and bootstrap/cache/. Don't make the whole application writable.

# Document root Important

Point the domain's document root at the package's public/ directory. If the application lives in /var/www/justdocs, the document root is /var/www/justdocs/public.

This keeps .env, the code, logs and stored secrets outside the public web directory. If /public appears in your site's address, the document root isn't set correctly.

A package-level fallback file may help on restricted hosting, but the real document root is the production-safe answer.

Web server notes

  • Apache/LiteSpeed: allow the included .htaccess rules and enable URL rewriting.
  • Nginx: route requests through public/index.php with a standard Laravel server block.
  • Customers' domains: requests for a customer's domain arrive with that hostname. Make the JustDocs virtual host the default one (Apache: first in the list; Nginx: server_name _; or default_server), so they reach JustDocs instead of a default page. See Custom domains.
  • Reverse proxies: forward the original host, scheme and client address, so the application knows it's on HTTPS.

# Database setup

  1. Create an empty MySQL or MariaDB database with the utf8mb4 character set.
  2. Create a dedicated database user with a strong password.
  3. Give that user the rights to create and alter tables and to read and write data.
  4. Note the host, port, database name, username and password for the installer.

Don't reuse the database administrator account. On managed database services, also allow connections from the application host.

# Web installer

Open https://your-domain.example/install. The installer walks through three steps:

  1. Requirements: the PHP version, allow_url_fopen and the required extensions, each with a check mark.
  2. Database: the connection details of the empty database. The installer tests them before it goes on, and asks you to confirm if the database already has tables (an earlier or unfinished installation, or another app's).
  3. General info: the site name, the website address (the full https:// address readers will use), the administrator's email and password, and your product license code from your Envato downloads or purchase email.

Then the installer runs its steps one at a time, with a progress list: checking the license, saving the database connection, creating the tables, adding the default data, applying your site name and address, creating the administrator, and finishing. Keep the page open. Because each step is its own request, a host's time limit can't cut the whole setup short, and a step that stops can be retried where it stopped. A refused license code shows Change the details to correct it.

When it finishes, the browser opens your site. Sign in at https://your-domain.example/admin with the administrator account. An install marker in storage/app/ stops the installer from running again.

If the installer fails: read storage/logs/laravel.log, fix the cause, and use Retry. Start over clears the installer's progress (not the database) and goes back to the database step; empty the database or pick a new one first. If the browser that started the installation is gone, the installer says the setup has already started: run php artisan installer:reset in the site's folder, or rename storage/app/installing.json to installing.json.bak with your File Manager or FTP. Check the database connection, file ownership and the hidden files, and if only /public/install works, fix the document root.

A fresh install writes outgoing email to the log file instead of sending it, and Admin → System health says so. Set up email before inviting anyone.

Launch checklist

Do these in order before inviting customers. Later items depend on earlier ones, so testing them as one chain tells you more than checking settings one by one. Items marked optional are features you can leave off.

OrderOwner actionLaunch test
1Set the production address, HTTPS, site name, logos, colours, timezone and language.Open the homepage, sign-in, sign-up, the app and the admin on a desktop and a phone, in light and dark mode.
2Configure email.Save the email settings to get a test email, sign up a new account and confirm it, invite a member, reset a password.
3Install the scheduler cron line.Within five minutes, Admin → System health shows the scheduler as Healthy, and Site settings → Git sync and → Domains stop warning that it isn't running.
4Choose storage and upload limits.Upload an image and a file to a page, publish, and open both from the published docs.
5Review security and compliance: 2FA, captcha, email checks, the link policy, cookies, account deletion.Sign up with 2FA on, try a wrong site password five times, delete a test account.
6Sign in with Google, GitHub, X or Facebook (optional).Sign in with each provider you set up and land in the app.
7Add the platform's AI account and budget (optional).Send the test question in Settings → AI, then ask a question in a published site.
8Turn on analytics and choose how countries are found.Open a published page, then see it in the site's Insights.
9Set up HTTPS for customers' domains (optional).Connect a test domain and see it reach Live.
10Create the GitHub App or GitLab application (optional).Connect a test repository, push a change, publish, and see the commit.
11When billing is on: payments, invoices, taxes, and the plans.Subscribe in the sandbox, hit a limit, see the upgrade prompt, cancel.
12Back up, rehearse a restore, and read the update steps.Restore the backup on a staging copy and sign in.

Final smoke test: register a new customer, create a workspace and a site, write a page with a heading, a list, a code block and an image, publish it, open the published docs, search for a word on the page, switch to dark mode, ask Ask AI a question, and add a custom domain.

Configuration

The settings pages live under Admin → Settings. Configure the platform first; customers then set up their own sites from the app.

# Site, branding and languages

Start in Admin → Settings → General:

  • Site: name, App URL, description, slogan, whether new accounts must confirm their email.
  • Branding: light and dark logos, favicon, the docs badge icon (shown in grey beside “Powered by” on published docs), social-sharing image, social profile links.
  • Appearance: whether people can switch themes, the default theme (light, dark, or System, which follows each visitor's device), text direction, page transitions.
  • Localization: the default language, the language switch, following the browser's language, and the platform timezone. Each workspace also has its own timezone for Insights.
  • Homepage: the landing page, an example docs site shown on it, or a redirect to an address of your own.
  • Social auth: sign-in with Google, GitHub, X or Facebook, one sub-tab each (see Social sign-in).
  • Code & Ads: custom CSS and JavaScript for the platform, and an optional ad slot in the docs sidebar (an HTML snippet from Carbon Ads, EthicalAds or similar).

Make the platform's colour theme in Admin → Settings → Theme, and set the admin panel's own logos and title in Admin → Settings → Admin. Reset to default on the Theme page brings back the built-in colours without contacting the theme server; the theme file it replaces is kept in storage/app/theme-backups.

Keep the App URL exact: https://, the final hostname, no trailing path. Custom domains, Git webhooks, social sign-in, emails and generated links all depend on it.

Languages

The app ships in English and Romanian. To add a language, copy lang/en.json to lang/xx.json and translate the values; the language then appears in the language menus and as a default language. Laravel's own messages live in lang/xx/*.php.

Published docs have their own words ("On this page", the search box, Ask AI, ratings, about 200 texts). Reader packs in lang/reader/ translate only those, in German, Spanish, French, Italian, Japanese, Portuguese (Brazil) and Chinese (Simplified). A site picks its reader language in Customize → Configure, or follows each reader's browser. To add a pack, copy one and name it after the language's code.

php artisan translations:check

The command lists missing texts, texts the code no longer uses, and broken translations (a lost placeholder, a changed tag, the wrong number of plural forms).

# Email

Open Admin → Settings → Emails. Email is used for account confirmation, password resets, invitations, 2FA codes, email changes, account deletion, and billing notices.

DriverUseNotes
SMTPMost transactional email servicesHost, port, encryption, username, password, sender name and address.
MailgunMailgun's APISending domain, secret, and the regional endpoint.
SendmailThe server's own mail transportOnly where the host looks after deliverability.
LogDevelopmentWrites messages to the log file instead of sending them. Never for a launch.

Use a sender on a domain you control and set up SPF, DKIM and DMARC with your provider. Saving the settings sends a test email to the administrator who saved them.

# Scheduler

Add one cron entry that runs Laravel's scheduler every minute. The command line needs PHP 8.3 or newer too: hosts with several PHP versions often run an older one there, so check php -v and, if needed, use the full path to PHP 8.3 (for example /usr/local/bin/php8.3; your host's panel lists it).

* * * * * cd /path/to/justdocs && php artisan schedule:run >> /dev/null 2>&1

JustDocs has no queue worker, so this one line is everything that runs in the background. Admin → System health shows when it last ran:

  • checking customers' domains (every five minutes) and moving them towards Live;
  • Git sync: applying pushes and sending releases to GitHub or GitLab (every minute, with a full pass every hour);
  • the daily analytics summary and the country database update;
  • checking outside links in the docs (nightly) and refreshing API pages from their OpenAPI addresses;
  • when billing is on: ending trials and subscriptions and sending their notices (hourly);
  • carrying out account deletions after their waiting period, pruning old Ask AI questions, and tidying cache files.
A missing scheduler looks like many unrelated bugs. Domains stay on "Waiting for DNS", Git sync waits, Insights show nothing after the first day, and trials never end. Site settings → Git sync and → Domains say when the scheduler hasn't run.

# Storage and uploads

Choose where images and files go in Admin → Settings → Storage.

DriverTypical useConfiguration
Public (local)One server, simplest setupFiles live in storage/app/public, served through public/storage.
Amazon S3Managed object storageAccess key, secret, region, bucket, and optionally a CloudFront CDN with signed addresses.
DigitalOcean SpacesS3-compatible object storageAccess key, secret, region, bucket.
WasabiS3-compatible object storageAccess key, secret, region, bucket.
MinIOSelf-hosted object storageAccess key, secret, region, bucket, endpoint.
PushrObject storage with a CDNAccess key, secret, bucket, endpoint, CDN hostname.
Cloudflare R2S3-compatible edge storageAccess key, secret, bucket, region, endpoint, public address.

Create the bucket first, give the credentials access to that bucket only, and set CORS rules for your domain if browsers read objects directly. After saving, upload an image to a page and open it from the published docs.

Private docs and files. On cloud storage, files of password-protected and members-only sites are served through short-lived links, so a saved address stops working. On local disk, files have unguessable names, and anyone who has the exact address can open them. Tell customers with sensitive docs to pick cloud storage, or keep sensitive material out of images and attachments.

Uploads count toward the workspace's storage limit when billing is on.

Upload limits

Admin → Settings → Media sets the largest image or file editors can put on a page, the allowed file extensions, avatar sizes, and whether large files upload in parts. Uploading in parts (a few MB each) gets around low upload limits on shared hosting and behind Cloudflare; a 100 MB import then arrives as many small requests.

# Security and compliance

Review Admin → Settings → Security:

  • email-based 2FA: on or off, on by default for new accounts, and whether people may turn it off;
  • Enforce SSL, if your proxy doesn't already redirect to HTTPS;
  • a captcha on the sign-in and sign-up forms: Cloudflare Turnstile, hCaptcha or Google reCAPTCHA;
  • checking that sign-up addresses can receive mail (Abstract API), and an email domain policy: accept every domain, or only the ones you list;
  • the link policy for published docs: allow links to every domain, only to allowed domains, or block the domains you list. It applies to every site on the platform.

Password-protected sites rate-limit wrong passwords on their own: five a minute and thirty an hour per visitor and site, after which even the right password waits.

Then review Admin → Settings → Compliance: the cookie notice, whether people may change their email address, and account deletion: on or off, immediate or with a waiting period people can cancel (14 days), and whether owning a workspace or an active subscription blocks it until resolved. Deletion requests show in Admin → Users.

# Social sign-in

People can sign in with Google, GitHub, X or Facebook, on the sign-in and create-account pages. Each button shows once you enter that provider's client ID and secret in Admin → Settings → General → Social auth. Each provider has its own sub-tab, which also shows the callback address to give the provider:

  • Google: an OAuth client in the Google Cloud console, callback https://your-domain.example/socialAuth/google/callback.
  • GitHub: an OAuth App under Settings → Developer settings, callback https://your-domain.example/socialAuth/github/callback.
  • X: an app in the X developer portal with OAuth 2.0 (Web App) turned on, callback https://your-domain.example/socialAuth/x/callback. Ask X for email access: people whose provider doesn't share an email can't sign up.
  • Facebook: an app in Meta for Developers with Facebook Login, callback https://your-domain.example/socialAuth/facebook/callback.

The App URL must match the hostname in the callback exactly.

How it behaves

  • The first sign-in with a provider creates an account with the name and email it shares. Later sign-ins with the same provider find that account again.
  • A provider has to share an email address. If it doesn't (X only does once your app is allowed to ask for it), the person sees a message and can use another way to sign in.
  • An email that already has an account can't sign up again through a provider: that person signs in the way they first did.
  • The sign-up rules still apply: allowed and blocked email domains, email confirmation if you require it, and two-step sign-in for people who turned it on.
  • Invitations to a workspace work the same with every provider: the person lands in the workspace after signing in.

# Payments and plans

Billing follows the license. With a Regular License, billing is off: every plan feature is allowed and every limit is unlimited, so you can run JustDocs for your own team or company. With an Extended License, workspaces choose a plan, start trials, pay, and hit limits.

Payments

Open Admin → Settings → Payments:

  • the currency, its symbol and position, the business country;
  • Stripe and PayPal, for subscriptions that renew automatically and for one-time payments, each with sandbox and live keys and its webhook or IPN secret;
  • regional one-time providers (Coinbase, CoinGate, Crypto.com, Flutterwave, Mollie, Paystack and others), where a payment buys a fixed access period instead of a renewing subscription;
  • invoices: generated automatically for payments, with a prefix and your company details, and taxes per country under Admin → Finances.

Run each provider's sandbox before launch: subscribe, renew, cancel, and watch the webhook arrive. A plan limit reached during a trial shows the upgrade prompt, and downgrading leaves nothing broken.

Plans

Create plans in Admin → Finances → Plans. One plan covers a whole workspace. Each plan has a monthly and a yearly price, free trial days (once per workspace), limits, and features. Leave a limit empty for unlimited.

SettingWhat it controls
Docs sites, team seats, custom domains, versions per site, storageHow many of each a workspace may have. Seats count the owner and pending invitations. Zero custom domains leaves them out of the plan.
Password-protected docs, members-only docs, remove "Powered by"Whether sites may require a password, be readable by members only, or hide the platform branding.
Ask AI answers, AI writing requests, pages translated with AI (a month)Allowances on the platform's AI key. A workspace's own key isn't counted.
FeaturesThe Customize options and other features sites on the plan may use: themes, fonts, code themes, background tint, announcement, footer links, primary link, page ratings, page actions, MCP server, Ask AI, custom CSS, integrations, analytics, languages, Write with AI, Git sync. An unticked option shows as "Pro" with an upgrade prompt.

Workspace owners see their plan, usage and payments under Plans & billing in the app, and compare plans on the public pricing page.

AI and Insights

Three things in JustDocs use an AI provider: Ask AI in the published docs, where readers ask questions and get answers that cite pages; Write with AI in the editor, which writes or improves text as real blocks; and Translate with AI, which fills in a site's other languages. All three run on the platform's AI account, within the plan's monthly allowances, or on a workspace's own key with no limits.

# The platform's AI

  1. Add an account under Admin → AI → AI accounts: the provider, a model, and your API key. Providers: OpenAI, Anthropic, Google Gemini, Mistral AI, DeepSeek, xAI, Qwen, Kimi, Z.ai, Ollama, and any OpenAI-compatible endpoint such as OpenRouter. Admin → AI → AI models keeps the model list, and "Import from provider" fetches the current models with a real key.
  2. In Admin → Settings → AI, pick it as the platform AI account, set a monthly budget (Ask AI pauses for workspaces on the platform key once it's spent; empty means no limit), how much of the docs is sent with each question, and the longest answer. Send the test question.
  3. Decide whether workspaces can use their own key. They add it under Workspace settings → AI; their answers then don't count toward the plan, and they pay their provider directly.

Admin → AI → AI requests lists every call with its workspace, kind (answer, writing, translation), tokens and cost, so you can see where the budget goes. Readers' questions and the docs' own unanswered questions show on each site's Feedback page.

Readers' questions go to the provider of the account that answers them. Say so in your privacy policy, and choose a provider whose terms fit your customers.

# Docs for AI tools

Every published site can also be read by AI tools, with no key of yours involved:

  • /llms.txt and /llms-full.txt under the site's address, and every page as Markdown with .md;
  • an MCP server per site, which Claude Code, Cursor, VS Code and other tools use to search and read the docs; the site's Customize → Configure → AI tools page has the address and one-click set-ups;
  • page actions in the reader: copy a page as Markdown or open it in ChatGPT or Claude.

These are plan features when billing is on. The site's Insights → AI tools page shows which tools read the docs.

# Built-in analytics

Admin → Settings → Analytics turns on Insights for every site: page views, visitors, visits, searches, AI tools and broken links, without cookies and without storing IP addresses. Off means nothing is recorded and the Insights pages are hidden. Plans decide who sees Insights.

Daily totals are kept for good; detailed events are kept for the number of months you choose, which keeps the database small on busy sites.

Readers' countries are found from the IP address at the moment of the visit, and the address itself is never stored:

  • Off: no countries.
  • Cloudflare: free and instant for sites behind Cloudflare, from the header it adds.
  • DB-IP: a free database downloaded to the server and updated by the scheduler; the Insights pages credit "IP Geolocation by DB-IP" as its licence asks.
  • MaxMind GeoLite2: free with a MaxMind account (account ID and licence key), or a GeoLite2-Country file you keep up to date yourself.
  • IPinfo, ip-api, IPGeolocation.io: lookup services. Readers' addresses are sent to the service; answers are kept for a day under a code, not the address.

Use Test country detection after saving. Customers can also add their own analytics and support tools (Google Analytics, Plausible, PostHog, Intercom and more) per site, with a consent notice for tools that set cookies.

Custom domains

Every site always works at its built-in address on your platform, https://your-domain.example/docs/site-name, under your own certificate. Custom domains (docs.customer.com) are an extra, and a plan feature when billing is on. This section explains how to offer them with HTTPS.

# What the customer does

In Site settings → Domains, the customer adds their domain and creates two DNS records:

RecordNameValueWhy
TXT_docsbuilder.docs.customer.comthe token shownProves they own the domain
CNAMEdocs.customer.comyour CNAME targetSends visitors to your platform

A bare domain (customer.com) can't have a CNAME record, so they use an ALIAS or flattened CNAME record, or an A record to your server's address if you give one in the admin. A subdomain is always simpler.

JustDocs checks new domains every few minutes, then less often. Each domain moves through Waiting for DNS → Connecting → Getting certificate → Live, and when something is wrong the customer sees a plain explanation, such as "points to X, not Y". Check connection runs the check straight away. A domain is only used for canonical links and the sitemap once it's Live, which means it answers over HTTPS and leads to your install.

# Before you start

  1. Run the scheduler. The domain checks run from it (see Scheduler).
  2. Let the app answer on any hostname. Requests for customers' domains arrive with the customer's hostname. Your web server must pass them to JustDocs instead of showing a default page: with Apache, make the JustDocs virtual host the first one; with Nginx, use server_name _; or default_server.
  3. Open Admin → Settings → Custom domains and choose one of the three ways to handle certificates below. The CNAME target is the host customers point at; empty means your platform's own host.

You can check any domain by hand:

php artisan docs:check-domains --domain=<id>

# Option 1: Manual (the default)

Use this if your hosting already gets certificates for every domain pointed at it (cPanel AutoSSL, Plesk), or if you run certbot yourself.

JustDocs checks the DNS records, then tests whether the domain reaches it over HTTPS. If the domain works over HTTP but not HTTPS, the customer is told the certificate is still missing. JustDocs doesn't create certificates in this mode.

Settings: the CNAME target, and optionally a server IP address shown to customers who connect a bare domain.

# Option 2: Own server (Caddy)

Use this if you have a VPS or dedicated server. Caddy runs in front of JustDocs and gets a free Let's Encrypt certificate for each customer domain the first time someone visits it. Before it does, it asks JustDocs whether that domain is allowed; only domains whose ownership record has been confirmed are, so nobody can make your server request certificates for random domains.

  1. Move Apache or Nginx off ports 80 and 443, for example to 127.0.0.1:8080. Keep the App URL as https://your-domain.example; JustDocs trusts the forwarded headers Caddy sends.
  2. Install Caddy and make sure ports 80 and 443 reach it from the internet. Let's Encrypt needs both.
  3. In Admin → Settings → Custom domains, choose Own server (Caddy). The page shows the exact ask line with your check key.
  4. Put this in /etc/caddy/Caddyfile, with your own domain, email and ask line:
{
	email you@your-domain.example

	on_demand_tls {
		ask https://your-domain.example/__domains/allowed?key=YOUR_CHECK_KEY
	}
}

# Your platform: a normal certificate.
your-domain.example {
	reverse_proxy 127.0.0.1:8080
}

# Customers' domains: a certificate on first visit, for allowed domains only.
https:// {
	tls {
		on_demand
	}
	reverse_proxy 127.0.0.1:8080
}

http:// {
	redir https://{host}{uri} permanent
}

Then run sudo systemctl reload caddy. When a customer's DNS is right, their domain goes from Getting certificate to Live, usually within a minute. If it stays stuck, the customer is asked to check that ports 80 and 443 reach your server and that no CAA record on their domain blocks Let's Encrypt. If you make a new check key, update the ask line and reload Caddy.

# Option 3: Cloudflare for SaaS

Use this if you're on shared hosting or a platform where you can't run Caddy, or if you want Cloudflare's network in front of customers' domains. Cloudflare issues and renews the certificates; JustDocs registers each customer domain with Cloudflare through its API and reports progress.

Cloudflare charges per custom hostname beyond a free allowance; see Cloudflare for SaaS pricing. Customers should use subdomains: a bare domain behind Cloudflare is an Enterprise add-on unless their DNS provider flattens CNAME records.

  1. Add your platform domain to Cloudflare; your nameservers must point to Cloudflare.
  2. Create a proxied DNS record for the address customers will point at, for example customers.your-domain.example, as an A record to your server.
  3. Under SSL/TLS → Custom Hostnames, enable Cloudflare for SaaS and set the Fallback Origin to that address.
  4. Set SSL/TLS → Overview → encryption mode to Full. Your server needs a certificate of its own; a Cloudflare Origin Certificate is fine.
  5. Create an API token under My Profile → API Tokens → Create Token → Custom token with the permission Zone → SSL and Certificates → Edit on your platform domain.
  6. Copy the Zone ID from the domain's Overview page.
  7. In Admin → Settings → Custom domains, choose Cloudflare for SaaS, set the CNAME target to customers.your-domain.example, and enter the zone ID and the token.

Once a customer adds their domain and the TXT record is found, JustDocs creates the custom hostname in Cloudflare, and Cloudflare validates it after the CNAME is in place. If Cloudflare asks for anything extra, such as its own TXT record, the customer sees that request on the domain. Removing a domain also removes its custom hostname from Cloudflare.

Git sync

Git sync lets customers keep their docs in a GitHub or GitLab repository: a push to the branch shows up in JustDocs, and every publish goes back as a commit. GitLab can be gitlab.com or your own GitLab. It's optional, and a plan feature when billing is on.

# What the customer does

In Site settings → Git sync, the customer clicks Connect GitHub or Connect GitLab (only the ones you set up are shown). GitHub asks them to sign in and to install your platform's GitHub App on their account or organisation; GitLab asks them to sign in and allow JustDocs. Then they pick the repository, the branch (usually main), an optional folder for docs inside a project's own repository, and whether pushes go live straight away or arrive as drafts (the default). Each version of a site can be connected to its own branch.

  • A repository with docs (Mintlify docs.json, GitBook SUMMARY.md, or plain folders of Markdown) is shown for review, like a zip import, and comes in as drafts. An empty repository gets the site's pages with the next publish.
  • A push brings changed files in as drafts: changed pages are updated, new files become pages, renamed files keep their pages, deleted files archive their pages. Images become site files.
  • Each publish goes to the repository as one commit, with the release title and notes as its message and the publisher as its author. Only pages changed in JustDocs are written; a file nobody edited in JustDocs is never rewritten.
  • A page changed in both places keeps the editor's draft; the repository's version is saved in the page's history and the editor offers "Use GitHub's version" or "Keep mine".
  • API pages made from an OpenAPI file stay in JustDocs and aren't written to the repository.

Site settings → Git sync shows what waits, the last syncs and their outcome, and a Sync now button.

GitHub and GitLab differ in one way. GitHub works through your platform's GitHub App: repository access uses GitHub's one-hour tokens, made when needed and never stored. GitLab has no apps of that kind, so a connection works as the person who connected it; their GitLab sign-in is kept encrypted with the connection and renewed as it expires. JustDocs adds a webhook to the project for pushes, which needs the Maintainer role; without it, pushes come in once an hour and with Sync now.

Before you start: the scheduler must run (pushes are applied and releases sent by a job that runs every minute), and your install must be reachable from the internet over HTTPS, because GitHub sends push notices to https://your-domain.example/git/github/webhook and GitLab to /git/gitlab/webhook. An install they can't reach still connects and publishes; changes then come in with Sync now and once an hour.

# Creating the GitHub App

Every install has its own GitHub App, so your customers see your name when they install it.

  1. Open Admin → Settings → Git sync and click Create GitHub App.
  2. Give it a name (unique on GitHub, up to 34 characters) and, if your team should manage it together, a GitHub organisation.
  3. Click Continue to GitHub, check the name, and confirm. GitHub creates the app and sends you back; JustDocs saves its id, keys and secrets, encrypted.
  4. Click Test to check GitHub accepts the keys.

The app asks for read and write access to repository contents, read access to metadata, and push notices. Customers choose which repositories it can reach.

Making it by hand (for example, if your install isn't reachable yet): create a GitHub App on GitHub with the callback URL https://your-domain.example/app/docs/git/github/callback and "Request user authorization (OAuth) during installation" ticked, the webhook URL https://your-domain.example/git/github/webhook with a secret, the permissions Contents: read and write and Metadata: read, and the Push event. Then fill in the app id, slug, client id and secret, webhook secret and private key under Set up by hand on the GitHub tab.

Removing the app stops every connected site from syncing until a new app is set up and the sites connect again. Delete the app on GitHub too.

# Adding the GitLab application

  1. In GitLab, open Admin area → Applications (on your own GitLab, for every user) or User settings → Applications (on gitlab.com), and add an application with the redirect URI https://your-domain.example/app/docs/git/gitlab/callback, Confidential ticked, and the api scope.
  2. In Admin → Settings → Git sync → GitLab, fill in the Application ID and Secret, and your GitLab's address if it isn't gitlab.com.
  3. Click Test GitLab to check the address answers.

A self-hosted GitLab must reach your install for webhooks; if it refuses addresses on your network, an administrator allows them under Admin area → Settings → Network → Outbound requests.

Running a sync by hand: php artisan docs:git-sync for what waits, or php artisan docs:git-sync --all for every connected branch.

Workspaces and sites

What your customers do once they sign in. A new account lands in a welcome step that creates its first workspace and site, and opens the editor on a starter page.

# Workspaces, members and roles

A workspace has a name and a timezone (Insights' hours follow it), its members, its sites, and its plan. Members are invited by email; an invitation link works for seven days. A member can be limited to chosen sites. Ownership can be handed to another member, and the Activity page lists who changed what, with a CSV download.

RoleCan
OwnerEverything, including billing and deleting the workspace.
AdminManage sites, domains, settings and the team. Publish and delete pages.
EditorWrite, archive and publish pages. Can't change site settings or the team.
ViewerRead drafts, previews and private docs without changing anything.

Every action is checked on the server against these roles, and a suspended member loses access at once. Two people on the same page see each other in the editor, and a save never writes over someone else's unseen changes: the editor asks "Keep my version" or "Use their version", and the other version goes into the page's history.

# Sites and who can read them

A site has a name, a built-in address (/docs/site-name), spaces (the tabs readers see), and pages nested up to five levels. Its Overview shows the live site, its state, what needs attention, analytics, releases and shortcuts. Site settings has these sections:

  • General: name, description, address slug, and deleting the site.
  • Access: Public (anyone with the link), Password (visitors unlock the site first), or Private (workspace members only, after signing in, on the built-in address and on custom domains). Spaces and pages can also be private on a public site; private titles never leak to signed-out readers. Reader search and search engine indexing switches live here too.
  • SEO: the home page's search title and description, with previews of the search result and the shared link.
  • Domains: the customer's own domain, see Custom domains.
  • Redirects: old addresses that send readers to the right page. Publishing adds one automatically when a page's address changes.
  • Integrations: Google Analytics 4, Google Tag Manager, Plausible, Fathom, PostHog, Microsoft Clarity, Hotjar, Intercom and Crisp, each by its ID, with a consent notice for the ones that set cookies. Tools that run code load only on the customer's own domain.
  • Languages and Git sync, below and above.

Files lists every image and file uploaded to the site's pages, with what still uses them; a file shown on a page, a revision or a release can't be deleted.

# Versions and languages

Versions (v1, v2, Latest) are full copies of a site's pages with their own addresses, a default version, hidden versions, a switcher in the reader and an "older version" banner. A new version starts as a copy of another. One publish puts every version live.

Languages share one page tree: each page can be translated into the site's other languages, in the editor beside the original or with AI (a page, the changes since the original moved on, or every missing page, within the plan's monthly allowance). One publish puts every language live. Readers get /docs/site-name/es/…, a language menu, untranslated pages in the original with a note, per-language search and sitemaps, and the reader's own words from the reader packs. Export, import and Git sync keep each language in its folder.

Editor and publishing

# The editor

The editor shows the site's spaces in the sidebar, the open space's pages beside it, and the page itself, with Editor and Preview switching in place. Pages are made of blocks, added from the / menu on an empty line:

  • text: paragraphs, headings, lists, quotes, tooltips;
  • code blocks and code groups with a copy button and syntax highlighting;
  • images (SVG too, cleaned of anything that could run code) and files, uploaded in parts, or chosen from the site's Files;
  • callouts, tables, tabs, steps, accordions and cards, which can hold text, lists, code, images and tables;
  • embeds: YouTube, Vimeo, Loom, Wistia, Figma, Miro, CodePen, CodeSandbox, StackBlitz, Google Slides, Docs, Sheets and Drive, Arcade and Supademo; any other link becomes a link card;
  • Mermaid diagrams and KaTeX maths, loaded only on pages that use them;
  • changelog entries, which get an RSS feed, and API blocks made from an OpenAPI file.

The page saves itself as you type. Page settings hold the address, who can read it, an icon, a template, and its own SEO fields. New pages can start from a template. Write with AI (Space on an empty line, or the AI button on selected text) writes from a request, or improves, corrects, shortens or simplifies, to keep or discard.

# Import and export

  • One page of Markdown or MDX, understanding Mintlify, GitBook, Docusaurus and GitHub syntax.
  • A whole docs folder as a zip, from Mintlify (docs.json), GitBook (SUMMARY.md) or plain folders, with a review step before anything is created. Links between pages and images come along.
  • An OpenAPI 3 file (JSON or YAML, uploaded or from an address) becomes an introduction and a page per operation, with request samples in seven languages. Pages made from an address are refreshed nightly.
  • Export a site version as Mintlify-style MDX with docs.json; importing the export gives the same site back.

# Publishing and history

Publish in the editor shows what changed since the last release, takes a title and notes, and puts a new release live in one step. Readers never see a half-published site. The Releases page lists every release with what it changed, page by page and line by line, and any earlier release can be put back live as a new one. Each page has a full history of its revisions, showing what restoring one would change.

Preview shows the drafts as readers would see them, and an expiring preview link can be shared with people outside the workspace. The whole site or one page can be saved as a PDF.

# Customize

Customize has three pages, each beside a live preview of the site:

  • Theme: title, icon, light and dark logos; style (Clean, Muted, Bold, Gradient), primary colour, background tint, light, dark or system mode; fonts and code block themes; corners, sidebar and custom CSS.
  • Layout: an announcement bar, the header (site name, search bar or button, header links), page width, the updated date and previous/next links, and the footer (columns, copyright, social accounts, "Powered by").
  • Configure: the reader language, where the logo leads, links to other sites, the privacy policy, the social preview image, page ratings, page actions, Ask AI and the MCP set-up.

Options a plan doesn't include show as "Pro" with an upgrade prompt, when billing is on.

# What readers get

The published docs are a fast site with spaces as tabs, a sidebar tree, a table of contents, previous and next links, search (Ctrl K) across every page's full text, light and dark mode, a language menu and a version switcher. Readers can ask Ask AI and get streamed answers that cite pages, rate a page ("Was this page helpful?") with a comment, copy a page as Markdown, open it in an AI tool, subscribe to a changelog's feed, and print or save pages as PDF. A page that no longer exists suggests where the reader meant to go. Every site has a sitemap, and private pages never appear in search, navigation or sitemaps for people who may not read them.

# Insights

Each site has its Insights pages, when analytics is on and the plan includes it:

  • Traffic: page views, visitors and visits over time, people against AI agents, pages and entry pages, traffic sources, countries and languages, platforms, active hours, and bots.
  • Search: what readers looked for, what they opened, and searches that found nothing, as ideas for new pages.
  • AI tools: which tools read the docs through llms.txt, Markdown pages or the MCP server.
  • Broken links: links in the docs that lead nowhere (checked on every publish; outside links nightly), and addresses readers couldn't open, each one a redirect away.
  • Feedback: page ratings with their comments, and what readers asked Ask AI, including questions the docs didn't answer.

Administration

The admin panel is at https://your-domain.example/admin. The installer creates the first administrator; promote another account from the application directory with:

php artisan make-admin user@example.com
AreaWhat's there
DashboardPeople, workspaces and published sites, then four charts with a period to pick: sign-ups, publishing (releases and new sites), readers (page views, while Insights is on), and revenue when billing is on, or AI use and what the platform's AI keys cost when it's off.
System healthPHP, the database, the cache, the folders JustDocs writes to, the scheduler, email and share pictures, each marked Healthy, Warning or Error with what to do. A support report to copy into a request: it leaves out passwords, keys, license codes and customers' data.
UsersAccounts with their role, workspaces and any request to delete them; deletion requests, notifications, and uploaded files with what uses each one. Sign in as a user to see what they see. Deleting an account first lists what goes with it: the workspaces they own, with their sites and files. Files they added to other people's workspaces stay there.
DocsWorkspaces: edit, transfer or restore one, and manage its members (suspend, give access back, remove) and invitations (resend, cancel). Docs sites: content, domains and releases, with buttons to open the live site or sign in as the owner. Domains: every custom domain with its state and the last check's message, and Check now. Git sync: each connection's state and sync log. The activity log.
AIAI accounts, the model catalogue, and every AI request with its cost.
FinancesPlans, subscriptions and transactions, taxes, countries. A subscription from a real payment provider is cancelled, not deleted; only free trials and other records JustDocs makes itself can be deleted.
SiteThe platform's public pages, blog posts, contact messages and announcements.
SettingsGeneral, Theme, Admin, Emails, Storage, Media, Security, Compliance, Payments, AI, Analytics, Custom domains, Git sync, License.

When something seems off on the server, start with Admin → System health. When a customer reports a problem, check in this order: the site's state on its Overview (unpublished changes, needs attention), the workspace's plan and usage, the scheduler, the application log in storage/logs/laravel.log, and, for AI, Git or domain issues, Admin → AI → AI requests, Admin → Docs → Git sync or Admin → Docs → Domains.

# Backups and recovery

A usable backup includes:

  • the complete database;
  • the .env file;
  • storage/, including the install marker and local uploads;
  • cloud storage buckets, or their replication and versioning policy;
  • custom code, themes or language files kept outside the original package;
  • the cron line, the web server configuration, and the Caddyfile if you use Caddy.

Encrypt backups, keep copies off the application server, and test a restore on a staging copy. A database-only restore leaves images missing from pages; a file-only restore leaves files the database doesn't know about.

How to update

Back up first. Package updates overwrite product files. Keep your own changes under version control and try the new release on a staging copy.
  1. Read the release notes and compare any new requirements with your server.
  2. Back up the database, .env, storage/ and your customizations.
  3. Download the latest archive from Envato and replace the application files with the contents of its Script directory. Keep your .env and storage/.
  4. Visit https://your-domain.example/update while signed in as an administrator and run the update. It applies the database changes the new release needs.
  5. Run the launch smoke test: sign in, send a test email, publish a site, open the published docs, ask Ask AI, and if you use them, check a custom domain and a Git sync.

If the installer appears after an update, the install marker in storage/app/ wasn't preserved. If the application fails before the update page loads, check storage/logs/laravel.log, the PHP version, file ownership and the restored .env.

FAQ and support

# Why does my address contain /public?

Your domain points at the application directory instead of its public/ subdirectory. Correct the document root; don't move .env or the code into the public directory.

# Why do I get a 500 error after uploading?

Read storage/logs/laravel.log. The usual causes: a missing hidden file, an unsupported PHP version, a missing extension, storage/ or bootstrap/cache/ not writable, an incomplete upload, or the database connection.

# Why don't emails arrive?

A fresh install writes email to the log file. Configure a driver in Admin → Settings → Emails, send the test email, and check the sender domain's SPF and DKIM records.

# Why is a domain stuck on "Waiting for DNS", or Git sync waiting?

Both depend on the scheduler. Check the cron line, the PHP path and the application path. Then, for a domain, read its message in Admin → Docs → Domains and use Check now; for Git sync, the sync log in Admin → Docs → Git sync (or the site's Site settings → Git sync), and whether your install is reachable from the internet for webhooks.

# Why doesn't Ask AI answer?

Check that Settings → AI has a platform account and the test question works, that the monthly budget isn't spent, that the workspace's plan includes Ask AI and has answers left, and that the site turned it on in Customize → Configure. Admin → AI → AI requests shows the provider's error.

# Why are the Insights pages empty or missing?

Missing: analytics is off in Admin → Settings → Analytics, or the plan doesn't include it. Empty: nobody has opened the published docs yet, or the scheduler hasn't run the daily summary; today's visits show live.

# Why do uploads fail?

Check the limits in Admin → Settings → Media and turn on uploading in parts if the host has a low request size limit. On cloud storage, check that the bucket exists, the credentials and region are right, and CORS allows your domain.

# Why does an option say "Pro"?

Billing is on and the workspace's plan doesn't include that feature. Change the plan's features in Admin → Finances → Plans, or let the customer upgrade.

# Why does a reader get "page not found" for a page that exists?

The page, its space or the site is private, or it isn't published yet. Signed-out readers are told nothing about private pages on purpose. Members see it after signing in; on a custom domain, a one-time sign-in pass from the app brings them back to the page.

# Getting support

For product support, contact Qdev Techs through the Envato author profile. Installation and customization services are also available from Qdev Techs.

Include the JustDocs version, the PHP version, the hosting type, the affected area, steps to reproduce, the time and timezone, and the relevant log excerpt with secrets removed. Never send .env, purchase codes, payment secrets, AI keys or GitHub App keys.