Install using a docker image

The docker image is probably the simplest installation use case, since it includes all dependencies and works standalone.


Shlink docker images are published both in Docker hub and Github Container Registry.

All examples use Docker hub images. In order to install images from Github Container Registry, use instead of shlinkio/shlink.


The most basic way to run Shlink’s docker image is by providing these mandatory env vars.

  • DEFAULT_DOMAIN: The custom short domain used for this Shlink instance. For example s.test.
  • IS_HTTPS_ENABLED: Either true or false.
  • GEOLITE_LICENSE_KEY: Your GeoLite2 license key. Learn more about this.

To run Shlink on top of a local docker service, and using an internal SQLite database, do the following:

docker run \
    --name my_shlink \
    -p 8080:8080 \
    -e DEFAULT_DOMAIN=s.test \
    -e IS_HTTPS_ENABLED=true \
    -e GEOLITE_LICENSE_KEY=kjh23ljkbndskj345 \

Generate first API key

Once the Shlink container is running, you can interact with the CLI entry point by running shlink with any of the supported commands.

One of the main reasons you would want to do that, is to generate your first API key. For example, if the container is called my_shlink, you can do it with:

docker exec -it my_shlink shlink api-key:generate

If you can’t interact with the container’s shell (for example, when running Shlink in Google Cloud Run or similar), or if you wish to provide an initial API key yourself, starting with Shlink 3.3.0, you can do so by providing the INITIAL_API_KEY env var with an API key of your choice.

docker run \
    --name my_shlink \
    [...] \
    -e INITIAL_API_KEY=<super_secure_api_key> \

Interact with Shlink’s CLI on a running container.

Generating the first API key is not the only thing you can do with Shlink’s CLI entry point inside the container’s shell.

You can also list all tags:

docker exec -it my_shlink shlink tag:list

Or locate remaining visits:

docker exec -it my_shlink shlink visit:locate

All Shlink commands will work the same way.

You can also list all available commands by just running this:

docker exec -it my_shlink shlink

Use an external DB

The image comes with a working SQLite database, but in production, it’s strongly recommended using a distributed database.

It is possible to use a set of env vars to make this Shlink instance interact with an external MySQL, MariaDB, PostgreSQL or Microsoft SQL Server database.

  • DB_DRIVER: [Mandatory]. Use the value mysql, maria, postgres or mssql to prevent the SQLite database to be used.
  • DB_NAME: [Optional]. The database name to be used. Defaults to shlink.
  • DB_USER: [Mandatory]. The username credential for the database server.
  • DB_PASSWORD: [Mandatory]. The password credential for the database server.
  • DB_HOST: [Mandatory]. The host name of the server running the database engine.
  • DB_PORT: [Optional]. The port in which the database service is running.
    • Default value is based on the value provided for DB_DRIVER:
      • mysql or maria -> 3306
      • postgres -> 5432
      • mssql -> 1433

PostgreSQL is supported since v1.16.1 and Microsoft SQL server since v2.1.0. Do not try to use them with previous versions.

Taking this into account, you could run Shlink on a local docker service like this:

docker run \
    --name my_shlink \
    -p 8080:8080 \
    -e DEFAULT_DOMAIN=s.test \
    -e IS_HTTPS_ENABLED=true \
    -e GEOLITE_LICENSE_KEY=kjh23ljkbndskj345 \
    -e DB_DRIVER=mysql \
    -e DB_USER=root \
    -e DB_PASSWORD=123abc \
    -e \

You could even link to a local database running on a different container:

docker run \
    --name my_shlink \
    -p 8080:8080 \
    [...] \
    -e DB_HOST=some_mysql_container \
    --link some_mysql_container \

If you have considered using SQLite but sharing the database file with a volume, read this issue first.

Other integrations

Use an external redis server

If you plan to run more than one Shlink instance, there are some resources that should be shared (Multi instance considerations).

One of those resources are the locks Shlink generates to prevent some operations to be run more than once in parallel. You can find more information here.

Integrations for real-time updates

Shlink supports sending real-time updates to some queueing systems, like Mercure, RabbitMQ or Redis pub/sub.

Check the real-time updates section to get more details on how to integrate with them.

Supported env vars

A few env vars have been already used in previous examples, but this image supports others that can be used to customize its behavior.

See the full list of supported Environment variables.


Starting on v2.3.0, Shlink’s docker image is built for multiple architectures.

The only limitation is that images for architectures other than amd64 will not have support for Microsoft SQL databases, since there are no official binaries.

Multi-instance considerations

These are some considerations to take into account when running multiple Shlink instances.

  • Some operations performed by Shlink should never be run more than once at the same time (like creating the database for the first time, or downloading the GeoLite2 database). For this reason, Shlink uses a locking system.

    However, these locks are locally scoped to each Shlink instance by default.

    You can (and should) make the locks to be shared by all Shlink instances by using a redis server/cluster. Just define the REDIS_SERVERS env var with the list of servers.


Versioning on this docker image works as follows:

  • X.X.X: when providing a specific version number, the image version will match the Shlink version it contains. For example, installing shlinkio/shlink:2.9.1, you will get an image containing Shlink v2.9.1.
  • X.X: when providing major and minor version numbers, the image version will match the latest patch for that combination. For example, installing shlinkio/shlink:3.6, you will get an image containing Shlink v3.6.4.
  • X: when providing major version number, the image version will match the latest minor version for it. For example, installing shlinkio/shlink:3, you will get an image containing Shlink v3.7.0.
  • stable: always holds the most recent stable tag. For example, if latest Shlink version is 3.0.0, installing shlinkio/shlink:stable, you will get an image containing shlink v3.0.0
  • latest: same as stable, but if the most recent release is an alpha or beta version, latest will point to it.

Runtime variations

Before Shlink 4.0.0, you could add -roadrunner or -openswoole to the tag you wanted to install in order to get an image using RoadRunner (for example, shlinkio/shlink:stable-roadrunner or shlinkio/shlink:3.4.0-roadrunner) or openswoole (for example shlinkio/shlink:3.4.0-openswoole).

Starting with v4.0.0, Shlink only ships images with RoadRunner, but you can still append -roadrunner to make sure you’ll continue getting that runtime in case support is added for something else.


Starting with Shlink 4.0.0, Shlink docker images run as a non-root user for security reasons.

For versions 3.6.x and 3.7.x you could add -non-root to get a RoadRunner-based docker image using a non-privileged user.