GitLab Pages

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

With GitLab Pages, you can publish static websites directly from a repository in GitLab.

  • Use for any personal or business website.
  • Use any Static Site Generator (SSG) or plain HTML.
  • Create websites for your projects, groups, or user account.
  • Host your site on your own GitLab instance or on GitLab.com for free.
  • Connect your custom domains and TLS certificates.
  • Attribute any license to your content.
Examples of SSGs supported by Pages

To publish a website with Pages, you can use any static site generator, like Gatsby, Jekyll, Hugo, Middleman, Harp, Hexo, or Brunch. You can also publish any website written directly in plain HTML, CSS, and JavaScript.

Pages does not support dynamic server-side processing, for instance, as .php and .asp requires. For more information, see Static vs dynamic websites.

Getting started

To create a GitLab Pages website:

Document Description
Use the GitLab UI to create a simple .gitlab-ci.yml Add a Pages site to an existing project. Use the UI to set up a simple .gitlab-ci.yml.
Create a .gitlab-ci.yml file from scratch Add a Pages site to an existing project. Learn how to create and configure your own CI file.
Use a .gitlab-ci.yml template Add a Pages site to an existing project. Use a pre-populated CI template file.
Fork a sample project Create a new project with Pages already configured by forking a sample project.
Use a project template Create a new project with Pages already configured by using a template.

To update a GitLab Pages website:

Document Description
GitLab Pages domain names, URLs, and base URLs Learn about GitLab Pages default domains.
Explore GitLab Pages Requirements, technical aspects, specific GitLab CI/CD configuration options, Access Control, custom 404 pages, limitations, and FAQ.
Custom domains and SSL/TLS Certificates Custom domains and subdomains, DNS records, and SSL/TLS certificates.
Let’s Encrypt integration Secure your Pages sites with Let’s Encrypt certificates, which are automatically obtained and renewed by GitLab.
Redirects Set up HTTP redirects to forward one page to another.

For more information, see:

Document Description
Static vs dynamic websites Static versus dynamic site overview.
Modern static site generators SSG overview.
Build any SSG site with GitLab Pages Use SSGs for GitLab Pages.

How it works

To use GitLab Pages, you must create a project in GitLab to upload your website’s files to. These projects can be either public, internal, or private.

GitLab always deploys your website from a specific folder called public in your repository. When you create a new project in GitLab, a repository becomes available automatically.

To deploy your site, GitLab uses its built-in tool called GitLab CI/CD to build your site and publish it to the GitLab Pages server. The sequence of scripts that GitLab CI/CD runs to accomplish this task is created from a file named .gitlab-ci.yml, which you can create and modify. A user-defined job with pages: true property in the configuration file makes GitLab aware that you’re deploying a GitLab Pages website.

You can either use the GitLab default domain for GitLab Pages websites, *.gitlab.io, or your own domain (example.com). In that case, you must be an administrator in your domain’s registrar (or control panel) to set it up with Pages.

The following diagrams show the workflows you might follow to get started with Pages.

New projects for GitLab Pages

Access to your Pages site

If you’re using GitLab Pages default domain (.gitlab.io), your website is automatically secure and available under HTTPS. If you’re using your own custom domain, you can optionally secure it with SSL/TLS certificates.

If you’re using GitLab.com, your website is publicly available to the internet. To restrict access to your website, enable GitLab Pages Access Control.

If you’re using a self-managed instance, your websites are published on your own server, according to the Pages settings chosen by your sysadmin, who can make them public or internal.

Pages examples

These GitLab Pages website examples can teach you advanced techniques to use and adapt for your own needs:

Administer GitLab Pages for self-managed instances

If you are running a self-managed instance of GitLab, follow the administration steps to configure Pages.

Watch a video tutorial about how to get started with GitLab Pages administration.

Configure GitLab Pages in a Helm Chart (Kubernetes) instance

To configure GitLab Pages on instances deployed with Helm chart (Kubernetes), use either:

Security for GitLab Pages

Namespaces that contain .

If your username is example, your GitLab Pages website is located at example.gitlab.io. GitLab allows usernames to contain a ., so a user named bar.example could create a GitLab Pages website bar.example.gitlab.io that effectively is a subdomain of your example.gitlab.io website. Be careful if you use JavaScript to set cookies for your website. The safe way to manually set cookies with JavaScript is to not specify the domain at all:

