34

I'm using Hosted Gitlab to host my Git repositories, and more recently I've been using it to build/deploy PHP and Java applications to servers.

What I'd like to do is once a build is complete, deploy the application using SSH. Sometimes this might just be uploading the contents of the final build (PHP files) to a server via SSH, or other times it may be uploading a compiled .jar file and then executing a command on the remote server to restart a service.

I've set up my own Docker container as a build environment, this includes things such as Java, PHP, Composer, and Maven all that I need for builds to complete. I'm using this image to run builds.

What I'd like to know is, how can I SSH into an external server in order to perform deployment commands that I can specify in my gitlab-ci.yaml file?

Tyler Rick
  • 9,191
  • 6
  • 60
  • 60
SheppardDigital
  • 3,165
  • 8
  • 44
  • 74

6 Answers6

42

You can store your SSH key as a secret variable within gitlab-ci.yaml and use it during your build to execute SSH commands, for more details please see our documentation here.

Once you have SSH access you can then use commands such as rsync and scp to copy files onto your server. I found an example of this in another post here which you can use as a reference.

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Adam Mulvany
  • 444
  • 5
  • 2
  • 3
    Could you summarize a little the post here in case the page goes down? – tutuca Mar 23 '18 at 22:05
  • 1
    @Adam-Mulvany, With all due respect, the first link does an extremely poor job of documenting in plain English WHY and HOW. And it doesn't work for me-I get and exit status of 1 with no explanation. I don't think people should be asked to develop an additional area of expertise just to get GitLab CI/CD to do something simple. If we already have a shared ssh key to push things up from the server to Gitlab, why do we need to do all this just to get Gitlab to send commands for our server to run? Much deployment code is basic copying and locking down of files. Thank you. –  Aug 01 '19 at 16:37
11

Just as an example, lets suppose you have a server with requirements already installed and you want to deploy to that server using ssh.

image: ubuntu:latest
stages:
  - deploy
deploy_QA:
  stage: deploy
  environment: 
    name: Staging
    url: "$QA_URL"
  before_script:
  - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
  - mkdir -p ~/.ssh
  - eval $(ssh-agent -s)
  - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
  script:
    - ssh-add <(echo "$PRIVATE_KEY")
    - ssh -o StrictHostKeyChecking=no user@"$QA_SERVER" 'rm -rf /var/www/html/*'
    - scp -P22 -r . ubuntu@"$QA_SERVER":/var/www/html

First, in this example we are using ubuntu image. Also notice that we are using some gitlab secret variables. $QA_URL, $PRIVATE_KEY, $DB_CONNECTION, $QA_SERVER. The important ones are $PRIVATE_KEY and QA_SERVER. Private key is the one you need to authenticate with the QA_SERVER (if you are using private key). And obviously QA_SERVER is the address that you want to deploy your code.

For creating new variable access gitlab->settings->CI/CD.



Within before_script what we are doing is creating and adding ssh key, also we are disabling command line to ask for password. 'StrictHostKeyChecking no'

ssh-add <(echo "$PRIVATE_KEY")

Add ssh key to the agent.

ssh -o StrictHostKeyChecking=no user@"$QA_SERVER" 'rm -rf /var/www/html/*'

Not required: this line uses ssh for deleting any file within /var/www/html scp -P22 -r . ubuntu@"$QA_SERVER":/var/www/html Finally, files are copied from current directory to /var/www/html

Be careful with permissions, it depends of the directory you want to copy.

Johan Durán
  • 153
  • 2
  • 8
  • 2
    Johan its not clear where PRIVATE_KEY is generated and where is corresponding PUBLIC KEY is stored? My guess is that admin logs into QA_SERVER and generates key pairs copy paste private key into PRIVATE_KEY variable on gitlab. – ace Sep 06 '18 at 12:12
  • 1
    @ace That's correct, first we must follow the normal ssh keys generation, place public on the server the copy the private into gitlab variable. In this video of my tutorial I talk about CI using just shh [Gitlab CI/CD Tutorial, Pain SSH](https://www.youtube.com/watch?v=Mj-RdXlNE9E) (For this question after minute 7). Regarding Gitlab because SSH keys generation is as usual. – Johan Durán Sep 09 '18 at 23:01
5

Dealing with ssh on gitlab.com is not straightforward.

That's why i've written a SSH helper for .gitlab-ci.yml.
You can check it out here https://gitlab.com/gitlab-cd/ssh-template

Just include: it to your .gitlab-ci.yml and then you can go with:

ssh_run root myhostname $MYHOST_PKEY "touch foo; cp foo bar; ls -al; rm foo bar; ls -al"

Xavier D
  • 3,364
  • 1
  • 9
  • 16
1

Use mirrors. Under Settings -> Repository -> Mirroring Repositories.

It generates an ssh pubkey you should place on your server.

You can select direction (pull or push), and which branches get pulled or pushed. Also waits for pipelines.

Works fantastic.

Pedro Rodrigues
  • 2,520
  • 2
  • 27
  • 26
  • 1
    This is awesome, thank you for this. Another advantage is that it doesn’t use any minute on Gitlab pipelines. – bfontaine Dec 20 '21 at 15:56
0

I have a Deploy using SSH example, i hope that helps.

First of all, you need to configure the SSH keys on the server, generate a key (https://www.cyberciti.biz/faq/how-to-set-up-ssh-keys-on-linux-unix/) and paste the public key in the ".ssh/authorized_keys" file in the user's home.

Still on the server, edit the file "/etc/ssh/sshd_config".

find it:

AcceptEnv LANG LC_*

replace to:

AcceptEnv LANG LC_* CI_*

This will make the Git-Lab variables used by the server

After that, I recommend that you store the public key and server address in GitLab CI variables (https://docs.gitlab.com/ee/ci/variables/#protected-cicd-variables)

After declaring the variables, just base yourself on this gitlab-ci.yml below:

Deploy:
  stage: Deploy
  image: dwdraju/ssh-client-alpine
  before_script:
    - mkdir -p ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n      SendEnv CI_*  \n" > ~/.ssh/config
    - echo -n  $SSH_PRIVATE_KEY  > ~/.ssh/id_rsa
    - chmod 700 ~/.ssh
    - chmod 600 ~/.ssh/id_rsa
  script: 
    - ssh $SSH_HOST 'echo $CI_PROJECT_NAME'
0

Another important thing is to mask corresponding GitLab variable containing SSH private key.

For some reason, GitLab doesn't allow us to do this straightforwardly. After pasting the key, the option to mask it just becomes impossible.

There's an open issue in GitLab regarding this: https://gitlab.com/gitlab-org/gitlab/-/issues/220187

Possible workaround: Gitlab masking variables

Just encode SSH private key using base64 -w0 option, and add encoded SSH key to the GitLab variable value. After that you could use SSH private key to connect to the remote servers like this, and the key is not exposed (this is not true).

echo "${ENCODED_PRIVATE_KEY}" | base64 -d | ssh-add - > /dev/null

UPD. Unfortunately GitLab doesn't mask decoded masked variable. Please consider this when using SSH keys.

ololoid
  • 63
  • 5