Skip to main content

Publishing

GitLab CI builds this site and syncs documentation/build to an S3 bucket. The pipeline is .gitlab-ci.yml at the repository root.

A pipeline runs when documentation/** or .gitlab-ci.yml changes:

  • Merge requests and other branches build the site only.
  • The default branch (main) builds the site, then syncs it to S3.

The deploy job uses aws s3 sync --delete. Use a bucket that contains only this site. Objects that are no longer in the build are removed.

GitLab CI/CD variables​

Set these in Settings → CI/CD → Variables. Mark secrets as masked, and mark every variable below as protected so they are only available on protected branches.

VariableRequiredPurpose
DOCS_S3_BUCKETYesDestination bucket name
AWS_DEFAULT_REGIONYesBucket region
AWS_ROLE_ARNYes, for OIDCIAM role GitLab assumes
AWS_ACCESS_KEY_IDAlternative to the roleStatic access key
AWS_SECRET_ACCESS_KEYAlternative to the roleStatic secret key
DOCS_URLRecommendedPublic site URL baked into canonical links, for example https://docs.example.com
DOCS_BASE_URLNoPath prefix. Defaults to /. Include leading and trailing slashes
CLOUDFRONT_DISTRIBUTION_IDNoWhen set, the job invalidates /* after the sync
AWS_OIDC_AUDIENCENoOIDC audience. Defaults to https://gitlab.com

Prefer AWS_ROLE_ARN. The deploy job requests an OIDC token and calls sts:AssumeRoleWithWebIdentity. Static keys are used only when AWS_ROLE_ARN is unset.

IAM role​

Create an IAM OIDC provider for https://gitlab.com if the account does not have one. Trust this project on main:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/gitlab.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"gitlab.com:aud": "https://gitlab.com"
},
"StringLike": {
"gitlab.com:sub": "project_path:zontally/zontallyirm:ref_type:branch:ref:main"
}
}
}
]
}

Allow the role to update the bucket:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::<BUCKET_NAME>"
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::<BUCKET_NAME>/*"
}
]
}

Add cloudfront:CreateInvalidation on the distribution when CLOUDFRONT_DISTRIBUTION_ID is set.

Bucket hosting​

Pages are built with trailingSlash: true, so each page is a directory containing index.html.

Either of these hosting setups works:

  • S3 static website hosting, with index document index.html and error document 404.html.
  • CloudFront in front of the bucket (origin access control), with the default root object index.html.

Set DOCS_URL to the URL readers use. The next default-branch pipeline republishes the site with that URL in the canonical links.