Set up self-hosted documentation

View as Markdown
Enterprise feature

This feature is available only for the Enterprise plan. To get started, reach out to support@buildwithfern.com.

Prerequisites

Before setting up self-hosted documentation, ensure you have:

  • Docker installed on your system
  • Access to your Fern project’s fern/ directory
  • A Docker Hub account (for accessing the private image)

Setup instructions

1

Request Access to the Docker Image

The self-hosted documentation runs on a private Docker image: fernapi/fern-self-hosted

Contact Fern Support and provide your Docker Hub username to the Fern team. Fern will allowlist your account to download the private image, and provide you with the latest tag.

2

Download the Docker Image

Once your account is allowlisted, download the latest image:

$docker pull fernapi/fern-self-hosted:<latest-tag>

Do not use fernapi/fern-self-hosted:latest as it may not contain the most recent version. Always use the specific latest tag provided by Fern.

You can verify the image is available in your Docker daemon:

$docker images | grep fernapi/fern-self-hosted
3

Create a Dockerfile

In the directory containing your fern/ folder, create a new Dockerfile with the following content:

<your-docker-file-name>
1FROM fernapi/fern-self-hosted:<latest-tag>
2
3COPY fern/ /fern/
4
5RUN fern-generate

Replace <latest-tag> with the actual tag used in the previous step.

fern-generate processes your documentation at build time, enabling faster container startup, air-gapped deployment, and a smaller attack surface. You can alternatively defer generation to runtime.

4

Build Your Custom Docker Image

Build your custom Docker image using the Dockerfile:

$docker build -f <your-docker-file-name> -t <your-image-name> <path-to-dockerfile>

Example:

$docker build -f Dockerfile -t self-hosted-docs .
5

Run the Documentation

Start your self-hosted documentation:

$docker run -p <port-number>:3000 <your-image-name>

The documentation will be available at localhost:<port-number>.

6

Configure Custom Domain

Your documentation will be published to the domain specified in your docs.yml file. For example:

1instances:
2 - url: example-org.docs.buildwithfern.com
3 custom-domain: docs.plantstore.dev
7

Deploy the Documentation

You can now deploy the image to your own infrastructure, allowing you to host the documentation on your own domain.

Additional configuration

The following sections cover optional configurations for specific deployment scenarios.

Runtime generation

By default, fern-generate runs at Docker build time. Defer generation to runtime if you need to:

  • Pass configuration (environment variables, secrets) at runtime
  • Speed up Docker builds during development
  • Share a single image across multiple documentation configurations

Use the --only-deps flag to defer generation to runtime:

1FROM fernapi/fern-self-hosted:<latest-tag>
2
3COPY fern/ /fern/
4
5RUN fern-generate --only-deps

This starts required services (PostgreSQL, MinIO, FDR) at build time but skips documentation generation. When the container starts, it automatically runs fern generate --docs.

Runtime generation requires network access at container startup. For air-gapped deployments, use the default build-time generation.

Air-gapped deployments with gRPC

If your API uses gRPC with dependencies from the Buf Schema Registry (BSR), the buf CLI fetches modules from buf.build during generation. This fails in air-gapped environments without network access.

1

Check for BSR dependencies

Check if your project has BSR dependencies in either location:

In buf.yaml:

1version: v2
2deps:
3 - buf.build/googleapis/googleapis
4 - buf.build/grpc-ecosystem/grpc-gateway

In generators.yml:

1api:
2 specs:
3 - proto:
4 root: ./protos/
5 dependencies:
6 - buf.build/googleapis/googleapis

If there’s no deps or dependencies section (or only local paths), you can skip the rest of this section.

2

Choose a solution

Use this option when you don’t have all the information at build time and need the docs to generate differently at runtime, such as injecting environment variables at runtime.

To generate at runtime in an air-gapped environment, vendor buf dependencies locally:

1FROM fernapi/fern-self-hosted:<latest-tag>
2
3# Install buf CLI for dependency caching
4RUN npm install -g @bufbuild/buf
5
6# Copy fern configuration
7COPY fern/ fern/
8COPY protos/ protos/
9
10# Pre-fetch buf dependencies at build time (caches googleapis, protovalidate)
11RUN cd protos && buf dep update
12
13# Build fern dependencies
14RUN fern-generate --only-deps

Update buf.yaml to reference vendored dependencies:

1# Before
2deps:
3 - buf.build/googleapis/googleapis
4
5# After
6deps:
7 - ./vendor/googleapis

If you don’t have a buf.yaml file, you can specify proto dependencies directly in your generators.yml. The self-hosted container automatically creates a temporary buf.yaml from these dependencies during the build process.

generators.yml
1api:
2 specs:
3 - proto:
4 root: ./protos/
5 dependencies:
6 - buf.build/googleapis/googleapis
7 - buf.build/bufbuild/protovalidate

This approach works with both build-time and runtime generation:

1FROM fernapi/fern-self-hosted:<latest-tag>
2
3COPY fern/ /fern/
4
5# For build-time generation (recommended for air-gapped deployments)
6RUN fern-generate
7
8# Or for runtime generation (requires network at startup)
9# RUN fern-generate --only-deps

The container parses all generators.yml files in your fern directory, finds proto specs with dependencies but no buf.yaml, and creates the necessary configuration automatically.