// Safe: This cookie is only visible to example.gitlab.io
document.cookie = "key=value";

// Unsafe: This cookie is visible to example.gitlab.io and its subdomains,
// regardless of the presence of the leading dot.
document.cookie = "key=value;domain=.example.gitlab.io";
document.cookie = "key=value;domain=example.gitlab.io";

This issue doesn’t affect users with a custom domain, or users who don’t set any cookies manually with JavaScript.

Shared cookies

By default, every project in a group shares the same domain, for example, group.gitlab.io. This means that cookies are also shared for all projects in a group.

To ensure each project uses different cookies, enable the Pages unique domains feature for your project.

Unique domains

History

By default, every new project uses pages unique domain. This is to avoid projects on the same group to share cookies.

The project maintainer can disable this feature on:

  1. On the left sidebar, select Search or go to and find your project.
  2. Select Deploy > Pages.
  3. Clear the Use unique domain checkbox.
  4. Select Save changes.

For example URLs, see GitLab Pages default domain names.

Expiring deployments

Tier: Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated
History

You can configure your Pages deployments to be automatically deleted after a period of time has passed by specifying a duration at pages.expire_in:

deploy-pages:
  stage: deploy
  script:
    - ...
  pages:  # specifies that this is a Pages job
    expire_in: 1 week
  artifacts:
    paths:
      - public

By default, parallel deployments expire automatically after 24 hours. To disable this behavior, set pages.expire_in to never.

Expired deployments are stopped by a cron job that runs every 10 minutes. Stopped deployments are subsequently deleted by another cron job that also runs every 10 minutes. To recover it, follow the steps described in Recover a stopped deployment.

A stopped or deleted deployment is no longer available on the web. Users see a 404 Not found error page at its URL, until another deployment is created with the same URL configuration.

The previous YAML example uses user-defined job names.

Recover a stopped deployment

Prerequisites:

  • You must have at least the Maintainer role for the project.

To recover a stopped deployment that has not yet been deleted:

  1. On the left sidebar, select Search or go to and find your project.
  2. Select Deploy > Pages.
  3. Near Deployments turn on the Include stopped deployments toggle. If your deployment has not been deleted yet, it should be included in the list.
  4. Expand the deployment you want to recover and select Restore.

Parallel deployments

Tier: Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated Status: Beta
History
The availability of this feature is controlled by a feature flag. For more information, see the history. This feature is available for testing, but not ready for production use.

Use the pages.path_prefix CI/CD option to configure a prefix for the GitLab Pages URL. A prefix allows you to differentiate between multiple GitLab Pages deployments:

  • Main deployment: a Pages deployment created with a blank path_prefix.
  • Parallel deployment: a Pages deployment created with a non-blank path_prefix

The value of pages.path_prefix is:

  • Converted to lowercase.
  • Shortened to 63 bytes.
  • Any character except numbers (0-9), letters (a-z) and periods (.) is replaced with a hyphen (-).
  • Leading and trailing hyphens (-) and period (.) are removed.

Example configuration

Consider a project such as https://gitlab.example.com/namespace/project. By default, its main Pages deployment can be accessed through:

  • When using a unique domain: https://project-namespace-123456.gitlab.io/.
  • When not using a unique domain: https://namespace.gitlab.io/project.

If a pages.path_prefix is configured to the project branch names, like path_prefix = $CI_COMMIT_BRANCH, and there’s a branch named username/testing_feature, this parallel Pages deployment would be accessible through:

  • When using a unique domain: https://project-namespace-123456.gitlab.io/username-testing-feature.
  • When not using a unique domain: https://namespace.gitlab.io/project/username-testing-feature.

Limits

The number of parallel deployments is limited by the root-level namespace. For specific limits for:

To immediately reduce the number of active deployments in your namespace, delete some deployments. For more information, see Delete a deployment.

To configure an expiry time to automatically delete older deployments, see Expiring deployments.

Expiration

By default, parallel deployments expire after 24 hours, after which they are deleted. If you’re using a self-hosted instance, your instance admin can configure a different default duration.

To customize the expiry time, configure pages.expire_in.

To prevent deployments from automatically expiring, set pages.expire_in to never.

Path clash

pages.path_prefix can take dynamic values from CI/CD variables that can create pages deployments which could clash with existing paths in your site. For example, given an existing GitLab Pages site with the following paths:

/index.html
/documents/index.html

