Introduction
Polr is a free and open-source link shortener written in PHP and powered by the Lumen framework. It allows you to host your URL shortener and to gain control over your data. Its significant features include a management dashboard, detailed link analytics, and a robust API.
This tutorial guides you through the process of installing Polr on Ubuntu 20.04 LTS and setting up HTTPS with a free Let's Encrypt TLS certificate.
Prerequisites
- A Ubuntu 20.04 server.
- Follow Rcs's best practices guides to create a sudo user and update the Ubuntu server.
- (Optional) Configure the Ubuntu firewall with ports 80, 443, and 22 open.
This tutorial assumes you own a domain name such as example.com, and you have pointed it to the server IP address. If not, replace example.com with the server IP address.
Make sure to replace example.com in the code examples with your domain name or IP address.
1. Install PHP
At the time of this writing, the latest version of PHP compatible with Polr is 7.3. But, the official Ubuntu 20.04 repositories only offer PHP 7.4. Therefore, you must use another 3rd-party repository to install PHP 7.3.
ppa:ondrej/php is an Ubuntu repository developed by Ondřej Surý, a long-time Debian developer. It offers both PHP 5.6, PHP 7.0 – 7.4, and PHP 8.0. You can install PHP 7.3 now, and when Polr supports newer PHP versions, you can also install them.
Log in to the server as a non-root sudo user via SSH.
Add the
ppa:ondrej/phprepository.$ sudo LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/phpInstall PHP-FPM and other necessary PHP extensions.
$ sudo apt -y install php7.3-cli php7.3-common php7.3-curl php7.3-fpm php7.3-json php7.3-mbstring php7.3-mysql php7.3-xmlList all the time zones that your Ubuntu system supports. Use the Up / Down keys to move through the list, and press Q to exit.
$ timedatectl list-timezonesCopy an appropriate time zone from the list, for example, America/New_York. Then update your Ubuntu system with that time zone.
$ sudo timedatectl set-timezone America/New_YorkEdit the main PHP configuration file to tell PHP to use the new time zone. This tutorial uses
nanoas the editor, but you can use another editor such asvim.$ sudo nano /etc/php/7.3/fpm/php.iniFind the line
;date.timezone =. Remove the semicolon and add your time zone. For example:date.timezone = America/New_YorkSave the configuration file and exit.
To enhance the security of your server, create a dedicated user named
polras the user/group of PHP-FPM processes for Polr. This user also owns the Polr source code files/folders.$ sudo adduser polrEvery time you want to add, delete, or update the source code files/folders, you need to switch to this user.
Create the PHP-FPM configuration file from the default one.
$ sudo cp /etc/php/7.3/fpm/pool.d/www.conf /etc/php/7.3/fpm/pool.d/polr.confRename the default file to disable it and keep it as a backup.
$ sudo mv /etc/php/7.3/fpm/pool.d/www.conf /etc/php/7.3/fpm/pool.d/www.conf.defaultEdit the PHP-FPM configuration file.
$ sudo nano /etc/php/7.3/fpm/pool.d/polr.confIn the configuration file, any line starting with
;is a comment.Search for the following settings, then:
- Replace
[www]with[polr] - Replace
user = www-datawithuser = polr - Replace
group = www-datawithgroup = polr(do not touch thelisten.group = www-datasetting)
Make sure the
listen = /run/php/php7.3-fpm.socksetting does not start with;. This setting makes PHP-FPM listen on a Unix socket specified by the/run/php/php7.3-fpm.sockfile.- Replace
Copy and paste the following settings to the end of the file.
catch_workers_output = yes php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php/polr/error.log php_admin_flag[log_errors] = on php_admin_value[session.save_path] = /var/lib/php/session.polrThose settings make PHP-FPM log error messages to the
/var/log/fpm-php/polr/error.logfile instead of displaying them to website users and store session data in the/var/lib/php/session.polrfolder.Save the configuration file and exit.
Create two folders to store PHP logs and session data.
$ sudo mkdir -p /var/log/fpm-php/polr $ sudo mkdir -p /var/lib/php/session.polrUpdate the ownership and permissions of the two folders so that only the PHP-FPM processes of Polr can write to them.
$ sudo chown polr:polr /var/log/fpm-php/polr $ sudo chmod 700 /var/log/fpm-php/polr $ sudo chown polr:polr /var/lib/php/session.polr $ sudo chmod 700 /var/lib/php/session.polrCheck the new configuration.
$ sudo php-fpm7.3 -tRestart the PHP-FPM service for the changes to take effect.
$ sudo systemctl restart php7.3-fpm.service
2. Install MySQL
The minimum version of MySQL supported by Polr is 5.5. However, you can install MySQL version 8.0 from the official Ubuntu 20.04 repositories to fulfill this requirement.
$ sudo apt -y install mysql-serverRun the
mysql_secure_installationscript to enhance the security of MySQL.$ sudo mysql_secure_installationTo enforce strong passwords, press Y and Enter to set up the
VALIDATE PASSWORDcomponent. Then press 1 and Enter to select theMEDIUMpassword policy, which is secure enough.With this policy, MySQL requires all passwords to includes numeric, mixed case, and special characters. You can use a free password manager like KeePassXC or an online tool such as Random Password Generator to generate strong passwords.
Enter a strong password twice for the MySQL
rootuser. Then press Y and Enter to confirm.Press Y and Enter for any remaining questions to accept the recommended options.
Connect to the MySQL command line as the MySQL
rootuser.$ sudo mysql -u rootCreate a MySQL database named polr for Polr.
mysql> CREATE DATABASE polr CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Create a MySQL user named polr for Polr. Replace password with a strong password.
mysql> CREATE USER 'polr'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; mysql> GRANT ALL PRIVILEGES ON polr.* TO 'polr'@'localhost'; mysql> FLUSH PRIVILEGES;Exit the MySQL command line.
mysql> exit
3. Install Polr
Download the Source Code
Retrieve the code from GitHub.
$ cd ~ && wget https://github.com/cydrobolt/polr/archive/refs/tags/2.3.0b.zipAt the time of this writing, the latest stable version of Polr is 2.3.0b. Of course, you can always visit the Polr releases page on GitHub to get the latest version.
Install the
unzippackage to extract the archive.$ sudo apt -y install unzipExtract the archive.
$ unzip 2.3.0b.zipSet
polras the owner of the source code folder.$ sudo chown -R polr:polr polr*Move the source code folder to
/var/www/polrbecause, traditionally, the source code folders of websites are in the/var/wwwfolder.$ sudo mkdir /var/www $ sudo mv polr* /var/www/polr
Install Dependencies
Polr requires Composer, the PHP dependency manager, to manage its dependencies.
Install Composer with the following command.
$ cd ~ && curl -sS https://getcomposer.org/installer | phpMake the
composercommand globally available.$ sudo mv composer.phar /usr/local/bin/composerSwitch to the
polruser before installing Polr dependencies.$ sudo su polrInstall dependencies with Composer.
$ cd /var/www/polr && composer install --no-dev -oCopy the provided configuration file to enable the web-based installer.
$ cp .env.setup .envSwitch back to the sudo user to continue with the setup.
$ exit
4. Install Nginx
Install Nginx with the following command.
$ sudo apt -y install nginxDisable the default configuration.
$ sudo rm /etc/nginx/sites-enabled/defaultCreate a new configuration file for Polr.
$ sudo nano /etc/nginx/sites-available/polr-http.confPaste the following contents:
server { listen 80; listen [::]:80; server_name example.com; root /var/www/polr/public; index index.html index.php; # All URLs are processed by index.php location / { try_files $uri $uri/ /index.php$is_args$args; } # Pass PHP files to PHP-FPM listening on /run/php/php7.3-fpm.sock location ~ \.php$ { try_files $uri =404; # Mitigate https://httpoxy.org/ vulnerabilities fastcgi_param HTTP_PROXY ""; fastcgi_pass unix:/run/php/php7.3-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } # Set expiration of assets to MAX for caching location ~* \.(jpg|jpeg|gif|png|css|js|ico|svg|eot|ttf|woff|woff2|otf)$ { expires max; log_not_found off; } }Save the configuration file and exit.
Enable the new configuration.
$ sudo ln -s /etc/nginx/sites-available/polr-http.conf /etc/nginx/sites-enabled/polr-http.confAdd the
www-datauser to thepolrgroup so that Nginx processes can access the Polr source code folder.$ sudo usermod -aG polr www-dataCheck the new configuration.
$ sudo nginx -tReload the Nginx service for the changes to take effect.
$ sudo systemctl reload nginx.service
5. (Optional) Configure HTTPS
If you own a valid domain name, you can set up HTTPS for your Polr at no cost. Using the Certbot program, you can get a free TLS certificate from Let's Encrypt, a certificate authority.
Install Certbot with Snap
Snap Store is an app store for Linux with millions of users. Ubuntu has built-in Snap Store support that makes it easy to get the latest version of Certbot with features like automatic certificate renewal.
$ sudo snap install --classic certbotMake the certbot command globally available.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbotGet a Let's Encrypt Certificate
Rename the HTTP configuration file to make it the template for the HTTPS configuration file.
$ sudo mv /etc/nginx/sites-available/polr-http.conf /etc/nginx/sites-available/polr-https.confCreate a new configuration file to serve HTTP requests.
$ sudo nano /etc/nginx/sites-available/polr-http.confPaste the following contents:
server { listen 80; listen [::]:80; server_name example.com; root /var/www/polr/public; location / { return 301 https://$server_name$request_uri; } location /.well-known/acme-challenge/ {} }This configuration makes Nginx redirect all HTTP requests, except those from Let's Encrypt, to corresponding HTTPS requests.
Save the configuration file and exit. Then check the Nginx configuration.
$ sudo nginx -tApply the new configuration.
$ sudo systemctl reload nginx.serviceRun the following command to get the Let's Encrypt certificate.
$ sudo certbot certonly --webroot -w /var/www/polr/public -d example.com -m admin@example.com --agree-tosYou may need to answer a question about sharing your email with the Electronic Frontier Foundation.
When finished, certbot tells you the path of your certificate file and key file:
/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pemAnother critical file, located in the same folder, also needed for the next step, is chain.pem.
Install the Certificate with Nginx
Generate a file with DH parameters for DHE ciphers.
$ sudo openssl dhparam -out /etc/nginx/dhparam.pem 20482048 is the recommended size of DH parameters. This process may take a while, so please be patient.
Update the HTTPS configuration file.
$ sudo nano /etc/nginx/sites-available/polr-https.confFind the following lines:
listen 80; listen [::]:80;Replace them with:
listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; # about 40000 sessions # DH parameters file ssl_dhparam /etc/nginx/dhparam.pem; # intermediate configuration ssl_protocols TLSv1.2; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # HSTS (ngx_http_headers_module is required) (63072000 seconds) # # Uncomment the following line only if your website fully supports HTTPS # and you have no intention of going back to HTTP, otherwise, it will # break your site. # # add_header Strict-Transport-Security "max-age=63072000" always; # OCSP stapling ssl_stapling on; ssl_stapling_verify on; # verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem; # Use Cloudflare DNS resolver resolver 1.1.1.1;Save the configuration file and exit.
Enable the new configuration.
$ sudo ln -s /etc/nginx/sites-available/polr-https.conf /etc/nginx/sites-enabled/polr-https.confCheck the Nginx configuration.
$ sudo nginx -tApply the new configuration.
$ sudo systemctl reload nginx.service
Automate Renewal
Let's Encrypt certificates are valid for 90 days, so you must renew your TLS certificate at least once every three months. The Certbot installation automatically created a systemd timer unit to automate this task.
Run the following command to verify the timer is active.
$ sudo systemctl list-timers | grep 'certbot\|ACTIVATES'After renewing the certificate, Certbot will not automatically reload Nginx, so Nginx still uses the old certificate. Instead, you must write a script inside the
/etc/letsencrypt/renewal-hooks/deployfolder to reload Nginx.Open your text editor.
$ sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shPaste the following contents:
#!/bin/bash /usr/bin/systemctl reload nginx.serviceSave and exit.
Make the script executable.
$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shTest the renewal process with a dry run.
$ sudo certbot renew --dry-run
This Rcs article explains all the above steps in more detail. This kind of TLS setup gives you an A on the SSL Labs test.
6. Complete the Polr Setup
Restart the server.
$ sudo rebootWait a moment for the system to boot, then open the http://example.com link in your browser.

The Setup screen appears with many settings. Here are the fundamental ones:
- Database Username: enter polr
- Database Password: enter the database password you created in step 2
- Database Name: enter polr
- Application Protocol: enter https:// if you have set up HTTPS in step 5. If not, enter http://
- Application URL: enter example.com
- Shortening Permissions: choose between Anyone can shorten URLs and Only logged in users may shorten URLs
- Admin Username: enter a desired name
- Admin Password: enter a strong password
For the remaining settings, customize them to fit your specific needs or accept their default values.
Click the Install button at the bottom of the screen to start the installation. When finished, Polr redirects you to the Setup Complete screen.
Behind the scenes, Polr has just saved all the settings in the /var/www/polr/.env configuration file. If you have programming experience, you can edit this file to change the settings as needed.
Your Polr website is now ready. You may log in or access the home page to create shortened links.