Using multiple domains
While in many cases you will just have one short domain, and you’ll want all your short URLs to be served from it, there are some cases in which you may want to have multiple short domains served from the same Shlink instance.
If that’s the case, you need to understand how Shlink will behave when managing your short URLs or any of them is visited.
Important!
In this page you will learn how a single Shlink instance behaves when served behind more than one domain.
However, it’s still up to you to properly configure the DNS and web server, so that all the domains point to the proper “place”, and the requests end up in Shlink. Shlink will never be able to do this on its own.
If you want to learn more about this aspect, go to External configuration.Management
When you create a short URL (either from the CLI or the REST API), it is possible to optionally provide a domain param. If you don’t pass it, the short URL will be created for the default domain (the one provided during Shlink’s installation or in the DEFAULT_DOMAIN env var).
However, if you pass it, the short URL will be “linked” to that domain.
Note that, if the default domain is passed here, Shlink will ignore it and will behave as if no
domainparam was provided.
The main benefit of being able to pass the domain is that Shlink will allow the same custom slug to be used in multiple short URLs, as long as the domain is different (like example.com/my-compaign, another.com/my-compaign and foo.com/my-compaign).
Then, each short URL will be tracked separately and you will be able to define specific tags and metadata for each one of them.
However, this has a side effect. When you try to interact with an existing short URL (editing tags, editing meta, resolving it or deleting it), either from the REST API or the CLI, you will have to provide the domain appropriately.
Let’s imagine this situation. Shlink’s default domain is example.com, and you have the next short URLs:
https://example.com/abc123: a regular short URL where no domain was provided.https://example.com/my-campaign: a regular short URL where no domain was provided, but it has a custom slug.https://another.com/my-campaign: a short URL where theanother.comdomain was provided, and it also has a custom slug.https://another.com/def456: a short URL where theanother.comdomain was provided.
These are some of the results you will get when trying to interact with them, depending on the params you provide:
- Providing just the
abc123short code: the first URL will be matched. - Providing just the
my-campaignshort code: the second URL will be matched, since you did not specify a domain, therefor, Shlink looks for the one with the short code/slugmy-campaignwhich is also linked to default domain (or not linked to any domain, to be more precise). - Providing the
my-campaignshort code and theanother.comdomain: The third one will be matched. - Providing just the
def456short code: Shlink will fail/not find any short URL, since there’s none with the short codedef456linked to default domain. - Providing the
def456short code and theanother.comdomain: The fourth short URL will be matched. - Providing any short code and the
foo.comdomain: Again, no short URL will be found, as there’s none linked tofoo.comdomain.
Visits
Before adding support for multiple domains, you could point as many domains as you wanted to Shlink, and they would have always worked for existing short codes/slugs.
In order to keep backwards compatibility, Shlink’s behavior when a short URL is visited is slightly different, getting to fallback in some cases.
Let’s continue with previous example, and also consider we have three domains that will resolve to our Shlink instance, which are example.com, another.com and foo.com.
With that in mind, this is how Shlink will behave when the next short URLs are visited:
https://another.com/abc123: There was no short URL specifically defined for domainanother.comand short codeabc123, but it exists for default domain (example.com), so it will fall back to it and redirect to whereexample.com/abc123is configured to redirect.https://example.com/def456: The fall back does not happen from default domain to specific ones, only the other way around (like in previous case). Because of that, this one will result in a not-found URL, even though thedef456short code exists foranother.comdomain.https://foo.com/abc123: This will also fall back toexample.com/abc123, like in the first case.https://another.com/non-existing: The combination ofanother.comdomain with thenon-existingslug does not exist, so Shlink will try to fall back to the same but for default domain (example.com). However, since that combination does not exist either, it will result in a not-found URL.- Any other short URL visited exactly as it was configured will, of course, resolve as expected.
Special redirects
Starting with Shlink v2.8.0, it is possible to configure special redirects on a per-domain basis. Read the docs to get more information.
External configuration
Now that you know how Shlink behaves on a multi-domain context, you also need to perform a couple of extra steps outside Shlink itself.
Not performing these steps will result in requests never reaching Shlink or miss important information.
-
Configure the DNS: You probably did this for the default domain, and it needs to be done for every extra domain you plan Shlink to handle.
DNS management is different for every provider, but a good way to start is by searching for “configure DNS” followed by your DNS provider name on the search engine of your choice.
-
Configure your server’s virtual host: If you are serving Shlink with a classic web server or behind a reverse proxy, you have probably configured you virtual hosts at some point.
Those virtual hosts need to handle all the default and non-default domains. This is how it’s done for the most used web servers here:
- Nginx: Use the
server_namefollowed by all the domains, separated by spaces.
server_name example.com another.com foo.com- Apache: Use the
ServerNamedirective for the main domain, and then add as manyServerAliasas you need, until you completed all the domains.
ServerName example.comServerAlias another.comServerAlias foo.com- Caddy: Use the
binddirective followed by all the domains, separated by spaces.
bind example.com another.com foo.com - Nginx: Use the
-
Make sure the domain is passed when using a reverse proxy: If you don’t configure your reverse proxy to pass the domain down, Shlink won’t be able what was the actual domain used when visiting a short URL, resulting in 404s or incorrect visits stats.
Because fo that, follow the Using a reverse proxy documentation.
In any case, these are the important instructions for the most used web servers:
- Nginx: Use the
proxy_set_headerdirective to pass theHostheader, combined with the$hostvariable.
proxy_set_header Host $host;- Apache: Set the
ProxyPreserveHostoption toOn.
ProxyPreserveHost On- Caddy: Use the
header_updirective to pass theHostheader, combined with the{upstream_hostport}placeholder.
header_up Host {upstream_hostport} - Nginx: Use the