Skip to main content

Server

Emanates supports deploying to a Virtual Private Server (VPS) or any other server that you might have SSH Access.

How will it work?#

Deploying to any VPS will have three steps:

  • Building the distributable (the webpage in our case)
  • Pushing to some container storage (like Docker or GitHub Container Registry)
  • Fetching the latest image and deploying it on the server (by SSH'ing into the server)

The above steps should all be ran directly through the pipeline so that it can be run as an action.

Before you begin#

You need to setup a deployment script that will run everytime a new image is built. This script should be able to pull the latest image from the container storage (like Docker) and then deploy it locally.

info

You'd need to connect the locally run container with a domain. Steps to set that up is beyond the scope of this documentation. The basic idea is that there should be a domain that will feed the content being fed by the container image that will be deployed by the deployment script.

Below is a straightforward deployment script:

#!/bin/bash######################################### Put this on a Server# run chmod +x deploy_app.sh to make the script executable# # Execute this script:  ./deploy_app.sh docker-username/docker-appname:$TAG# Replace the $TAG with the actual Build Tag you want to deploy#########################################
set -e
DOCKER_IMAGE=$1CONTAINER_NAME="emanates-blog"
# Check for argumentsif [[ $# -lt 1 ]] ; then    echo '[ERROR] You must supply a Docker Image to pull'    exit 1fi
echo "Deploying $CONTAINER_NAME to Docker Container"
#Check for running container & stop it before starting a new oneif [ $(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME) = "true" ]; then    docker stop $CONTAINER_NAMEfi
# Pull the latest imageecho "Pulling latest image for $DOCKER_IMAGE"
docker pull $DOCKER_IMAGE
echo "Starting $CONTAINER_NAME using Docker Image name: $DOCKER_IMAGE"
docker run -d --rm=true -p 80:8080 --name $CONTAINER_NAME $DOCKER_IMAGE
# Show the running processesdocker ps

The above script expects an argument that will be the name of a docker image and it will be passed along to the code accordingly.

Setup the script#

Copy the above content of the script and save it on your server as deploy_emanates.sh

info

You can save the script somewhere better suited like a ~/Scripts directory.

Once the script is copied, make sure it's executable by runing the following command.

chmod +x deploy_emanates.sh
info

You might need to add sudo in the above command.

Action Used#

We will use the SSH action in order to SSH into the server and run the deployment script.

Requirements#

You need to setup a few secrets in order for the workflow to run properly.

The SSH Action requires three values in order to be able to SSH into the server and run the deployment command.

  • SERVER_IP: IP Address of your server.
  • SERVER_USERNAME: Username of the user to ssh into the server.
  • KEY: Contents of the private key file.

All three of the above variables need to be added as a secret in GitHub with the name given above and the content as described.

Files to set up#

Dockerfile#

In order for the static page to work, you need to setup a Dockerfile in the root of your repository. Just copy the following content and save it in the root as Dockerfile.

# Use latest nginx imageFROM nginx:latest
# Remove default filesRUN rm -rf /usr/share/nginx/html/*
# Copy the distributable directoryCOPY ./dist/ /usr/share/nginx/html
# Copy the configCOPY nginx.conf /etc/nginx/nginx.conf

Nginx config#

We also need a nginx config file with the name nginx.conf in the root directory that will be used by the docker container to configure nginx.

user  nginx;worker_processes  1;error_log  /var/log/nginx/error.log warn;pid        /var/run/nginx.pid;
events {  worker_connections  1024;}
http {    gzip on;
    gzip_vary on;    gzip_proxied any;    gzip_comp_level 6;    gzip_buffers 16 8k;    gzip_http_version 1.1;    gzip_min_length 256;    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
    # Expires map    map $sent_http_content_type $expires {        default                    off;        text/html                  epoch;        text/css                   max;        application/javascript     max;        ~image/                    max;    }
    server {        listen 8080 default_server;        listen [::]:8080 default_server;
        expires $expires;
        root /usr/share/nginx/html;        index index.html index.htm;
        server_name emanates;
        error_page 404 /200.html;                    location / {        }    }}

Workflow Code#

Before you deploy#

Before copying and deploying the workflow, please make changes to the file according to your setup. Currently, the workflow supports using GitHub Container Registry as well as Docker Hub.

Whichever you want to use, follow one of the follow subtopics accordingly.

GitHub Container Registry (GHCR)#

The following instructions are exactly same as the one below for Docker just that this will use GitHub Container Registry to store the container and pull it from there and deploy.

warning

Make sure GitHub Container Registry support is added in your github account. Refer this on how to do that

  • Enable GitHub Container Registry on your GitHub Account. Check
  • Login into the container registry on your server through docker. Check
  1. Add username, password and image to code

    • Add your github username in place of the <docker username or ghcr username>. Alternately, you can use ${{ github.repository_owner }} if you want to store the image for the current github user.

    • Generate a GitHub token with access to container images (or use the Emanates token with added access for container images) and store it as a secret on GitHub with the name DOCKER_PASSWORD.

    • Replace all the occurences of <image_name> with the path to your image name, this should be something like ghcr.io/github-username/image-name:latest. For eg: ghcr.io/octokit/emanates-blog:latest

  2. Signin to Docker with GitHub container account on your server

    Since the deploy script will use the docker to pull the latest image, it is important to login to that account so docker is able to pull the changes.

    Read this to learn how to login to docker with GitHub

Docker Hub#

In order to push the built images to Docker Hub, follow the following instructions.

  1. Add username, password and image to code

    • Add your docker username in place of the <docker username or ghcr username>.

    • Save your docker password as a secret on GitHub with the name DOCKER_PASSWORD.

    • Replace all the occurences of <image_name> with the path to your image name, this should be something like docker-username/image-name:latest. For eg: octokit/emanates-blog:latest

  2. Signin to Docker account on your server

    Since the deploy script will use the docker to pull the latest image, it is important to login to that account so docker is able to pull the changes.

    You can use your docker username and password to login in the following way:

    docker -u <username>

Template Code#

Below is the deploy.yml file that you need to add in the .github/workflows directory on your repository.

warning

If there is already a deploy.yml file in that repo, replace it with the below one!

name: 'Emanates Deploy'
on:  issues:    types: [opened, edited, deleted]
jobs:  build-push:    name: 'Build Page and Push to Container Registry'    runs-on: ubuntu-latest
    steps:      - name: Checkout the repo        uses: actions/checkout@v2      - name: Install dependencies        run: npm install      - name: Set the repo env variable        run: echo "REPO=$(echo $GITHUB_REPOSITORY)" >> $GITHUB_ENV      - name: Build the static page        run: npm run generate        env:          EMANATES_TOKEN: ${{ secrets.EMANATES_TOKEN }}      # Login to ghcr      - name: Login to GitHub Container Registry        uses: docker/login-action@v1         with:          registry: ghcr.io          username: <docker username or ghcr username>          password: ${{ secrets.DOCKER_PASSWORD }}      # Build the docker image now      - name: Build and push        uses: docker/build-push-action@v2        with:          context: .          push: true          tags: <image_name>
  deploy:    needs: build-push    runs-on: ubuntu-latest    steps:      # SSH into the server      - name: SSH into server        uses: appleboy/ssh-action@master        with:          host: ${{ secrets.SERVER_IP }}          username: ${{ secrets.SERVER_USERNAME }}          key: ${{ secrets.KEY }}          script: /bin/bash deploy_emanates.sh <image_name>

Once you save the above file, it's time to create a new blog post.