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 beginYou 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 scriptCopy 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 UsedWe will use the SSH action in order to SSH into the server and run the deployment script.
#
RequirementsYou 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#
DockerfileIn 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 configWe 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 deployBefore 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
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 likeghcr.io/github-username/image-name:latest
. For eg:ghcr.io/octokit/emanates-blog:latest
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.
#
Docker HubIn order to push the built images to Docker Hub, follow the following instructions.
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 likedocker-username/image-name:latest
. For eg:octokit/emanates-blog:latest
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 CodeBelow 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.