# GitLab Pages Reference ## Overview GitLab Pages allows you to host static websites directly from your GitLab repository. Perfect for documentation, portfolios, blogs, and landing pages. ## Pages URL Format **GitLab.com**: ``` https://username.gitlab.io/project-name ``` **Custom domain**: ``` https://www.example.com ``` **Group pages**: ``` https://groupname.gitlab.io ``` ## Creating a Pages Site ### Basic Setup **.gitlab-ci.yml**: ```yaml pages: stage: deploy script: - mkdir .public - cp -r * .public - mv .public public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` **Requirements**: 1. Job must be named `pages` 2. Must create `public/` directory 3. Must have artifact with `public/` path 4. Runs on default branch (usually main) ### Static HTML **index.html**: ```html My GitLab Page

Welcome!

This is hosted on GitLab Pages

``` **.gitlab-ci.yml**: ```yaml pages: stage: deploy script: - mkdir public - cp index.html public/ artifacts: paths: - public only: - main ``` ## Static Site Generators ### Hugo ```yaml image: registry.gitlab.com/pages/hugo:latest variables: GIT_SUBMODULE_STRATEGY: recursive pages: script: - hugo artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### Jekyll ```yaml image: ruby:2.7 before_script: - bundle install pages: script: - bundle exec jekyll build -d public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### Gatsby ```yaml image: node:18 cache: paths: - node_modules/ - .cache/ pages: script: - npm install - npm run build - mv public public-gatsby - mv public-gatsby public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### Next.js ```yaml image: node:18 cache: paths: - node_modules/ - .next/cache/ pages: script: - npm install - npm run build - npm run export - mv out public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### VuePress ```yaml image: node:18 pages: script: - npm install - npm run docs:build - mv docs/.vuepress/dist public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### MkDocs ```yaml image: python:3.11 pages: script: - pip install mkdocs mkdocs-material - mkdocs build - mv site public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### Docusaurus ```yaml image: node:18 pages: script: - npm install - npm run build - mv build public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ### Hexo ```yaml image: node:18 pages: script: - npm install hexo-cli -g - npm install - hexo generate - mv public public-hexo - mv public-hexo public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ## Custom Domain Setup ### Add Custom Domain **Via UI**: 1. Settings > Pages 2. New Domain 3. Enter domain name 4. Save **Via API**: ```bash curl --request POST --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages/domains" \ --data "domain=www.example.com" ``` ### DNS Configuration **For root domain (example.com)**: ``` Type: A Name: @ Value: 35.185.44.232 ``` **For subdomain (www.example.com)**: ``` Type: CNAME Name: www Value: username.gitlab.io ``` **Verify DNS**: ```bash dig www.example.com nslookup www.example.com ``` ### SSL/TLS Certificate **Automatic Let's Encrypt**: 1. Add custom domain 2. Configure DNS 3. Enable "Automatic certificate management using Let's Encrypt" **Manual certificate**: ```bash curl --request PUT --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages/domains/www.example.com" \ --form "certificate=@/path/to/cert.pem" \ --form "key=@/path/to/key.pem" ``` ## Access Control ### Private Pages Require authentication to access pages (Premium/Ultimate): **Enable private pages**: ```bash curl --request PUT --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id" \ --data "pages_access_level=private" ``` **Access levels**: - `public` - Anyone can access - `private` - Only project members - `enabled` - Controlled by project visibility - `disabled` - Pages disabled ### Authentication When pages are private: - Users must log in to GitLab - Project members can access - Access controlled by member permissions ## Preview Environments Create preview for merge requests: ```yaml pages: stage: deploy script: - npm run build - mv dist public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH pages:preview: stage: deploy script: - npm run build - mv dist public artifacts: paths: - public environment: name: review/$CI_COMMIT_REF_NAME url: https://$CI_PROJECT_ROOT_NAMESPACE.gitlab.io/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/public/index.html rules: - if: $CI_MERGE_REQUEST_ID ``` ## Advanced Configuration ### Custom 404 Page Create `public/404.html`: ```html Page Not Found

404 - Page Not Found

The page you're looking for doesn't exist.

