30 KiB
CHANGELOG
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[5.0.1] - 2026-03-04
Added
- Nothing
Changed
- #2573 Update to PHPUnit 13
- #2579 Update docker images to Alpine 3.22, to address CVE-2025-15467
Deprecated
- Nothing
Removed
- Nothing
Fixed
- Nothing
[5.0.0] - 2026-01-09
Added
-
#2431 Add new date-based conditions for the dynamic rules redirections system, that allow to perform redirections based on an ISO-8601 date value.
before-date: matches when current date and time is earlier than the defined threshold.after-date: matches when current date and time is later than the defined threshold.
-
#2513 Add support for redis connections via unix socket (e.g.
REDIS_SERVERS=unix:/path/to/redis.sock). -
Visits generated in the command line can now be formatted in CSV, via
--format=csv.
Changed
-
#2522 Shlink no longer tries to detect trusted proxies automatically, when resolving the visitor's IP address, as this is a potential security issue.
Instead, if you have more than 1 proxy in front of Shlink, you should provide
TRUSTED_PROXIESenv var, with either a comma-separated list of the IP addresses of your proxies, or a number indicating how many proxies are there in front of Shlink. -
#2311 All visits-related commands now return more information, and columns are arranged slightly differently.
Among other things, they now always return the type of the visit, region, visited URL, redirected URL and whether the visit comes from a potential bot or not.
-
#2540 Update Symfony packages to 8.0.
-
#2512 Make all remaining console commands invokable.
Deprecated
- Nothing
Removed
- #2507 Drop support for PHP 8.3.
- #2514 Remove support to generate QR codes. This functionality is now handled by Shlink Web Client and Shlink Dashboard.
- #2517 Remove
REDIRECT_APPEND_EXTRA_PATHenv var. UseREDIRECT_EXTRA_PATH_MODE=appendinstead. - #2519 Disabling API keys by their plain-text key is no longer supported. When calling
api-key:disable, the first argument is now always assumed to be the name. - #2520 Remove deprecated
--including-all-tagsand--show-api-key-nameoptions fromshort-url:listcommand. Use--tags-alland--show-api-keyinstead. - #2521 Remove deprecated
--tagsoption in all commands using it. Use--tagmultiple times instead, one per tag. - #2543 Remove support for
--order-by=field,diroptionshort-url:listcommand. Use--order-by=field-dirinstead. - Remove support to provide redis database index via URI path. Use
?database=3query instead. - #2565 Remove explicit dependency in ext-json, since it's part of PHP since v8.0
Fixed
-
#2564 Fix error when trying to persist non-utf-8 title without being able to determine its original charset for parsing.
Now, when resolving a website's charset, two improvements have been introduced:
- If the
Content-Typeheader does not define the charset, we fall back to<meta charset>or<meta http-equiv="Content-Type">. - If it's still not possible to determine the charset, we ignore the auto-resolved title, to avoid other encoding errors further down the line.
- If the
[4.6.0] - 2025-11-01
Added
-
#2327 Allow filtering short URL lists by those not including certain tags.
Now, the
GET /short-urlsendpoint accepts two new params:excludeTags, which is an array of strings with the tags that should not be included, andexcludeTagsMode, which accepts the valuesanyandall, and determines if short URLs should be filtered out if they contain any of the excluded tags, or all the excluded tags.Additionally, the
short-url:listcommand also supports the same feature via--exclude-tagoption, which requires a value and can be provided multiple times, and--exclude-tags-all, which does not expect a value and determines if the mode should beall, orany. -
#2192 Allow filtering short URL lists by the API key that was used to create them.
Now, the
GET /short-urlsendpoint accepts a newapiKeyNameparam, which is ignored if the request is performed with a non-admin API key which name does not match the one provided here.Additionally, the
short-url:listcommand also supports the same feature via the--api-key-nameoption. -
#2330 Add support to serve Shlink with FrankenPHP, by providing a worker script in
bin/frankenphp-worker.php. -
#2449 Add support to provide redis credentials separately when using redis sentinels, where provided servers are the sentinels and not the redis instances.
For this, Shlink supports two new env ras / config options, as
REDIS_SERVERS_USERandREDIS_SERVERS_PASSWORD. -
#2498 Allow orphan visits, non-orphan visits and tag visits lists to be filtered by domain.
This is done via the
domainquery parameter in API endpoints, and via the--domainoption in console commands. -
#2472 Add support for PHP 8.5
-
#2291 Add
api-key:deleteconsole command to delete API keys.
Changed
- #2424 Make simple console commands invokable.
Deprecated
- Nothing
Removed
- Nothing
Fixed
- Nothing
[4.5.3] - 2025-10-10
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2488 Ensure
Access-Control-Allow-Credentialsis set in all cross-origin responses whenCORS_ALLOW_ORIGIN=true.
[4.5.2] - 2025-08-27
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2433 Try to mitigate memory leaks allowing RoadRunner to garbage collect memory after every request and every job, by setting
GC_COLLECT_CYCLES=true.
[4.5.1] - 2025-08-24
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2433 Try to mitigate memory leaks by restarting job and http workers every 250 executions when using RoadRunner.
[4.5.0] - 2025-07-24
Added
-
#2438 Add
MERCURE_ENABLEDenv var and corresponding config option, to more easily allow the mercure integration to be toggled.For BC, if this env var is not present, we'll still consider the integration enabled if the
MERCURE_PUBLIC_HUB_URLenv var has a value. This is considered deprecated though, and next major version will rely only onMERCURE_ENABLED, so if you are using Mercure, make sure to setMERCURE_ENABLED=trueto be ready. -
#2387 Add
REAL_TIME_UPDATES_TOPICSenv var and corresponding config option, to granularly decide which real-time updates topics should be enabled. -
#2418 Add more granular control over how Shlink handles CORS. It is now possible to customize the
Access-Control-Allow-Origin,Access-Control-Max-AgeandAccess-Control-Allow-Credentialsheaders via env vars or config options. -
#2386 Add new
any-value-query-paramandvalueless-query-paramredirect rule conditions.These new rules expand the existing
query-param, which requires both a specific non-empty value in order to match the condition.The new conditions match as soon as a query param exists with any or no value (in the case of
any-value-query-param), or if a query param exists with no value at all (in the case ofvalueless-query-param). -
#2360 Add
TRUSTED_PROXIESenv var and corresponding config option, to configure a comma-separated list of all the proxies in front of Shlink, or simply the amount of trusted proxies in front of Shlink.This is important to properly detect visitor's IP addresses instead of incorrectly matching one of the proxy's IP address, and if provided, it disables a workaround introduced in https://github.com/shlinkio/shlink/pull/2359.
-
#2274 Add more supported device types for the
deviceredirect condition:linux: Will match desktop devices with Linux.windows: Will match desktop devices with Windows.macos: Will match desktop devices with MacOS.chromeos: Will match desktop devices with ChromeOS.mobile: Will match any mobile devices with either Android or iOS.
-
#2093 Add
REDIRECT_CACHE_LIFETIMEenv var and corresponding config option, so that it is possible to set theCache-Controlvisibility directive (publicorprivate) when theREDIRECT_STATUS_CODEhas been set to301or308. -
#2323 Add
LOGS_FORMATenv var and corresponding config option, to allow the logs generated by Shlink to be in console or JSON formats.
Changed
- #2406 Remove references to bootstrap from error templates, and instead inline the very minimum required styles.
Deprecated
- #2408 Generating QR codes via
/{short-code}/qr-codeis now deprecated and will be removed in Shlink 5.0. Use the equivalent capability from web clients instead.
Removed
- Nothing
Fixed
- Nothing
[4.4.6] - 2025-03-20
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2391 When sending visits to Matomo, send the country code, not the country name.
- Fix error with new option introduced by
endroid/qr-code6.0.4.
[4.4.5] - 2025-03-01
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
-
#2373 Ensure deprecation warnings do not end up escalated to
ErrorExceptions byProblemDetailsMiddleware.In order to do this, Shlink will entirely ignore deprecation warnings when running in production, as those do not mean something is not working, but only that something will break in future versions.
[4.4.4] - 2025-02-19
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2366 Fix error "Cannot use 'SCRIPT' with redis-cluster" thrown when creating a lock while using a redis cluster.
- #2368 Fix error when listing non-orphan visits using API key with
AUTHORED_SHORT_URLSrole.
[4.4.3] - 2025-02-15
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
-
#2351 Fix visitor IP address resolution when Shlink is served behind more than one reverse proxy.
This regression was introduced due to a change in behavior in
akrabat/rka-ip-address-middleware, that now picks the first address from the right after excluding all trusted proxies.Since Shlink does not set trusted proxies, this means the first IP from the right is now picked instead of the first from the left, so we now reverse the list before trying to resolve the IP.
In the future, Shlink will allow you to define trusted proxies, to avoid other potential side effects because of this reversing of the list.
-
#2354 Fix error "NOSCRIPT No matching script. Please use EVAL" thrown when creating a lock in redis.
-
#2319 Fix unique index for
short_codeanddomain_idinshort_urlstable not being used in Microsoft SQL engines for rows wheredomain_idisnull.
[4.4.2] - 2025-01-29
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2346 Get back docker images for ARM architectures.
[4.4.1] - 2025-01-28
Added
- #2331 Add
ADDRESSenv var which allows to customize the IP address to which RoadRunner binds, when using the official docker image.
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2341 Ensure all asynchronous jobs that interact with the database do not leave idle connections open.
- #2334 Improve how page titles are encoded to UTF-8, falling back from mbstring to iconv if available, and ultimately using the original title in case of error, but never causing the short URL creation to fail.
[4.4.0] - 2024-12-27
Added
-
#2265 Add a new
REDIRECT_EXTRA_PATH_MODEoption that accepts three values:default: Short URLs only match if the path matches their short code or custom slug.append: Short URLs are matched as soon as the path starts with the short code or custom slug, and the extra path is appended to the long URL before redirecting.ignore: Short URLs are matched as soon as the path starts with the short code or custom slug, and the extra path is ignored.
This option effectively replaces the old
REDIRECT_APPEND_EXTRA_PATHoption, which is now deprecated and will be removed in Shlink 5.0.0 -
#2156 Be less restrictive on what characters are disallowed in custom slugs.
All URI-reserved characters were disallowed up until now, but from now on, only the gen-delimiters are.
-
#2229 Add
logo=disabledquery param to dynamically disable the default logo on QR codes. -
#2206 Add new
DB_USE_ENCRYPTIONconfig option to enable SSL database connections trusting any server certificate. -
#2209 Redirect rules are now imported when importing short URLs from a Shlink >=4.0 instance.
Changed
-
#2281 Update docker image to PHP 8.4
-
#2124 Improve how Shlink decides if a GeoLite db file needs to be downloaded, and reduces the chances for API limits to be reached.
Now Shlink tracks all download attempts, and knows which of them failed and succeeded. This lets it know when was the last error or success, how many consecutive errors have happened, etc.
It also tracks now the reason for a download to be attempted, and the error that happened when one fails.
Deprecated
- Nothing
Removed
- #2247 Drop support for PHP 8.2
Fixed
- Nothing
[4.3.1] - 2024-11-25
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2285 Fix performance degradation when using Microsoft SQL due to incorrect order of columns in
unique_short_code_plus_domainindex.
[4.3.0] - 2024-11-24
Added
-
#2159 Add support for PHP 8.4.
-
#2207 Add
hasRedirectRulesflag to short URL API model. This flag tells if a specific short URL has any redirect rules attached to it. -
#1520 Allow short URLs list to be filtered by
domain.This change applies both to the
GET /short-urlsendpoint, via thedomainquery parameter, and theshort-url:listconsole command, via the--domain|-dflag. -
#1774 Add new geolocation redirect rules for the dynamic redirects system.
geolocation-country-code: Allows to perform redirections based on the ISO 3166-1 alpha-2 two-letter country code resolved while geolocating the visitor.geolocation-city-name: Allows to perform redirections based on the city name resolved while geolocating the visitor.
-
#2032 Save the URL to which a visitor is redirected when a visit is tracked.
The value is exposed in the API as a new
redirectUrlfield for visit objects.This is useful to know where a visitor was redirected for a short URL with dynamic redirect rules, for special redirects, or simply in case the long URL was changed over time, and you still want to know where visitors were redirected originally.
Some visits may not have a redirect URL if a redirect didn't happen, like for orphan visits when no special redirects are configured, or when a visit is tracked as part of the pixel action.
Changed
-
#2193 API keys are now hashed using SHA256, instead of being saved in plain text.
As a side effect, API key names have now become more important, and are considered unique.
When people update to this Shlink version, existing API keys will be hashed for everything to continue working.
In order to avoid data to be lost, plain-text keys will be written in the
namefield, either together with any existing name, or as the name itself. Then users are responsible for renaming them using the newapi-key:renamecommand.For newly created API keys, it is recommended to provide a name, but if not provided, a name will be generated from a redacted version of the new API key.
-
Update to Shlink PHP coding standard 2.4
-
Update to
hidehalo/nanoid-php2.0 -
Update to PHPStan 2.0
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2264 Fix visits counts not being deleted when deleting short URL or orphan visits.
[4.2.5] - 2024-11-03
Added
- Nothing
Changed
- Update to Shlink PHP coding standard 2.4
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2244 Fix integration with Redis 7.4 and Valkey.
[4.2.4] - 2024-10-27
Added
- Nothing
Changed
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2232 Run RoadRunner in docker with
execto ensure signals are properly handled.
[4.2.3] - 2024-10-17
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2225 Fix regression introduced in v4.2.2, making config options with
nullvalue to be promoted as env vars with value'', instead of being skipped.
[4.2.2] - 2024-10-14
Added
- Nothing
Changed
- #2208 Explicitly promote installer config options as env vars, instead of as a side effect of loading the app config.
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2213 Fix spaces being replaced with underscores in query parameter names, when forwarded from short URL to long URL.
- #2217 Fix docker image tag suffix being leaked to the version set inside Shlink, producing invalid SemVer version patterns.
- #2212 Fix env vars read in docker entry point not properly falling back to their
_FILEsuffixed counterpart.
[4.2.1] - 2024-10-04
Added
- #2183 Redis database index to be used can now be specified in the connection URI path, and Shlink will honor it.
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2201 Fix
MEMORY_LIMIToption being ignored when provided via installer options.
[4.2.0] - 2024-08-11
Added
-
#2120 Add new IP address condition for the dynamic rules redirections system.
The conditions allow you to define IP addresses to match as static IP (1.2.3.4), CIDR block (192.168.1.0/24) or wildcard pattern (1.2.*.*).
-
#2018 Add option to allow all short URLs to be unconditionally crawlable in robots.txt, via
ROBOTS_ALLOW_ALL_SHORT_URLS=trueenv var, or config option. -
#2109 Add option to customize user agents robots.txt, via
ROBOTS_USER_AGENTS=foo,bar,bazenv var, or config option. -
#2163 Add
short-urls:editcommand to edit existing short URLs.This brings CLI and API interfaces capabilities closer, and solves an overlook since the feature was implemented years ago.
-
#2164 Add missing
--titleoption toshort-url:createandshort-url:editcommands.
Changed
- #2096 Update to RoadRunner 2024.
Deprecated
- Nothing
Removed
- Nothing
Fixed
- Nothing
[4.1.1] - 2024-05-23
Added
- Nothing
Changed
- Use new reusable workflow to publish docker image
- #2015 Update to PHPUnit 11.
- #2130 Replace deprecated
pugx/shortid-phppackage withhidehalo/nanoid-php.
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2111 Fix typo in OAS docs examples where redirect rules with
query-paramcondition type were defined asquery. - #2129 Fix error when resolving title for sites not using UTF-8 charset (detected with Japanese charsets).
[4.1.0] - 2024-04-14
Added
-
#1330 All visit-related endpoints now expose the
visitedUrlprop for any visit.Previously, this was exposed only for orphan visits, since this can be an arbitrary value for those.
-
#2077 When sending visits to Matomo, the short URL title is now used as document title in matomo.
-
#2059 Add new
short-url:delete-expiredcommand that can be used to programmatically delete expired short URLs.Expired short URLs are those that have a
validUntildate in the past, or optionally, that have reached the max amount of visits.This command can be run periodically by those who create many disposable URLs which are valid only for a period of time, and then can be deleted to save space.
-
#1925 Add new
integration:matomo:send-visitsconsole command that can be used to send existing visits to integrated Matomo instance. -
#2087 Allow
memory_limitto be configured via the newMEMORY_LIMITenv var or configuration option.
Changed
-
#2034 Modernize entities, using constructor property promotion and readonly wherever possible.
-
#2036 Deep performance improvement in some endpoints which involve counting visits:
- listing short URLs ordered by visits counts.
- loading tags with stats.
- visits overview.
This has been achieved by introducing a new table which tracks slotted visits counts. We can then
SUMall counts for certain short URL, avoidingCOUNT(visits)aggregates which are much less performant when there are a lot of visits. -
#2049 Request ID is now propagated to the background tasks/jobs scheduled during a request.
This allows for a better traceability, as the logs generated during those jobs will have a matching UUID as the logs generated during the request the triggered the job.
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2095 Fix custom slugs not being properly imported from bitly
- Fix error when importing short URLs and visits from a Shlink 4.x instance
[4.0.3] - 2024-03-15
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2058 Fix DB credentials provided as env vars being casted to
intif they include only numbers. - #2060 Fix error when trying to redirect to a non-http long URL.
[4.0.2] - 2024-03-09
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2021 Fix infinite GeoLite2 downloads.
[4.0.1] - 2024-03-08
Added
- Nothing
Changed
- Nothing
Deprecated
- Nothing
Removed
- Nothing
Fixed
- #2041 Document missing
colorandbgColorparams for the QR code route in the OAS docs. - #2043 Fix language redirect conditions matching too low quality accepted languages.
[4.0.0] - 2024-03-03
Added
-
#1914 Add new dynamic redirects engine based on rules. Rules are conditions checked against the visitor's request, and when matching, they can result in a redirect to a different long URL.
Rules can be based on things like the presence of specific params, headers, locations, etc. This version ships with three initial rule condition types: device, query param and language.
-
#1902 Add dynamic redirects based on query parameters.
This is implemented on top of the new rule-based redirects.
-
#1915 Add dynamic redirects based on accept language.
This is implemented on top of the new rule-based redirects.
-
#1868 Add support for docker compose secrets to the docker image.
-
#1979 Allow orphan visits lists to be filtered by type.
This is supported both by the
GET /visits/orphanAPI endpoint viatype=...query param, and by thevisit:orphanCLI command, via--typeflag. -
#1904 Allow to customize QR codes foreground color, background color and logo.
-
#1884 Allow a path prefix to be provided during short URL creation.
This can be useful to let Shlink generate partially random URLs, but with a known prefix.
Path prefixes are validated and filtered taking multi-segment slugs into consideration, which means slashes are replaced with dashes as long as multi-segment slugs are disabled.
Changed
- #1935 Replace dependency on abandoned
php-middleware/request-idwith userland simple middleware. - #1988 Remove dependency on
league\uripackage. - #1909 Update docker image to PHP 8.3.
- #1786 Run API tests with RoadRunner by default.
- #2008 Update to Doctrine ORM 3.0.
- #2010 Update to Symfony 7.0 components.
- #2016 Simplify and improve how code coverage is generated in API and CLI tests.
- #1674 Database columns persisting long URLs have now
TEXTtype, which allows for much longer values.
Deprecated
- Nothing
Removed
- #1908 Remove support for openswoole (and swoole).
Fixed
- #2000 Fix short URL creation/edition getting stuck when trying to resolve the title of a long URL which never returns a response.