Troubleshooting

These are some common issues that people have reported when using Shlink, together with questions that people ask with a higher frequency.

How do I change config options after installing Shlink.

When you install Shlink using the installation tool, you will be able to easily provide all the config options.

However, sometimes you need to change some of those params later in time.

In order to do that, you can simply use the vendor/bin/shlink-installer set-option script to change the value for any config option.

If that script fails, it could mean you are using a too old Shlink version. In that case, follow these steps:

  • Make a backup of the generated config file (config/params/generated_config.php).
  • Open that same file, locate the config option you want to change, and set the new value.
  • Delete the config cache file (data/cache/app_config.php). If the file does not exist, skip this step.

The generated config file is in PHP format, but it’s a relatively straightforward options “map”.

If you are not sure which option should be changed, feel free to open an issue asking for help.

If Shlink does not work after changing the config, restore the backup you did in first step.

BadMethodCallException: Undefined method ‘methodName’

If you have recently updated Shlink, it could include some new code that is not picked due to in-memory caches.

Try restarting apache/nginx/php-fpm services. It should solve the problem.

How to install Shlink on a shared hosting

First, shared hosting is not the main target env for Shlink. The goal of the project is to provide a cloud-native and cloud-friendly solution to self-host a URL shortener.

There are other projects which play better with shared hosting. Try googling “self-hosted URL shortener”.

That said, there are ways to get Shlink working.

  • Some shared hosting services provide SSH access to the document root’s parent folder. If that’s the case, upload Shlink there, and then rename the public folder to whatever name your service provider is using for the document root.
  • If you only have access to the document root, upload the project there, and then copy everything inside the public folder to the project’s root. Sadly, this makes all other folders accessible. It’s highly recommended that you deny access to them if you shared hosting provider allows it, for example, using .htaccess files.

In any case, you will need to have some kind of shell access in order to run the installation tool.

I renamed Shlink’s folder, and now nothing works

Shlink does not directly depend on the name of the folder, it’s perfectly fine to rename it and continue working.

However, Shlink generates a cached config file that resolves absolute paths. That makes file paths defined on it to still point to the old folder name, making Shlink unusable.

The solution is to just delete that file, data/cache/app_config.php. After that, Shlink will regenerate it with the new folder name where needed.

When trying to install or update Shlink, I see “PHP Parse error: syntax error”

It’s relatively frequent that servers have many PHP versions coexisting, being one of them the default one.

Sometimes, you think you are using the latest version required by Shlink, because that’s what you see with phpinfo() executed on a web request.

However, when running the install or update scripts you see syntax errors.

When this happens, it is because you are running an older PHP version from the CLI. Run php -v to see the actual version being used.

Shlink cannot be accessed from shlink-web-client or other web clients

Sometimes, after setting up Shlink and verifying it works from the command line, and you can create and visit short URLs, you try to get it configured on a web client like shlink-web-client, only to realize it fails to connect, displaying an error page.

In most of the cases, this is due to one of these other two issues:

In order to find out which is the actual root cause, you will have to open the browser’s developer console, which will most probably display one of the errors above.

These are the instructions to open it on the most popular web browsers:

Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present

Shlink generates all the CORS headers required to consume it from a web app running on different domains, including Access-Control-Allow-Origin.

It also handles transparently the preflight (OPTIONS) requests (See more info on the topic).

When the error above happens when consuming Shlink from shlink-web-client or any other web client running on a different URL, that’s because some element in between is dropping the CORS headers or blocking the OPTIONS requests.

The most frequent candidate is some reversed proxy with strict security rules. You need to make sure any reverse proxy in front of your Shlink instance returns transparently all the headers generated by Shlink.

Another scenario in which this could happen is when accessing Shlink from a web client which was accessed through IP address instead of hostname. This scenario is fixed after Shlink 2.5.2, but could also be the cause when using previous versions.

I see “Mixed Content” errors in the browser’s console

Many browsers (like Google Chrome on its latest versions) do not allow requests to http endpoints from web apps that were served with https.

