Post

GitLab Publishing Pipeline for Dreamhost

An easy to follow CI/CD example on how to deploy a static website to Dreamhost using GitLab

I’ve been leveraging Dreamhost to host my sites for a really long time now and they’ve never done wrong by me so I’ve no intention of moving to anything else, even though I get free hosting solutions with my current SRE gig. But, I did want to take advantage of an IAC pipeline to publish updates to my site and that’s a pretty easy process if you’re leveraging Dreamhost for hosting and is possible even with the free version of GitLab.

Prerequisites

First, you’ll need a user that can SSH into your hosting directory:

  1. Login to your Dreamhost Panel
  2. Click Websites -> Manage Websites -> “Manage” (next to your site URL) -> Content -> Login Info
  3. Make sure “Secure Shell Access” is enabled for your user (change the password if you’ve forgotten the login info or never logged in this way before)
  4. Login as the user and create an SSH key you’re going to use for your GitLab pipeline
    1
    2
    3
    4
    5
    6
    
    mkdir -p ~/.ssh
    ssh-keygen -q -t ed25519 -C "GitLab Dreamhost Pipeline" -f ~/.ssh/id_ed25519 -N ''
    cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
    chown 0600 ~/.ssh/authorized_keys
    cat ~/.ssh/id_ed25519
    cat ~/.ssh/id_ed25519.pub
    
  5. Now you’ll want to set these up as files in your GitLab pipeline so head over to your GitLab project and click Settings -> CI/CD
  6. Expand “Variables” and create the following variables of type “File” with the following contents
    • Key:ssh_key_private, Value: Results of cat ~/.ssh/id_ed25519
    • Key:ssh_key_public, Value: Results of cat ~/.ssh/id_ed25519.pub
    • Key:ssh_user, Value: Your Dreamhost SSH user you used to access the system and run those commands

The Pipeline

The pipeline itself is pretty simple. At this point you’re just trying to rsync data from your runner to your Dreamhost server. Let’s say you’re using this to push your static Jekyll website onto the server (since that’s what I’m using it for). There are a lot of ways you can make the below pipeline faster and more elegant but I tried to write this in a way that someone new to this might understand, so I’m sacrificing speed and efficiency for ease of both reading and understanding. Let’s just cover the actual pushing of the data itself, though for best practices you’d want to have other stages to your pipeline that perform checks and have this run when merging your data back into your ‘main’ branch. I’ve added echo commands into the pipleine so you’ll understand what each piece is doing but just shoot me an email or look me up on Mastodon if you have questions, I’m always happy to help folks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
---
stages:
  - deploy

variables:
  SERVER_NAME: "<replace with your server name>"
  RSYNC_USER: "${ssh_user}@${SERVER_NAME}"

deploy-site:
  stage: deploy
  image: ubuntu
  allow_failure: false
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  before_script:
    - echo "First running apt to update inside the container and then install a few essentials needed for the data..."
    - apt-get update
    - apt-get upgrade -y
    - apt-get install -y curl git-all build-essential gcc jq python3.12-venv python3.12 openssh-client rsync
    - echo "Using homebrew as an easily understandable method to install programs into user context..."
    - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    - echo >> /root/.bashrc
    - echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /root/.bashrc
    - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
    - echo "Installing gcc, NodeJS, and Ruby using Homebrew..."
    - brew install gcc ruby node
    - echo "Now we're mirroring what your SSH directory likely looks like on your server and we're copying files to where they would normally live..."
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - cp ${ssh_key_private} ~/.ssh/id_25519
    - cp ${ssh_key_public} ~/.ssh/id_25519.pub
    - echo "Disabling host key checking so we don't have to worry about popups related to trusting a new connection..."
    - echo -e "Host *\\n\\tStrictHostKeyChecking no\\n\\n" > ~/.ssh/config
    - echo "Fixing the permissions on the SSH files so your SSH Agent doesn't kvetch about it..."
    - chmod 0644 ~/.ssh/id_25519.pub
    - chmod 0400 ~/.ssh/id_25519
    - chmod 0600 ~/.ssh/config
    - echo "Lastly we're adding the keys to the SSH Agent and telling it to test the connection to your Dreamhost server" 
    - eval $(ssh-agent -s)
    - ssh-add ~/.ssh/id_25519
    - ssh-keyscan ${SERVER_NAME}
  script:
    - echo "We're in the home stretch now, just setting the paths for gems to install..."
    - export GEM_HOME="$HOME/gems"
    - export PATH="$HOME/.local/share/gem/ruby/3.4.0/bin:$PATH"
    - echo "Installing Jekyll and Bundler as we need those for the Jekyll build"
    - gem install --user-install jekyll bundler
    - echo "Some Jekyll themes also require you build your NodeJS files as well so this is needed on mine but might not be on yours..."
    - npm install
    - npm run build
    - echo "Almost there, just building the site with Jekyll..."
    - bundle install
    - jekyll build
    - echo "And last but not least, we push the contents of your _site folder to your Dreamhost server using rsync..."
    - rsync -ave ssh ./_site/ ${RSYNC_USER}:/home/${ssh_user}/${SERVER_NAME}
    - echo "We're done!"

Next Steps

This is pretty bare bones and like I said you would probably want to have other stages to this that run for your unprotected branches to test your code and make sure you’re not doing anything potentially unsafe with it. There are also tons of ways to make this faster and more efficient like using the Alpine or Jekyll images that are provided by GitLab but like I said, I wanted folks who are new to this process to understand it and Ubuntu is what a lot of folks are using when they get started in their Linux journey. I hope this helps a few folks but like I said above, if you have any questions then feel free to shoot me a message and I’m happy to answer whatever questions I can.

This post is licensed under CC BY 4.0 by the author.