DEV Community

Cover image for 🔗 Personal URL shortener on your domain with automation through GitHub Actions
Vic Shóstak
Vic Shóstak

Posted on • Updated on

🔗 Personal URL shortener on your domain with automation through GitHub Actions

Introduction

Hey, hey! 👋 Are you ready to continue learning how to work with GitHub Actions and get to know it better? Perfect! Today, we will create your own link shortener to simplify interaction on the Internet.

So where's GitHub Actions? Almost everywhere, because that's main part! We'll use it at its full power to add new links, reboot a web server and deploy a friendly index page of your shortener website.

📝 Table of contents

🤔 What will we build?

We will build the URL shortener for only important links, that you always use and which you won't change often.

👀 For example, for a slide in your presentation with contact information or for downloading a useful snippet from your repository (for easily wget manipulations) or for a shorter version of link to YouTube video... and so on.

All right, here's our plan:

  • Register domain name
  • Configure remote virtual server
  • Configure a separate branches of the same GitHub repository
  • Configure GitHub Actions for deploys
  • Push-to-Deploy

↑ Table of contents

Repository structure

As I said earlier, we will split our repository into two branches:

  1. master branch will contain the main scenario (a list of shortened URLs)
  2. website branch will contain the index page of your website (a "hello" message for curious users)

☝️ Please note: in this case, the unfolding of two branches will go independently of each other. Thank you, GitHub Actions!

Structure of master branch:

.
├── .github
│   └── workflows
│       └── urls_deploy.yml  # <-- GitHub Action
└── short_urls_list.conf     # <-- List of shorted URLs (NGINX config)
Enter fullscreen mode Exit fullscreen mode

Structure of website branch:

.
├── .github
│   └── workflows
│       └── website_deploy.yml  # <-- GitHub Action
└── index.html                  # <-- Index page of website
Enter fullscreen mode Exit fullscreen mode

↑ Table of contents

🌐 Register domain name

At the very beginning of our exciting journey, let's define the domain name for your project. I was lucky enough to register the domain name shrts.website, which fully matches to our idea: make shorten links to websites.

😉 Fun fact: I've been using this domain name registrar for over 14 years (to be exact, since October 2006) and I'm still fully satisfied with its prices and support.

You can play with different combinations and abbreviations, but the main purpose of the domain for a such project → simplicity and ease of remembering!

↑ Table of contents

⚙️ Configure remote virtual server

To avoid repeating myself, I'm not going to describe in detail the process of configuring the virtual server and just give you links to my articles, where I already described it:

  1. Create a new droplet on DigitalOcean
  2. Setup virtual server via snippets-deploy
  3. Create a private SSH key for GitHub Actions deploys

↑ Table of contents

🤖 Configure GitHub Actions for deploys

Let's start with the most interesting part: setting up GitHub Actions.

↑ Table of contents

GitHub secrets

Here's a list of all the secrets we need:

  • REMOTE_HOST – IP address of your virtual server
  • REMOTE_USER – user on your virtual server (not root, please)
  • REMOTE_NGINX_DIR – full path to your NGINX folder for place snippets (by default, it should be /etc/nginx/snippets)
  • REMOTE_WEBSITE_DIR – full path to your website root folder (if you setup your virtual server via snippets-deploy, it should be /var/www/<domain>/html)
  • SSH_KEY — the contents of a PRIVATE part (~/.ssh/gha_rsa) of the SSH key, that we generated in Private key for SSH section of my previous article
  • SSH_KEY_PASSPHRASE — the passphrase of the SSH key, that we entered, when generating the SSH key

GitHub secrets

☝️ Please read part of my previous article entitled "Understanding the GitHub secrets", if you want to know more about it.

↑ Table of contents

List of shorted URLs

Let's get started with NGINX config for your <domain> on remote virtual server.

Connect to server and open config in nano editor. Go to main server {...} section and add include snippets/short_urls_list.conf; line after index index.html;, like this:

# /etc/nginx/sites-available/<domain>.conf

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name <domain>;
    root /var/www/<domain>/html;
    index index.html;

    include snippets/short_urls_list.conf; # <-- include file with URLs redirects

    ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/<domain>/chain.pem;

    # ...
Enter fullscreen mode Exit fullscreen mode

❗️ Attention: do not forget to change <domain> to yours.

Good! 👍 Now, create snippet with shorten URLs in your GitHub repository:

# short_urls_list.conf

rewrite /link-1 https://huge-example-1.com/very-long/link/1 permanent;
Enter fullscreen mode Exit fullscreen mode