If a pages.path_prefix is documents, that version will override the existing path. In other words, https://namespace.gitlab.io/project/documents/index.html will point to the /index.html on the documents deployment of the site, instead of documents/index.html of the main deployment of the site.

Mixing CI/CD variables with other strings can reduce the path clash possibility. For example:

deploy-pages:
  stage: deploy
  script:
    - echo "Pages accessible through ${CI_PAGES_URL}/${PAGES_PREFIX}"
  variables:
    PAGES_PREFIX: "" # No prefix by default (master)
  pages:  # specifies that this is a Pages job
    path_prefix: "$PAGES_PREFIX"
  artifacts:
    paths:
    - public
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run on default branch (with default PAGES_PREFIX)
    - if: $CI_COMMIT_BRANCH == "staging" # Run on master (with default PAGES_PREFIX)
      variables:
        PAGES_PREFIX: '_stg' # Prefix with _stg for the staging branch
    - if: $CI_PIPELINE_SOURCE == "merge_request_event" # Conditionally change the prefix for Merge Requests
      when: manual # Run pages manually on Merge Requests
      variables:
        PAGES_PREFIX: 'mr-$CI_MERGE_REQUEST_IID' # Prefix with the mr-<iid>, like `mr-123`

Some other examples of mixing variables with strings for dynamic prefixes:

  • pages.path_prefix: 'mr-$CI_COMMIT_REF_SLUG': Branch or tag name prefixed with mr-, like mr-branch-name.
  • pages.path_prefix: '_${CI_MERGE_REQUEST_IID}_': Merge request number prefixed ans suffixed with _, like _123_.

The previous YAML example uses user-defined job names.

Use parallel deployments to create Pages environments

You can use parallel GitLab Pages deployments to create a new environment. For example:

deploy-pages:
  stage: deploy
  script:
    - echo "Pages accessible through ${CI_PAGES_URL}/${PAGES_PREFIX}"
  variables:
    PAGES_PREFIX: "" # no prefix by default (master)
  pages:  # specifies that this is a Pages job
    path_prefix: "$PAGES_PREFIX"
  environment:
    name: "Pages ${PAGES_PREFIX}"
    url: "${CI_PAGES_URL}/${PAGES_PREFIX}"
  artifacts:
    paths:
    - public
  rules:
    - if: $CI_COMMIT_BRANCH == "staging" # ensure to run on master (with default PAGES_PREFIX)
      variables:
        PAGES_PREFIX: '_stg' # prefix with _stg for the staging branch
    - if: $CI_PIPELINE_SOURCE == "merge_request_event" # conditionally change the prefix on Merge Requests
      when: manual # run pages manually on Merge Requests
      variables:
        PAGES_PREFIX: 'mr-$CI_MERGE_REQUEST_IID' # prefix with the mr-<iid>, like `mr-123`

With this configuration, users will have the access to each GitLab Pages deployment through the UI. When using environments for pages, all pages environments are listed on the project environment list.

You can also group similar environments together.

The previous YAML example uses user-defined job names.

Delete a Deployment

To delete a deployment:

  1. On the left sidebar, select Search or go to and find your project.
  2. Select Deploy > Pages.
  3. Under Deployments, select any area on the deployment you wish to delete. The deployment details expand.
  4. Select Delete.

When you select Delete, your deployment is stopped immediately. Stopped deployments are deleted by a cron job running every 10 minutes.

To restore a stopped deployment that has not been deleted yet, see Recover a stopped deployment.

Auto-clean

Parallel Pages deployments, created by a merge request with a path_prefix, are automatically deleted when the merge request is closed or merged.

User-defined job names

History
  • Introduced in GitLab 17.5 with a flag customizable_pages_job_name, disabled by default.
  • Generally available in GitLab 17.6. Feature flag customizable_pages_job_name removed.

To trigger a Pages deployment from any job, include the pages property in the job definition. It can either be a Boolean set to true or a hash.

For example, using true:

deploy-my-pages-site:
  stage: deploy
  script:
    - npm run build
  pages: true  # specifies that this is a Pages job
  artifacts:
    paths:
      - public

For example, using a hash:

deploy-pages-review-app:
  stage: deploy
  script:
    - npm run build
  pages:  # specifies that this is a Pages job
    path_prefix: '/_staging'
  artifacts:
    paths:
    - public

If the pages property of a job named pages is set to false, no deployment is triggered:

pages:
  pages: false