If you are trying to access a Shlink instance which is served with http (no encryption) from the default shlink-web-client at https://app.shlink.io or any other web client which is served with https, you will see those errors.

It is highly recommended that you serve Shlink with https to solve this problem, but instead, you can make sure the web client is also served with http.

Short URLs work, but I can’t consume Shlink from shlink-web-client

See Shlink cannot be accessed from shlink-web-client or other web clients

URLs on non-default domains result in 404 errors

In order to properly resolve short URLs when they use a non-default domain, Shlink needs to know what’s the host to which the request was made.

If you have a reverse proxy in front of Shlink, make sure to forward the hostname in the Host header.

For example when using nginx as a reverse proxy, use the proxy_set_header Host $host; instruction.

You can also get detailed info on how to expose Shlink through a reverse proxy.

My visits location is always unknown

There are two main reasons for the visits to never get located:

  • You are serving Shlink with a classic web server (like nginx or apache) and didn’t schedule the task that processes the visits.
  • You didn’t provide your own GeoLite2 license key.

When the second happens, Shlink falls back to the default license key. The problem is that this key is used by too many people, and the daily download limit is always hit.

Using your own GeoLite2 license key is currently considered mandatory. Follow the instructions to get it.

Real-time updates never get triggered

First, real-time updates are only triggered when serving Shlink with RoadRunner (or when using the docker image, which uses RoadRunner internally), and they will never work if you serve it with a classic web server.

Second, real-time updates are triggered after a visit has been located. Because of this, the issue described in previous point can also result in the updates never getting triggered.

For example, if you do not provide your own GeoLite2 license key and the default one already reached the limit, you will never get your first GeoLite2 db file, never being able to locate visits, and finally, never getting the real-time updates triggered.

Follow the instructions to provide your own GeoLite2 license key.

What are the minimum grants required for the database user when using MySQL/Mariadb

The database user you provide to Shlink will need to have at least these grants: ALTER, CREATE, DROP, INDEX, LOCK TABLES, REFERENCES, SELECT, INSERT, DELETE and UPDATE.

How to keep data on docker image between container recreations

Shlink’s docker image comes with a SQLite database inside it. This database is intended just for testing and experimentation purposes.

As soon as you plan to use Shlink in production, you should always use an external database, as that’s the only way to ensure you will not loose any data if the container gets killed.

Some people have tried to mount the SQLite database file in a volume, but that is not possible see this comment to understand why.

Shlink’s docker image does not listen to 443/https traffic

Yes, that’s right. Handling the https certificate is out of Shlink’s scope.

The recommendation is to put a reverse proxy that provides this capability in front of Shlink.

Follow these instructions in order to know how to expose Shlink through a reverse proxy.

Troubleshoot errors when booting-up the docker image

Sometimes, when running Shlink’s docker image, the container may fail to boot-up, without a clear or obvious reason.

A good way to troubleshoot this is by providing the env var SHELL_VERBOSITY=3, that will increase verbosity of the image’s entry point.

Subscription from shlink-web-client to mercure fails with “Response to preflight request doesn’t pass access control check”

If you are serving your mercure instance on a host different from the one where you serve shlink-web-client (which is most probably the case), you need to ensure mercure allows the client’s host.

For mercure older than v0.11, that’s done via the CORS_ALLOWED_ORIGINS env var, which can have the "*" value, or the explicit domain of your web client.

For mercure v0.11 or newer, you need to pass the MERCURE_EXTRA_DIRECTIVES env var, with value cors_origins https://my-web-client.com. This versions no longer allows the "*" value.

Error writing to config/params/generated_config.php during installation

Shlink’s installation tool does a couple of things. One of them is writing a config file with provided options.

A common mistake is running the installation tool from the wrong directory, which results on the generated config file’s path not being found, which triggers an error like this:

Error writing to "config/params/generated_config.php": file_put_contents(config/params/generated_config.php): Failed to open stream: No such file or directory.

In order to solve this, make sure the working directory when running the installation tool, is always Shlink’s root folder.