As you can see, these are common 301 Moved Permanently redirect from https://<domain>/link-1 to another link (https://huge-example-1.com/very-long/link/1 in this example).

Now, we've to create GitHub Action config for master branch:

# .github/workflows/urls_deploy.yml

name: Deploy new short URLs via SSH

on:
  push:
    branches: [master] # triggered only if pushed to master branch

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Checks-out repository under $GITHUB_WORKSPACE
      - uses: actions/checkout@master

      # Copying files to server via SSH
      - name: Copying files to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.SSH_KEY }}
          passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
          source: "short_urls_list.conf"
          target: "${{ secrets.REMOTE_NGINX_DIR }}"

      # Restart NGINX after deploy
      - name: Restart NGINX
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.SSH_KEY }}
          passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
          script: sudo nginx -t && sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

↑ Table of contents

Website index page

Switch to website branch and create an index page (simple index.html file) for the website of your taste.

👌 It could be some kind of welcome text describing your shortener or whatever you want. Fantasize about it!

And, finally, we're ready to create GitHub Action for website branch:

# .github/workflows/website_deploy.yml

name: Deploy website via SSH

on:
  push:
    branches: [website] # triggered only if pushed to website branch

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Checks-out repository under $GITHUB_WORKSPACE
      - uses: actions/checkout@master

      # Copying files to server via SSH
      - name: Copying files to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.SSH_KEY }}
          passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
          source: "index.html"
          target: "${{ secrets.REMOTE_WEBSITE_DIR }}"
Enter fullscreen mode Exit fullscreen mode

Let's deploy it!

Commit & push changes to your repository (for both branches) and visit https://<domain> to see website index page, like this:

shrts.website screen

Now, hit your shortened link to make sure everything works as intended.

Yep, it just works! 🎉

Add new link

To add a new link, all you need to do is add it to the short_urls_list.conf file (in the master branch) and make push.

That's all! Cool, isn't it? 😎

↑ Table of contents

💬 Questions for better understanding

  1. What should be the domain name for the link shortener?
  2. Due to what redirect from a short link to the original occurs?
  3. Which parameter in the GitHub Actions config is responsible for triggering job by branch name?

↑ Table of contents

✏️ Exercises for independent execution

  • Repeat everything you have seen in the article, but with your own domain and virtual server. Please, write about your result & link to your shorter website in the comments below!
  • Try to deploy index.html to GitHub Pages (at your repository) instead of the virtual server, using the right action. See gh-pages docs here.

↑ Table of contents

Photos/Images by

  • True web artisans (link)
  • GitHub repository settings (link)

P.S.

If you want more articles (like this) on this blog, then post a comment below and subscribe to me. Thanks! 😻

And of course, you can help me make developers' lives even better! Just connect to one of my projects as a contributor. It's easy!

My projects that need your help (and stars) 👇

  • 🔥 gowebly: A next-generation CLI tool for easily build amazing web applications with Go on the backend, using htmx & hyperscript and the most popular atomic/utility-first CSS frameworks on the frontend.
  • create-go-app: Create a new production-ready project with Go backend, frontend and deploy automation by running one CLI command.
  • 🏃 yatr: Yet Another Task Runner allows you to organize and automate your routine operations that you normally do in Makefile (or else) for each project.
  • 📚 gosl: The Go Snippet Library provides snippets collection for working with routine operations in your Go programs with a super user-friendly API and the most efficient performance.
  • 🏄‍♂️ csv2api: The parser reads the CSV file with the raw data, filters the records, identifies fields to be changed, and sends a request to update the data to the specified endpoint of your REST API.
  • 🚴 json2csv: The parser can read given folder with JSON files, filtering and qualifying input data with intent & stop words dictionaries and save results to CSV files by given chunk size.

Top comments (8)

Collapse
 
ben profile image
Ben Halpern

This is really slick

Collapse
 
koddr profile image
Vic Shóstak

Yes, it is 😅

Collapse
 
mariusty profile image
mariusty

Great article! And this series in general
Can't wait to read the forth part :)

Collapse
 
koddr profile image
Vic Shóstak

Thx! You're welcome 👍

Collapse
 
deven96 profile image
Diretnan Domnan

Nice article!

Collapse
 
koddr profile image
Vic Shóstak

Thanks! 😊

Collapse
 
mkoryak profile image
Misha Koryak

sharts.website

Hmmm

Collapse
 
koddr profile image
Vic Shóstak

Nope, it's shrts.website, without a letter between h and r 😉