DOCUMENTATION

Start a website from a template

A site on Gitt One Pages is a small git repository with your content in it. Everything else — the framework, the build, the web server — arrives as ready-made Docker images. This page walks an outside developer from an empty GitLab project to a live site, and explains what happens in between.

What a content repository is

Two template repositories on gitt.one, one for each kind of website. Each holds a Dockerfile, a three-line CI file, a docker-compose.yml, a pages.config.js and a little starter content — nothing else. No node_modules, no lock files, no build configuration: dependencies live inside the builder image.

gitt.one/pages/template-docs

Knowledge base

Markdown files become pages, folders become sections, README.md becomes the front page. Links between files are rewritten for the web, so the repository reads the same in GitLab and on the site.

  • Plain .md or .mdx, no front matter required
  • Tables, task lists, footnotes, code, Mermaid — rendered as GitLab renders them
  • Optional intranet mode behind a password
gitt.one/pages/template-www

Landing page

Pages are written as typed content tags — a hero, a list of features, steps, a contact form — so copy changes never touch the layout. Images and downloads are served straight from the repository.

  • articles/<page>/index.<locale>.mdx per page and language
  • images/ and assets/ next to the content
  • One brandColor in pages.config.js drives the whole palette

The two Dockerfiles

Each template's Dockerfile has two stages. The builder stage starts from the engine image, copies your content over the example content shipped inside it and builds the static site. The runtime stage takes the result into the engine's nginx image, which already knows how to compress, cache and answer 404 — and how to ask for a password when told to.

Knowledge base

The whole repository is the content, so the repository's own plumbing is removed before the build — otherwise the Dockerfile would become a page.

Dockerfile
FROM h.gitt.one/pages/engine-astro/builder-docs:latest AS builder

