linkr

Beautiful, fast URL shortening.
28 May 20191101

Linkr logo

Linkr

Build Status Coverage Status

Linkr is a self-hosted URL shortener built on modern web technologies that is fast, minimalistic, and developer-friendly.

Overview and Features

  • Minimalistic, modern, and responsive frontend interface for both mobile and desktop web
  • Support for administrator users and a dedicated admin interface to manage all links
  • Statistics tracking for each created link
  • Password-protected links
  • Low-friction user accounts support
  • Developer-friendly RESTful API, making it easy to build apps that leverage Linkr's services
  • Linkr is fast.
    • Web UI is built with React and React-Router, meaning page-to-page navigation is instantaneous and only one network request for an HTML document is ever made per session
    • The entire client-side SPA requires only a single HTTP request totaling < 300 KB in size (production build, minified and gzipped)

Installation

Prerequisites

  • You need Python, pip, and the virtualenv package. (Reference)
  • You need Node and npm. (Reference)
  • You need a MySQL database. (Reference) (You can use almost any other database too; see "Alternate databases")
  • You need Redis. (Reference)
  • You need Apache, with mod_wsgi installed. (Reference)
  • All following instructions assume Debian Linux.

Instructions

Get the code

$ git clone https://github.com/LINKIWI/linkr.git
$ cd linkr/

Install dependencies

$ sudo apt-get install libmysqlclient-dev python-dev
$ virtualenv env
$ source env/bin/activate
$ pip install -r requirements.txt
$ npm install

Set up the MySQL database

CREATE USER 'linkr'@'localhost' IDENTIFIED BY 'super-secret-password';
CREATE DATABASE linkr;
GRANT ALL ON linkr.* TO 'linkr'@'localhost';
FLUSH PRIVILEGES;

Configuration options and secrets

  • Don't skip this step! Building and running the app will fail without config files!
  • Documentation for each available config option is in the Configuration section.
$ cp config/options/client.json.template config/options/client.json
$ cp config/options/server.json.template config/options/server.json
$ cp config/secrets/client.json.template config/secrets/client.json
$ cp config/secrets/server.json.template config/secrets/server.json
# You can leave the options as default, or modify to your liking. Make sure the server-side secrets
# config contains your database connection credentials.

Build the app.

$ NODE_ENV=production npm run build

Run the linkr_setup.py script to walk you through setting up the database and creating an admin user.

$ python linkr_setup.py
==========LINKR SETUP==========

This script is used for initializing Linkr for the first time on a new deployment.
This will create the Linkr MySQL tables and create an admin user account.
...

Almost there! An Apache virtual host config sample using WSGI:

<VirtualHost *:80>
    ServerName t.example.com

    AliasMatch "^/(linkr/(?!.*api/).+)?$" /path/to/linkr/frontend/static/dist/index.html
    Alias /linkr/static /path/to/linkr/frontend/static

    WSGIScriptAlias / /path/to/linkr/linkr.wsgi

    <Directory /path/to/linkr>
        Require all granted
    </Directory>
</VirtualHost>

The service is now live at t.example.com!

I am lazy and just want a prebuilt Docker image

Building the application from source is highly recommended. This is because the application's configuration options are specific to your installation, and must be configured before the application can run. Also, client-side secrets are bundled directly into the application as part of the build process, so it's not possible to distribute a pre-built frontend.

Alternate databases

The default database is MySQL, but you can change this to any database that is compatible with flask-sqlalchemy. Simply change SQLALCHEMY_DATABASE_URI in config/flask.py for the database of your choice.

Configuration

config/options/client.json

Key Value
title The main page title on all Linkr frontend pages.
piwik An object of options to pass to piwik-react-router. If your production infrastructure does not make use of Piwik, leave this as null
enable_recent_links True to allow client-side storage and display of recently created and accessed links on the home page.

config/options/server.json

Key Value
linkr_url The public-facing URL to your Linkr installation, including the protocol and without a trailing forward slash.
require_login_to_create True to require users to sign in before creating links; false to allow anonymous and signed-in users to create links.
allow_open_registration True to allow anyone to register; false to disallow all registration.
secure_frontend_requests True to allow the server to perform additional request validation to ensure that non-public API endpoints are only requested via Linkr's frontend interface. It is recommended to leave this enabled, unless it is causing issues.

config/secrets/client.json

Note that all of these secrets are bundled into the frontend application at build time.

Key Value
sentry_client_dsn The client-side Sentry DSN key for this application. If your production infrastructure does not make use of Sentry or you don't care about error reporting, leave this as null
recaptcha_site_key The client-side site key for this application from the Google ReCAPTCHA admin panel. If you don't want to enable the human verification feature for links, leave this as null

config/secrets/server.json

Key Value
sentry_server_dsn The server-side Sentry DSN key for this application. If your production infrastructure does not make use of Sentry or you don't care about error reporting, leave this as null
recaptcha_secret_key The server-side secret key for this application from the Google ReCAPTCHA admin panel. If you don't want to enable the human verification feature for links, leave this as null
database.host The hostname or IP of the MySQL database.
database.name The name of Linkr's database.
database.user The username of the MySQL user for accessing the above database.
database.password The password of the MySQL user for accessing the above database.
redis.host The hostname of the Redis datastore.
redis.port The port of the Redis datastore.
statsd.host The hostname of the Statsd server. If you don't use Statsd, leave this as default
statsd.port The port of the Statsd server. If you don't use Statsd, leave this as default

Development

  1. Make sure all dependencies are installed and a database is available locally. Follow the same instructions for installation.
  2. At the terminal, run npm run dev. This will concurrently start the following processes:
    • npm run start: Server process
    • npm run build-js: Javascript build of the frontend application
    • npm run build-css: SCSS build

Contributing

Linkr is open to pull requests for bug fixes and/or new features. Please adhere to the following guidelines:

  • Maintain consistent code style with the rest of the codebase.
  • Document new functions, new components, or any non-intuitive logic according to existing documentation conventions.
  • Any changed or added lines should be accompanied with unit tests.
  • Don't drop coverage or introduce regressions. CI will help with this.