Guillotine
Guillotine is a simple URL Shortener written in Ruby and powers GitHubs URL Shortener Git.io. It supports multiple storage adapters, including MySQL, PostgreSQL, SQLite, Redis, Riak and Cassandra.
Note
For this guide you should be familiar with the basic concepts of
License
Guillotine is released under the MIT License.
Prerequisites
We’re using Ruby in the stable version 2.6:
[isabell@stardust ~]$ uberspace tools version use ruby 2.6
Selected Ruby version 2.6
The new configuration is adapted immediately. Patch updates will be applied automatically.
[isabell@stardust ~]$
You’ll need your MySQL credentials. Get them with my_print_defaults
:
[isabell@stardust ~]$ my_print_defaults client
--default-character-set=utf8mb4
--user=isabell
--password=MySuperSecretPassword
[isabell@stardust ~]$
Your Short URL needs to be setup:
[isabell@stardust ~]$ uberspace web domain list
isabell.uber.space
[isabell@stardust ~]$
Installation
Install Dependencies
Use gem
to install the latest versions of the Guillotine, Sequel and mysql2 gems:
[isabell@stardust ~]$ gem install guillotine sequel mysql2
Fetching sinatra-1.4.8.gem
Fetching addressable-2.3.8.gem
Fetching rack-1.6.11.gem
Fetching tilt-2.0.9.gem
Fetching rack-protection-1.5.5.gem
Fetching guillotine-1.4.2.gem
WARNING: You don't have /home/isabell/.gem/ruby/2.6.0/bin in your PATH,
gem executables will not run.
Successfully installed rack-1.6.11
Successfully installed rack-protection-1.5.5
Successfully installed tilt-2.0.9
Successfully installed sinatra-1.4.8
Successfully installed addressable-2.3.8
Successfully installed guillotine-1.4.2
Fetching sequel-5.22.0.gem
Successfully installed sequel-5.22.0
Fetching mysql2-0.5.2.gem
Building native extensions. This could take a while...
Successfully installed mysql2-0.5.2
8 gems installed
[isabell@stardust ~]$
Create App File
Create a directory for the application:
[isabell@stardust ~]$ mkdir ~/guillotine
[isabell@stardust ~]$
Add the following content to ~/guillotine/app.rb
to set up the connection to the MySQL database using the Sequel adapter. Make sure to adapt your MySQL credentials.
require 'guillotine'
require 'sequel'
module MyApp
class App < Guillotine::App
db = Sequel.connect("mysql2://isabell:MySuperSecretPassword@127.0.0.1:3306/isabell")
adapter = Guillotine::Adapters::SequelAdapter.new(db)
set :service => Guillotine::Service.new(adapter)
post "/" do
status, head, body = settings.service.create(params[:url], params[:code])
if loc = head['Location']
body = head['Location'] = File.join(request.base_url, loc)
end
# Show shortened URL in Body
[status, head, simple_escape(body)]
end
end
end
Note
This file can be used as a configuration point. The Katana project provides an example for possible extensions.
Create Rackup config file
Add the following content to ~/guillotine/config.ru
:
require "rubygems"
require File.expand_path("../app.rb", __FILE__)
run MyApp::App
Set up Database
Initialize the database for Guillotine:
[isabell@stardust ~]$ mysql <<__SQL__
USE $USER;
CREATE TABLE IF NOT EXISTS \`urls\` (
\`url\` varchar(255) DEFAULT NULL,
\`code\` varchar(255) DEFAULT NULL,
UNIQUE KEY \`url\` (\`url\`),
UNIQUE KEY \`code\` (\`code\`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
__SQL__
[isabell@stardust ~]$
Configure web server
Note
Guillotine is running on port 9292.
To make the application accessible from the outside, configure a web backend:
[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$
Setup daemon
Create ~/etc/services.d/guillotine.ini
with the following content:
[program:guillotine]
environment=APP_ENV=production
directory=%(ENV_HOME)s/guillotine
command=/opt/uberspace/etc/%(ENV_USER)s/binpaths/ruby/rackup config.ru --host 0.0.0.0 --port 9292
After creating the configuration, tell supervisord to refresh its configuration and start the service:
[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE RUNNING pid 26020, uptime 0:03:14
[isabell@stardust ~]$
If it’s not in state RUNNING, check your configuration.
Create short URL
Use your HTTP tool of choice (e.g. curl
) to make a POST request to create a short URL.
[isabell@stardust ~]$ curl https://isabell.uber.space \
--form "url=https://uberspace.de"
https://isabell.uber.space/D_deZA
[isabell@stardust ~]$
Define your own short code like so:
[isabell@stardust ~]$ curl https://isabell.uber.space \
--form "url=https://lab.uberspace.de" \
--form "code=lab"
https://isabell.uber.space/lab
[isabell@stardust ~]$
Updates
Note
Check the update feed regularly to stay informed about the newest version.
Use gem to update dependencies like so:
[isabell@stardust ~]$ gem update
Updating installed gems
Updating addressable
Fetching addressable-2.6.0.gem
Fetching public_suffix-3.1.1.gem
WARNING: You don't have /home/isabell/.gem/ruby/2.6.0/bin in your PATH,
gem executables will not run.
Successfully installed public_suffix-3.1.1
Successfully installed addressable-2.6.0
Updating bigdecimal
Fetching bigdecimal-1.4.4.gem
Building native extensions. This could take a while...
Successfully installed bigdecimal-1.4.4
Updating csv
Fetching csv-3.1.1.gem
Successfully installed csv-3.1.1
Updating fileutils
Fetching fileutils-1.2.0.gem
Successfully installed fileutils-1.2.0
Updating io-console
Fetching io-console-0.4.8.gem
Building native extensions. This could take a while...
Successfully installed io-console-0.4.8
Updating json
Fetching json-2.2.0.gem
Building native extensions. This could take a while...
Successfully installed json-2.2.0
Updating rack
Fetching rack-2.0.7.gem
Successfully installed rack-2.0.7
Updating rack-protection
Fetching rack-protection-2.0.5.gem
Successfully installed rack-protection-2.0.5
Updating rdoc
Fetching rdoc-6.1.1.gem
Successfully installed rdoc-6.1.1
Updating rexml
Fetching rexml-3.2.2.gem
Successfully installed rexml-3.2.2
Updating rss
Fetching rss-0.2.8.gem
Successfully installed rss-0.2.8
Updating sinatra
Fetching sinatra-2.0.5.gem
Fetching mustermann-1.0.3.gem
Successfully installed mustermann-1.0.3
Successfully installed sinatra-2.0.5
Gems updated: addressable public_suffix bigdecimal csv fileutils io-console json rack rack-protection rdoc rexml rss mustermann sinatra
[isabell@stardust ~]$
Restart the Service for the update to take effect.
[isabell@stardust ~]$ supervisorctl restart guillotine
guillotine: stopped
guillotine: started
[isabell@stardust ~]$
Check the status and logs to verify that Guillotine started successfully after the update.
[isabell@stardust ~]$ supervisorctl status guillotine
guillotine RUNNING pid 26020, uptime 0:03:14
[isabell@stardust ~]$ supervisorctl tail -5000 guillotine stderr
[2019-08-01 16:48:56] INFO WEBrick::HTTPServer#start done.
[2019-08-01 16:48:56] INFO WEBrick 1.4.2
[2019-08-01 16:48:56] INFO ruby 2.6.2 (2019-03-13) [x86_64-linux]
[2019-08-01 16:48:56] INFO WEBrick::HTTPServer#start: pid=26020 port=9292
[isabell@stardust ~]$
Tested with Ruby 2.6.2, Guillotine 1.4.2, Uberspace 7.3.4
Written by: Jan Philip Bernius <https://janphilip.bernius.net>