RUN rm -rf src/content/docs/* public/assets
COPY . src/content/docs/
COPY pages.config.js ./
RUN rm -rf src/content/docs/.git src/content/docs/.gitlab-ci.yml \
    src/content/docs/.gitignore src/content/docs/Dockerfile \
    src/content/docs/docker-compose.yml src/content/docs/pages.config.js
RUN pnpm run build

FROM h.gitt.one/pages/engine-astro/nginx:latest AS runner
COPY --from=builder /src/apps/docs/dist /usr/share/nginx/html

The image paths are a public contract: they do not move.

Landing page

Content, images and assets replace the examples; pages.config.js is the only configuration.

Dockerfile
FROM h.gitt.one/pages/engine-astro/builder-www:latest AS builder

RUN rm -rf src/articles/* src/images/* public/assets
COPY articles/ src/articles/
COPY images/ src/images/
COPY assets/ public/assets/
COPY pages.config.js ./
RUN pnpm run build

FROM h.gitt.one/pages/engine-astro/nginx:latest AS runner
COPY --from=builder /src/apps/www/dist /usr/share/nginx/html

Both runtime stages use the same nginx image; the landing simply never sets a password.

From template to a live site

About twenty minutes the first time, most of it waiting for DNS.

  1. 1

    Import the template

    In GitLab create a new project with 'Import project → Repository by URL' and paste https://gitt.one/pages/template-docs.git or https://gitt.one/pages/template-www.git. Forking works too; the template projects are not GitLab 'project templates', so they do not appear in the 'Create from template' tab.

  2. 2

    Let CI read the engine

    In the new project create a deploy token named gitlab-deploy-token with the read_registry scope (Settings → Repository → Deploy tokens). This is how the pipeline pulls the builder image; without it the build stops at the very first line.

  3. 3

    Tell it where to live

    Add the CI variables HOST (the domain the site answers on) and K8S_CLUSTER (the cluster you were given). Point the domain at the cluster's ingress host with a DNS-only record, so a certificate can be issued automatically.

  4. 4

    Make it yours

    Edit pages.config.js — title, siteUrl, contacts, brandColor — and replace the starter content. Commit to master, or open a merge request if you prefer review.

  5. 5

    Watch the pipeline

    Two jobs: build_container builds the image and pushes it to the project's registry, deploy_master rolls it out. The first run also obtains the TLS certificate; the site is up a minute or two later.

  6. 6

    Keep writing

    From now on every push to master rebuilds and redeploys. Edit in your IDE, in the GitLab web editor, or let an AI agent work on the repository — the pipeline does not care who made the commit.

The rest of the repository

These two files complete the picture. The CI file only includes shared pipeline templates; the configuration file is everything a site can change without touching the engine.

Pipeline

Two includes: master deploys to production, any other branch builds a preview environment.

.gitlab-ci.yml
include:
  - project: 'commons/ci'
    file: 'simpledeploy-master.yml'
  - project: 'commons/ci'
    file: 'simpledeploy-branch.yml'

docker-compose.yml names the image and the port; the pipeline builds through it.

Site configuration

A landing page's configuration, abridged. A knowledge base needs only title, siteUrl and description.

pages.config.js
export default {
  title: 'My Landing',
  siteUrl: 'https://www.example.com',
  defaultEmail: 'info@example.com',
  locales: ['en'],
  defaultLocale: 'en',
  brandColor: '#2563eb',
  navigation: [
    { name: 'Home', path: '' },
    { name: 'Contacts', path: 'contacts', cta: true },
  ],
};

brandColor is one seed colour; the full palette, including contrast-safe button shades, is derived from it at build time.

Things worth knowing

Short answers to the questions every new site raises once.

Which CI variables does a site need?

  • HOST — the domain, e.g. docs.example.com. Drives the ingress and the TLS certificate. A comma-separated list serves several domains; the first is canonical.
  • K8S_CLUSTER — the cluster the site deploys to. Leave it unset to use the shared cluster.
  • BASIC_AUTH_HTPASSWD — optional. Set it and the site asks for a password (user admin); remove it and redeploy to make the site public. The password is hashed when the container starts and never lands in the image.
  • A deploy token gitlab-deploy-token with read_registry — not a variable but a project setting; the pipeline uses it to pull the builder image.

Mark HOST and K8S_CLUSTER as protected if you want only master to reach production.

How does a commit become a deployment?

  1. You push to master.
  2. build_container runs docker compose build: the Dockerfile pulls the builder image, copies your content in and builds the static site; the result is packed into the nginx image and tagged with the commit’s short SHA.
  3. The image is pushed to your project’s container registry.
  4. deploy_master turns docker-compose.yml into Kubernetes resources — a deployment, a service, an ingress for HOST with a certificate — and applies them.
  5. Kubernetes pulls the new tag and swaps the pod.

If HOST is not set, the build still runs and the image is still pushed — that is how the templates themselves are verified — but the deploy step only starts a pod with no address (“VHOST env not specified. Skipping ingress”). Set HOST and push again; the next deploy adds the ingress and the certificate.

How do I get a newer engine?

The Dockerfile starts from builder-docs:latest or builder-www:latest, so every build picks up the current engine. But a build only happens on a new commit: re-running an old pipeline produces an image with the same tag, and a deployment whose image tag has not changed does not roll. When nothing in the content needs changing, make an empty commit:

git commit --allow-empty -m "Rebuild on the current engine"
git push

Say why in the message — it is the only record of why the site changed.

Can I run the build on my machine?

Yes. docker build -t mysite . in the repository, then docker run -p 8080:80 mysite and open http://localhost:8080. You need access to the engine’s registry (docker login h.gitt.one). Nothing else is installed locally — no Node, no package manager.

Can I leave?

Your content is plain Markdown and MDX in your own repository, and the output of a build is an ordinary nginx image that runs on any Docker host. The engine is Astro, MIT-licensed and the most widely used content framework, so any developer can take the project over.

THE QUALITY BAR

What a site from the template already has

None of this is configured in the template — it comes with the builder image, which is why the newest site is as good as the best one.

Lighthouse 100
Performance, accessibility, best practices and SEO — the acceptance target for every site, measured on production
Pre-rendered, zero JavaScript by default
Pages are static markup; a contact form is the only island, and it costs about a kilobyte
Images, compression, caching
Responsive webp at build time, pre-compressed files, immutable caching for hashed assets — served by nginx as built
SEO and markdown that match GitLab
Sitemap, robots.txt, meta tags, favicon set; one rendering engine for tables, task lists, footnotes, diagrams
Full-text search in knowledge bases
Every docs site gets a search box over all its pages, built at deploy time and running in the browser — also behind the password

Want the longer story?

How the pipeline is built, what the engine does on every push and the full quality checklist.

Read how it works

Need help setting it up?We do the first site with you.