Go Home ``` ### Redirects Create `public/_redirects`: ``` # Redirect /old-page to /new-page /old-page /new-page 301 # Redirect with wildcards /blog/* /news/:splat 301 # Conditional redirects /api/* https://api.example.com/:splat 200 # Country-based redirects / /us 302 Country=us / /uk 302 Country=uk ``` ### Headers Create `public/_headers`: ``` # Security headers /* X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Referrer-Policy: no-referrer-when-downgrade # Cache control /static/* Cache-Control: public, max-age=31536000, immutable # CORS /api/* Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, OPTIONS ``` ### Base URL Configuration For subdirectory deployment: **Hugo**: ```toml # config.toml baseURL = "https://username.gitlab.io/project-name/" ``` **Jekyll**: ```yaml # _config.yml baseurl: "/project-name" url: "https://username.gitlab.io" ``` **VuePress**: ```js // .vuepress/config.js module.exports = { base: '/project-name/', } ``` ## Optimization ### Image Optimization ```yaml pages: before_script: - npm install -g sharp-cli script: - | find public -name '*.jpg' -o -name '*.png' | while read img; do sharp -i "$img" -o "$img" resize 1920 done ``` ### Minification ```yaml pages: script: - npm run build - npm install -g html-minifier clean-css-cli uglify-js - | find public -name '*.html' -exec html-minifier --collapse-whitespace --remove-comments --minify-css --minify-js {} -o {} \; find public -name '*.css' -exec cleancss -o {} {} \; find public -name '*.js' -exec uglifyjs {} -c -m -o {} \; ``` ### Compression ```yaml pages: script: - npm run build - mv dist public - find public -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\|svg\|json\)$' -exec gzip -f -k {} \; - find public -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\|svg\|json\)$' -exec brotli -f -k {} \; ``` ## CI/CD Examples ### Multi-Branch Deployment ```yaml pages: stage: deploy script: - npm run build - mv dist public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == "main" pages:staging: stage: deploy script: - npm run build - mv dist public artifacts: paths: - public environment: name: staging url: https://staging.example.com rules: - if: $CI_COMMIT_BRANCH == "staging" ``` ### Conditional Deployment ```yaml pages: stage: deploy script: - | if [ "$CI_COMMIT_BRANCH" == "main" ]; then export NODE_ENV=production else export NODE_ENV=development fi - npm run build - mv dist public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH ``` ### Scheduled Rebuild ```yaml pages: script: - npm run build - mv dist public artifacts: paths: - public rules: - if: $CI_COMMIT_BRANCH == "main" - if: $CI_PIPELINE_SOURCE == "schedule" ``` ## Monitoring ### Analytics Add Google Analytics: ```html ``` ### Status Checks ```yaml test:pages: stage: test script: - npm run build - npm run test - | # Check for broken links npm install -g broken-link-checker blc http://localhost:8000 -ro ``` ## Troubleshooting ### Pages Not Updating 1. Check pipeline succeeded 2. Verify `pages` job ran 3. Check artifacts were created 4. Clear browser cache 5. Wait for CDN propagation (up to 30 minutes) ### 404 Errors 1. Verify file exists in `public/` directory 2. Check file paths (case-sensitive) 3. Verify artifact includes files 4. Check baseURL configuration ### Custom Domain Issues 1. Verify DNS configuration: `dig www.example.com` 2. Check SSL certificate status 3. Ensure domain verified in GitLab 4. Check domain registrar settings 5. Wait for DNS propagation (up to 48 hours) ### Build Failures ```yaml pages: script: - set -e # Exit on error - npm install - npm run build || (echo "Build failed" && exit 1) - mv dist public artifacts: paths: - public when: on_success ``` ## Best Practices ### 1. Performance - Optimize images - Minify CSS/JS - Enable compression - Use CDN - Implement caching ### 2. Security - Use HTTPS (automatic with Let's Encrypt) - Set security headers - Validate user input (if using forms) - Keep dependencies updated ### 3. SEO ```html ``` ### 4. Accessibility - Use semantic HTML - Add alt text to images - Ensure keyboard navigation - Maintain color contrast - Test with screen readers ### 5. Version Control ```yaml pages: script: - echo "Build $CI_COMMIT_SHA on $(date)" > public/version.txt - npm run build ``` ## API Reference ### Get Pages ```bash curl --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages" ``` ### Delete Pages ```bash curl --request DELETE --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages" ``` ### List Domains ```bash curl --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages/domains" ``` ### Add Domain ```bash curl --request POST --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages/domains" \ --data "domain=www.example.com" \ --data "auto_ssl_enabled=true" ``` ### Update Domain ```bash curl --request PUT --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages/domains/www.example.com" \ --data "auto_ssl_enabled=true" ``` ### Delete Domain ```bash curl --request DELETE --header "PRIVATE-TOKEN: " \ "https://gitlab.com/api/v4/projects/:id/pages/domains/www.example.com" ``` ## Examples Repository GitLab provides example pages projects: - https://gitlab.com/pages - Hugo: https://gitlab.com/pages/hugo - Jekyll: https://gitlab.com/pages/jekyll - Gatsby: https://gitlab.com/pages/gatsby - Next.js: https://gitlab.com/pages/nextjs ## Additional Resources - Pages Documentation: https://docs.gitlab.com/ee/user/project/pages/ - Pages Examples: https://gitlab.com/pages - Custom Domains: https://docs.gitlab.com/ee/user/project/pages/custom_domains_ssl_tls_certification/ - Let's Encrypt: https://letsencrypt.org/