Skip to main content

Deployment

5 min readStableIntermediate

OwnDocs ships as source code you own, so deploying starts with your copy of it rather than with someone else's repository. Push that copy to a Git repository you control, then point a host at it. By the end you'll have a live documentation site answering on a public URL, or on port 3000 of your own host.

Prerequisites

  • Your copy of the OwnDocs source, and a Git repository you control to push it to. A private repository is fine, and is the usual choice.
  • Node.js 20.9.0 or newer and npm 10 or newer, for a manual build. Node.js 24 is the tested version.
  • Docker with the Compose plugin, for the self-hosted container path
  • Values ready for the environment variables listed below; run bash scripts/setup-env.sh to generate the secret ones

Steps

Put the source in your own repository

OwnDocs is a commercial product, and the repository it ships from is private. A hosting platform cannot clone that repository on your behalf, so a deploy button pointing at it would fail every time. That is why there isn't one. What you deploy is your own copy of the source.

Create an empty repository on GitHub, GitLab, or Bitbucket, then push the source you received into it:

Bash
Bash
git init
git add .
git commit -m "Initial OwnDocs site"
git remote add origin git@github.com:your-org/your-docs.git
git push -u origin main

Keep that repository private. The host you connect it to authenticates as you, so it can read a private repository of your own without the source becoming public.

Everything below assumes your repository exists and holds the source.

Vercel

Vercel is Next.js's native host. In the Vercel dashboard choose Add New → Project, pick your repository, and let it import. The bundled vercel.json sets the framework to nextjs and the build command to npm run build, so there is nothing else to configure.

Add the environment variables under Project → Settings → Environment Variables before the first build, then deploy. The finished site answers on a .vercel.app URL until you attach your own domain.

Netlify

Netlify runs Next.js through the OpenNext adapter, which it installs during the build. Choose Add new site → Import an existing project, pick your repository, and Netlify reads the build command from the bundled netlify.toml.

Set the environment variables under Site configuration → Environment variables. The finished site answers on a .netlify.app URL.

Render

Render reads the bundled render.yaml, which defines the whole service, so use the Blueprint flow rather than creating a web service by hand. Choose New → Blueprint, pick your repository, and Render creates the service from that file.

The blueprint does more of the work than the other two. It pins Node.js 24, runs npm ci && npm run build, starts with npm start, and generates APP_PASSWORD, JWT_SECRET, and COOKIE_SALT for you, so you never type those three. It ships with ACCESS_MODE set to public and THEME_VARIANT set to violet; change either in the blueprint or in the dashboard before you go live. The finished site answers on an .onrender.com URL.

Environment Variables

All three platforms read the same variables. scripts/setup-env.sh generates them for local development; for a cloud deploy, set them in the platform's dashboard.

Five matter on a first deploy:

  • ACCESS_MODE: public unless you set it to private. Anything other than the exact value private keeps the site open.
  • APP_PASSWORD, JWT_SECRET, and COOKIE_SALT: required whenever the site is private. Render generates all three from its blueprint.
  • THEME_VARIANT: the color theme, defaulting to violet.

Configuration documents every variable with its exact default, including the optional footer links and the site URL used for the sitemap and OpenGraph tags.

Manual Deployment

For any Node.js hosting provider, build and start OwnDocs with:

Bash
Bash
npm install
npm run build
npm start

The production server starts on port 3000 by default. Set environment variables through your hosting provider's dashboard or a .env.local file before building.

Docker Self-Host

OwnDocs ships a Dockerfile and a docker-compose.yml so you can run it as a container on your own infrastructure. This is the recommended self-hosted path when you want a single isolated service without installing a Node toolchain on the host.

  1. Prepare environment variables

    The compose file reads secrets from .env.local. Generate them first:

    Bash
    Bash
    bash scripts/setup-env.sh
  2. Build and start the container

    Bash
    Bash
    docker compose up --build -d

    If you are on an older Docker installation, the legacy spelling works the same way:

    Bash
    Bash
    docker-compose up --build -d
  3. Open the site

    The container publishes port 3000, so the site is at http://localhost:3000.

  4. Stop the container

    Bash
    Bash
    docker compose down

The compose file maps 3000:3000, loads environment variables from .env.local, and restarts the container automatically with restart: unless-stopped. The Dockerfile builds a production image with a non-root user and runs npm start on port 3000. The image copies the docs content into the runtime, so on-demand revalidation and the MCP fetch_page tool work inside the container. It also sets FEEDBACK_DIR=/app/data/feedback, a writable directory owned by the non-root user where the daily feedback files land. The compose file maps no volume, so votes are lost on rebuild or recreate: mount a volume at /app/data/feedback to keep them. See Configuration for the full environment variable reference.

Result

Open the deployed URL. On Vercel it ends in .vercel.app, on Netlify .netlify.app, on Render .onrender.com, and on a manual or Docker host it is http://localhost:3000. You should land on the OwnDocs home page with the sidebar, the theme toggle, and working search. Two checks confirm the deploy took your configuration:

  • GET /api/health returns {"status":"pass"}.
  • With ACCESS_MODE set to private, any page redirects you to /login until you enter APP_PASSWORD.

If either check fails, the environment variables didn't reach the running process. Re-check them against Configuration.

Was this page helpful?

© 2026 DevOps. All rights reserved.