shlinkio / shlink

The definitive self-hosted URL shortener
https://shlink.io
MIT License
3.19k stars 257 forks source link

Ability to specify different "not found" redirects for every domain handled by Shlink #943

Closed ajtatum closed 3 years ago

ajtatum commented 3 years ago

Currently, the default domain is applied to all short domains. However, it would be nice if a default domain could be specified per short domain (similar to Bitly or Rebrandly). For example, I use a short domain for my blog and one for my main site. Right now, if someone goes to the root short domain or a non-existent short code on a short domain, they're taken to the application's default domain.

acelaya commented 3 years ago

It behaves like this for backwards-compatibility reasons.

Some time ago, Shlink didn't have multi-domain support, and you could point as many domains as you wanted to your Shlink instances, making all short codes work with any of them.

Then, when multi-domain support was added, in order to not break existing instances, I came up with the "default domain idea", which basically means you can set a domain when creating a short URL, or not set it.

When you set a domain, that short code will work only with that domain or with the default one, but it will not work with other non-default domains.

When you don't set a domain, the URL will be treated as a url for the default domain, but in practice, it will work with all the domains that point to your Shlink insurance.

Also actively providing the details domain is considered as not seeing a domain at all.

You can find a more detailed explanation here: https://shlink.io/documentation/advanced/multiple-domains/

That said, of course Shlink could be extended so that you can configure a different behavior, which would continue being backwards compatible. It's something I have in the roadmap, but it's hard to find the time to work on everything, haha.

acelaya commented 3 years ago

I'm reading the issue again, and just realized I misunderstood it.

I think that, what you mean is that you would like to be able to redirect to different places when someone visits the different base URLs/base domains supported by your instance.

That's actually the plan. I didn't do it like that at first, for simplicity, but the intention is to implement it soon.

tobiasfichter commented 3 years ago

Hey @acelaya, can you estimate when you'll tackle this? We'd like to use your tool for around 10 different domains, where every domain needs it's own redirect to "home" if no slug is specified.

acelaya commented 3 years ago

I'm afraid I can't really provide an estimation, but I'm prioritizing this for v2.8 (nothing is written in stone, but this is something very nice to have, although a bit complex to implement too).

Roy-Orbison commented 3 years ago

These could be implemented as additional fields in the domains table. You could use a domain-specific redirect if configured, then choose whether to fall back to the global config value if the db value is null, or behave as though both the domain-specific & global values are null by using a special value like the empty string or NONE.


A very hacky workaround is to edit the data/cache/app_config.php file and add something like below after the existing not_found_redirects array entry. It will get overwritten on any update, cache clearing, or option setting command, so you'll have to reinstate it each time. Easy if keeping that file under its own version control, e.g. git checkout --patch to restore the addition, then commit any remaining changes (use --separate-git-dir to protect the repo by keeping it outside the app's file tree).

    'not_found_redirects' => (function() {
        $nfrs = [
            'invalid_short_url' => null,
            'regular_404' => null,
            'base_url' => null,
        ];
        if (!empty($_SERVER['HTTP_HOST'])) {
            switch ($_SERVER['HTTP_HOST']) {
                case 'a.com':
                case 'www.a.com':
                    $nfrs['base_url'] = 'https://apparition.com/';
                    break;
                case 'b.com':
                case 'www.b.com':
                    $nfrs['base_url'] = 'https://burninate.com/';
                    break;
            }
        }
        return $nfrs;
    })(),
acelaya commented 3 years ago

FYI, I have just merged this https://youtu.be/69ItPCMCmlk

It adds support for this functionality, and a console command to manage the redirects for every domain.

I still need to tackle some things before closing this issue though, like adding a rest endpoint and solving some minor issue when handling domains with redirects using an API key that is restricted to a single domain.

acelaya commented 3 years ago

This is now fully implemented and will be part of v2.8.0

antwonw commented 3 years ago

I've upgraded from 2.7 to 2.8 and enabled this for some of my domains, however, it's not redirecting.

$ shlink/bin/cli domain:list -r
+----------------+------------+-------------------------------------------------------+
| Domain         | Is default | "Not found" redirects                                 |
+----------------+------------+-------------------------------------------------------+
| nwadvent.st    | Yes        | * Base URL: https://gleanernow.com                    |
|                |            | * Regular 404: https://gleanernow.com                 |
|                |            | * Invalid short URL: https://gleanernow.com           |
+----------------+------------+-------------------------------------------------------+
| mt.nwadvent.st | No         | * Base URL: https://montanaadventist.org              |
|                |            | * Regular 404: https://montanaadventist.org           |
|                |            | * Invalid short URL: https://montanaadventist.org     |
+----------------+------------+-------------------------------------------------------+
| wa.nwadvent.st | No         | * Base URL: https://washingtonconference.org          |
|                |            | * Regular 404: https://washingtonconference.org       |
|                |            | * Invalid short URL: https://washingtonconference.org |
+----------------+------------+-------------------------------------------------------+

Any insights?

(Might not be in the right location to ask, but it's tangential) How does one update the default domain's redirect URLs? It's not an option in domain:redirects.

$ shlink/bin/cli domain:redirects

 Select the domain to configure:
  [0] mt.nwadvent.st
  [1] wa.nwadvent.st
  [2] New domain
 > 
acelaya commented 3 years ago

The redirects for the default domain are still handled through the old config or env vars. Unifying that was tricky, so I left it as an improvement for a future version.

As per the other domans, the only thing I can think of is that the domain info is not getting propagated to Shlink, so it cannot determine the actual domain. Do you have a reverse proxy in front of it?