{"id":1933,"date":"2025-02-14T01:45:01","date_gmt":"2025-02-13T23:45:01","guid":{"rendered":"https:\/\/upcloud.com\/global\/us\/resources\/tutorials\/github-actions-deploy-upcloud-servers\/"},"modified":"2025-02-14T01:45:01","modified_gmt":"2025-02-13T23:45:01","slug":"github-actions-deploy-upcloud-servers","status":"publish","type":"tutorial","link":"https:\/\/upcloud.com\/global\/resources\/tutorials\/github-actions-deploy-upcloud-servers\/","title":{"rendered":"How to use GitHub Actions to deploy onto UpCloud Cloud Servers"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">GitHub Actions provide a powerful and flexible way to automate your software workflows directly from your GitHub repository. With UpCloud&#8217;s robust and scalable cloud infrastructure, you can create a seamless deployment pipeline that enhances your development process.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Key benefits include:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8211;   Automated deployments triggered by code push or pull requests<\/li>\n\n\n\n<li>&#8211;   Increased reliability and consistency in your deployment process<\/li>\n\n\n\n<li>&#8211;   Easy integration with your existing GitHub workflow<\/li>\n\n\n\n<li>&#8211;   Scalable infrastructure provided by UpCloud to handle your growing needs<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial will guide you through creating a GitHub Actions workflow to deploy a basic text file to an UpCloud server using SSH.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>1.   An active GitHub account with the ability to create repositories.<\/li>\n\n\n\n<li>2.   An UpCloud account with at least one deployed Linux server.<\/li>\n\n\n\n<li>3.   Basic understanding of YAML syntax, GitHub Actions concepts, and SSH.<\/li>\n\n\n\n<li>4.   Familiarity with using terminal\/command line interfaces and basic Linux commands.<\/li>\n\n\n\n<li>5.   Understanding of basic security practices for handling SSH keys and sensitive information.<\/li>\n\n\n\n<li>6.   (Optional) Familiarity with CI\/CD principles and cloud computing concepts.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Set Up Your UpCloud Server and SSH Keys<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">1. If you haven&#8217;t already, <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/deploy-server\">deploy a new UpCloud server<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/1-upcloud-example-cloud-server-1024x110.png\" alt=\"-\" class=\"wp-image-47423\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">2. Use <a href=\"https:\/\/upcloud.com\/global\/docs\/guides\/connecting-to-your-server\">SSH<\/a> to connect to your UpCloud server. The default Linux username is <strong>root<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ssh root@209.94.62.211<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">3. Within the new server, we need to create a new key pair to allow the GitHub Actions workflow to connect to the UpCloud server.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Generate a new SSH key pair on the server. You may accept the defaults for the following prompt.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ssh-keygen -t rsa -b 4096 -C \"your_email@example.com\"<\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Options<\/strong><\/td><td><\/td><\/tr><tr><td>-t<\/td><td>Specifies the type of key to create.&nbsp;<\/td><\/tr><tr><td>-b<\/td><td>Specifies the number of bits in the key to create.<\/td><\/tr><tr><td>-C<\/td><td>Provides a new comment.&nbsp;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">4. Add the newly generated public key to the <strong>authorized_keys<\/strong> file on your server:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cat ~\/.ssh\/id_rsa.pub &gt;&gt; ~\/.ssh\/authorized_keys<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Set Up GitHub Secrets and Environment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We will now add the newly generated public key to your GitHub account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. Copy the content of the public key file (usually `~\/.ssh\/id_rsa.pub`)<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cat ~\/.ssh\/id_rsa.pub<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\" style=\"white-space:normal;\">ssh-rsa [TRUNCATED]AAAAB3NzaC1yc2EAAAADAQABAAACAQDQYdyOZ6YJjNRgHuzsUCiPZ5gkLM2XX6ykuagraQBnX+s3mrROENHH5Yud0lBO8S2yNKa+s\/kleo8VLRocnwwO4VRuhqmFJ+70olPWlLjFd3AGn12pDBnF+beU5vP2cMsyCGcw0ZykA7TL0kQilLn9ShWPqHFOaP18fZcE5Wxcy6+Ai2hhodrySiUWa2n4H93BhBEjQtejGh8ExdTnPbtGKnYOMwx6aWY9UJhJgtI0mDSvNix9cramJNPxOSm9LuX0kkrmo9XefTzjfLblkCPeMDIk4cLxT8o09CmIEvVswW1Dmhgl3bNLg7YNQ== example@example.com<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">2. Go to your GitHub profile &gt; Settings &gt; <a href=\"https:\/\/github.com\/settings\/keys\" target=\"_blank\" rel=\"noopener\">SSH and GPG keys.<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3. Click the <strong>New SSH key<\/strong> button and paste your public key.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/2-github-actions-ssh-keys.png\" alt=\"-\" class=\"wp-image-47424\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">4. Save the public SSH key.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/3-github-actions-add-new-ssh-key.png\" alt=\"-\" class=\"wp-image-47425\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now we will proceed with setting up our GitHub repository for GitHub Actions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1. For the repository you intend to use with GitHub Actions, go to your GitHub repository settings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2. Navigate to <strong>Settings &gt; Environments &gt; New environment<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/4-github-actions-repository-environment-1024x272.png\" alt=\"-\" class=\"wp-image-47426\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note:<\/strong> The Environment settings may not be available to all <a href=\"https:\/\/docs.github.com\/en\/actions\/managing-workflow-runs-and-deployments\/managing-deployments\/managing-environments-for-deployment\" target=\"_blank\" rel=\"noopener\">repository types<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3. Create a new environment. For this tutorial, the environment is named <strong>Example<\/strong>, but you can use any name.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/5-github-actions-repository-configure-environment-1024x965.png\" alt=\"-\" class=\"wp-image-47427\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">4. In the <strong>Example<\/strong> environment, add the following secrets:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Secrets<\/strong><\/td><td><\/td><\/tr><tr><td>SSH_HOST<\/td><td>Your UpCloud server&#8217;s IP address.<\/td><\/tr><tr><td>SSH_USERNAME<\/td><td>The username to log in to your UpCloud server (usually &#8220;root&#8221;).<\/td><\/tr><tr><td>SSH_KEY<\/td><td>The private SSH key generated on your UpCloud server (the content of `~\/.ssh\/id_rsa`).<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Your Environment secrets should now look like this.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/6-github-actions-repository-environment-secrets.png\" alt=\"-\" class=\"wp-image-47428\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note:<\/strong> If you don\u2019t have an Environment section, then <strong>Actions secrets<\/strong> will work instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create the GitHub Actions Workflow File<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">1. In your GitHub repository, create a new file: <strong>.github\/workflows\/deploy.yml.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2. Start with the basic structure. Mind the spacing for YAML files!<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">name: Build &amp; Deploy<br><br>on:<br>\u00a0\u00a0push:<br>\u00a0\u00a0\u00a0\u00a0branches: [main]<br><br>jobs:<br>\u00a0\u00a0deploy:<br>\u00a0\u00a0\u00a0\u00a0runs-on: ubuntu-latest<br>\u00a0\u00a0\u00a0\u00a0environment: Example # Change this to match your environment name!<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Add Deployment Steps<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We will use the actions <a href=\"https:\/\/github.com\/actions\/checkout\" target=\"_blank\" rel=\"noopener\">checkout repository for GitHub Actions<\/a> along with Appleboy\u2019s <a href=\"https:\/\/github.com\/appleboy\/ssh-action\" target=\"_blank\" rel=\"noopener\">SSH for Github Actions<\/a> to connect and deploy to our UpCloud server. For additional information on GitHub Actions refer to GitHub\u2019s official <a href=\"https:\/\/docs.github.com\/en\/actions\" target=\"_blank\" rel=\"noopener\">documentation<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Add the following steps to your workflow:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">name: Build &amp; Deploy<br>on:<br>\u00a0\u00a0push:<br>\u00a0\u00a0\u00a0\u00a0branches: [main]<br><br>jobs:<br>\u00a0\u00a0deploy:<br>\u00a0\u00a0\u00a0\u00a0runs-on: ubuntu-latest<br>\u00a0\u00a0\u00a0\u00a0environment: Example # Change this to match your environment name!<br>\u00a0\u00a0\u00a0\u00a0steps:<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- name: Checkout code<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0uses: actions\/checkout@v2<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- name: Debug - Print Secret Availability<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0run: |<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0echo \"SSH_HOST is set: ${{ secrets.SSH_HOST != '' }}\"<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0echo \"SSH_USERNAME is set: ${{ secrets.SSH_USERNAME != '' }}\"<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0echo \"SSH_KEY is set: ${{ secrets.SSH_KEY != '' }}\"<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0- name: Deploy to UpCloud<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0uses: appleboy\/ssh-action@master<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0with:<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0host: ${{ secrets.SSH_HOST }}<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0 username: ${{ secrets.SSH_USERNAME }}<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0 key: ${{ secrets.SSH_KEY }}<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0 port: 22<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0 script: |<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0echo \"Connected to host\"<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0touch helloworld.txt<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0echo \"hello world!\" > helloworld.txt<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0echo \"Deployment successful\"<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Commit and Push<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Commit the <strong>deploy.yml<\/strong> file and push it to your main branch.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/7-github-actions-commit-changes.png\" alt=\"-\" class=\"wp-image-47429\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This will trigger the workflow.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Monitor the Workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">1. Go to the <strong>Actions<\/strong> tab in your GitHub repository.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/8-github-actions-workflow-run-1024x201.png\" alt=\"-\" class=\"wp-image-47430\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">2. You should see your workflow running. If the workflow succeeds, you will see a checkmark.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/9-github-action-complete.png\" alt=\"-\" class=\"wp-image-47431\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">3. Click on the workflow run to see detailed logs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">4. Check the output of the <strong>Debug &#8211; Print Secret Availability<\/strong> step to ensure your secrets are accessible.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/upcloud.com\/media\/10-github-action-debug-output.png\" alt=\"-\" class=\"wp-image-47432\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Verify Deployment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">1. SSH into your UpCloud server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2. Check if the <strong>helloworld.txt<\/strong> file has been created.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@example-server:~# pwd<br>\/root<br>root@example-server:~# ls<br>helloworld.txt<br>root@example-server:~# cat helloworld.txt<br>hello world!<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">3. You have now established a successful connection between your GitHub repository and your UpCloud server. You may now modify the workflow to suit your needs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8211;   If secrets are not available, double-check they are correctly set in your repository&#8217;s environment settings.<\/li>\n\n\n\n<li>&#8211;   Ensure the SSH key has the correct permissions on your UpCloud server.<\/li>\n\n\n\n<li>&#8211;   If the connection fails, verify that your UpCloud server&#8217;s firewall allows incoming SSH connections.<\/li>\n\n\n\n<li>&#8211;   Make sure the public key is correctly added to both GitHub and the <strong>authorized_keys<\/strong> file on your server.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If GitHub Actions fails with:<\/p>\n\n\n\n<ul id=\"block-87aa39fc-aa0e-4b70-868e-7c66b17b3c5c\" class=\"wp-block-list\">\n<li><strong>1. Error: missing server host<\/strong>; ensure you have set the correct environment in your workflow file.<\/li>\n\n\n\n<li><strong>2. Error: You have an error in your yaml syntax on line #<\/strong>; double-check your spacing and indentation.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Next Steps<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8211;   Set up a web server (like Nginx) on your UpCloud server to serve the deployed files.<\/li>\n\n\n\n<li>&#8211;   Expand the workflow to deploy more complex applications or static sites.<\/li>\n\n\n\n<li>&#8211;   Add additional security measures, such as IP restrictions or deployment approvals.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Remember to iterate and expand on this basic setup as your project grows and deployment needs become more complex.<\/p>\n","protected":false},"author":65,"featured_media":47444,"comment_status":"open","ping_status":"closed","template":"","community-category":[256,223],"class_list":["post-1933","tutorial","type-tutorial","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/1933","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/types\/tutorial"}],"author":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/comments?post=1933"}],"version-history":[{"count":0,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/tutorial\/1933\/revisions"}],"wp:attachment":[{"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/media?parent=1933"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/upcloud.com\/global\/wp-json\/wp\/v2\/community-category?post=1933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}