YOURLS is a self-hosted URL shortening service, it is like,,, etc.

Official descripton:

YOURLS stands for Your Own URL Shortener. It is a small set of PHP scripts that will allow you to run your own URL shortening service (a la TinyURL or bitly).

Running your own URL shortener is fun, geeky and useful: you own your data and don’t depend on third party services. It’s also a great way to add branding to your short URLs, instead of using the same public URL shortener everyone uses.

We need to install Lighttpd (I already have it since Pi-hole is installed), mysql the LAMP stack.

$ sudo apt install lighttpd mariadb php

Installation instructions are here:

Let us start. Download the git repository of YOURLS:

$ cd /var/
$ sudo git clone
$ sudo chown -R www-data:www-data YOURLS

We need to copy the user/config-sample.php to user/config.php Edit the user/config.php and set your configurations (explained here:

We will now create the database manually since there are issues with the database (#2307)

$ sudo mysql -uroot

>GRANT ALL PRIVILEGES on `yourls`.* TO 'yourls'@'localhost' IDENTIFIED BY 'MyGoodPassword';


You can skip this step if you are able to install yourls without error about the database.
Based on issue #2307 we need to manually create the table ‘yourls_url’. Login as yourls and create the table

$ sudo mysql -uyourls -p
>CREATE TABLE IF NOT EXISTS yourls_url (keyword varchar(200) BINARY NOT NULL,url text BINARY NOT NULL,title text CHARACTER SET utf8,timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,ip (keyword), KEY timestamp (timestamp), KEY ip (ip))

We need to edit lighttpd configuration (if you are using Pi-hole). The configuration will use http port 82 for yourls (you need to port forward to port 80 in your router, whenever someone is trying to access *.txt files in the url this will deny them access, this is also the equivalent .htaccess apache since lighttpd does not support .htaccess we will use this instead)

$ sudo nano /etc/lighttpd/external.conf
$SERVER["socket"] == ":82" {
        server.document.root = "/var/YOURLS"
        url.access-deny = ("~", ".md", ".txt", ".json", ".htaccess")
url.rewrite-once = (

    "^/([0-9A-Za-z-]+)?$" => "/yourls-go.php?id=$1",
    "^/([0-9A-Za-z-]+)?\+$" => "/yourls-infos.php?id=$1"


Edit the user/config.php:

 /* This is a sample config file.
 * Edit this file with your own settings and save it as "config.php"
 * IMPORTANT: edit and save this file as plain ASCII text, using a text editor, for instance TextEdit on Mac OS or
 * Notepad on Windows. Make sure there is no character before the opening <?php at the beginning of this file.

 ** MySQL settings - You can get this info from your web host

/** MySQL database username */
define( 'YOURLS_DB_USER', 'yourls' );

/** MySQL database password */
define( 'YOURLS_DB_PASS', 'MyGoodPassword' );

/** The name of the database for YOURLS */
define( 'YOURLS_DB_NAME', 'yourls' );

/** MySQL hostname.
 ** If using a non standard port, specify it like 'hostname:port', eg. 'localhost:9999' or '' */
define( 'YOURLS_DB_HOST', 'localhost' );

/** MySQL tables prefix */
define( 'YOURLS_DB_PREFIX', 'yourls_' );

/** YOURLS installation URL -- all lowercase and with no trailing slash.
 ** If you define it to "http://sho.rt", don't use "http://www.sho.rt" in your browser (and vice-versa) */

define( 'YOURLS_SITE', '' );

/** Server timezone GMT offset */
define( 'YOURLS_HOURS_OFFSET', 0 ); 

/** YOURLS language
 ** Change this setting to use a translation file for your language, instead of the default English.
 ** That translation file (a .mo file) must be installed in the user/language directory.
 ** See for more information */
define( 'YOURLS_LANG', '' ); 

/** Allow multiple short URLs for a same long URL
 ** Set to true to have only one pair of shortURL/longURL (default YOURLS behavior)
 ** Set to false to allow multiple short URLs pointing to the same long URL ( behavior) */
define( 'YOURLS_UNIQUE_URLS', true );

/** Private means the Admin area will be protected with login/pass as defined below.
 ** Set to false for public usage (eg on a restricted intranet or for test setups)
 ** Read for more details if you're unsure */
define( 'YOURLS_PRIVATE', true );

/** A random secret hash used to encrypt cookies. You don't have to remember it, make it long and complicated. Hint: copy from http://$
define( 'YOURLS_COOKIEKEY', 'thisisalongrandomsecrethash' );

/** Username(s) and password(s) allowed to access the site. Passwords either in plain text or as encrypted hashes
 ** YOURLS will auto encrypt plain text passwords in this file
 ** Read for more information */
$yourls_user_passwords = array(
        'admin' => 'root'
        // 'username2' => 'password2',
        // You can have one or more 'login'=>'password' lines
/** Debug mode to output some internal information
 ** Default is false for live site. Enable when coding or before submitting a new issue */
define( 'YOURLS_DEBUG', false );

 ** URL Shortening settings

/** URL shortening method: 36 or 62 */
define( 'YOURLS_URL_CONVERT', 36 );
 * 36: generates all lowercase keywords (ie: 13jkm)
 * 62: generates mixed case keywords (ie: 13jKm or 13JKm)
 * Stick to one setting. It's best not to change after you've started creating links.
* Reserved keywords (so that generated URLs won't match them)
* Define here negative, unwanted or potentially misleading keywords.
$yourls_reserved_URL = array(
        'porn', 'faggot', 'sex', 'nigger', 'fuck', 'cunt', 'dick', 'admin', 'shit'

 ** Personal settings would go after here.

define( 'BARRE_LOG_LOGIN_FILENAME', '/var/log/yourls.log' );
define( 'BARRE_LOG_LOGIN_FAILURE', true );

You can enhance your installation by using plugins:
Securing yourls, we can secure yourls using fail2ban and a recaptcha (if you are planning to make your yourls public access).
The Fail2ban method is done using a plugin, please review the issues since it has a bug.
Follow the steps in their github repo:

$ git clone

For manual configuration of fail2ban using log-login plugin
In the above configuration I already added the define( ‘BARRE_LOG_LOGIN_FILENAME’…

$ sudo apt install fail2ban
$ pear install Log-1.12.7
or use sudo if it has permission errors

Create a new file or edit an existing fail2ban config:

$ sudo nano /etc/fail2ban/jail.d/debian-default.conf
enabled = true
port = http,82
filter  = yourls
logpath = /var/log/yourls.log
maxretry = 12
findtime = 120
logtimezone = UTC

Create a new file:

$ sudo nano /etc/fail2ban/filter.d/yourls.conf
# This is an exempel filter for yourls.
# if you have changed the log format for the plugin
# you must change the filter to match the log format

failregex = .*-  -.*LOGIN FAILURE.*
ignoreregexp =

Create a new file:

$ sudo nano /etc/logrotate.d/yourls 
# change the path to match your log-login settings.

/var/log/yourls.log {
        rotate 52
        create 640 www-data adm

For the public interface read these:

You need to move the file sample-public-front-page.txt to index.php and add the recaptcha code, follow the tutorial below
Read and follow the instructions:

Public Page with recaptcha GOOGLE

An alternative to Google reCaptcha would be securImage ( it generates captcha and you can easily integrate it in any of your programs. It is licensed under BSD. We will now implement it to our public interface, you need to remove all google recaptcha code, if you implemented it earlier.

Download the source code at :
or clone the git site:

$ git clone --depth 1 ''
Copy the folder to your root website directory (eg. /var/www/)
 $ sudo cp -R securimage /var/www/
 $ sudo chown -R www-data:www-data /var/www/securimage

We now need to edit the public interface file and add the following:

add this below <?php


add the following after the require_once (dirname(__FILE__)…..

include_once $_SERVER['DOCUMENT_ROOT'] . '/securimage/securimage.php';
$securimage = new Securimage();

add below: // Part to be executed if FORM has been submitted

if ($securimage->check($_REQUEST['captcha_code']) == true) {

add below: $status¬†¬† = isset( $return[‘status’] ) ? $return[‘status’] : ”;


add after: echo “<script>init_clipboard();</script>\n”;

else { //if url shortening failed it may because of invalid captcha or other

add below: <p><label>Optional title: <input type=”text” class=”text” name=”title” /></label></p>

<img id="captcha" src="/securimage/securimage_show.php" alt="CAPTCHA Image" />
<p><input type="text" name="captcha_code" size="10" maxlength="6" /></p>

Restart lighttpd and try it out.

You need to remove some examples in the secureimage folder if you cloned the git repo otherwise you are ready to go. Enjoy Google-less tracking.

Here is the interface of YOURLS after implementing securimage. This is the basic implementation, I did not include the audio captcha or refresh captcha image.



Admin page to administer links created from public API

Except where otherwise noted, this work is licensed under Creative Commons Attribution-ShareAlike 4.0 International License (
I hope that this post is useful to you, if you liked this post you may support me via liberapay. Thank you for your support.

Donate using Liberapay