独自ドメインで短縮 URL を実現するために、
わざわざデータベース使ってコード作っているのを見かけたので……
数が少なければ、そんな事する必要ないですよね?


短縮 URL について

このブログの記事 URL、SEO 対策なのですが、すっごい長いんですよね~ 😅😖😆

🎈 https://balloon.asia/2020/02/独自ドメインで独自の短縮-url-を作る方法/

日本語は変換されて、本当の URL はこうなります。

🎈 https://balloon.asia/2020/02/%E7%8B%AC%E8%87%AA%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%A7%E7%8B%AC%E8%87%AA%E3%81%AE%E7%9F%AD%E7%B8%AE-url-%E3%82%92%E4%BD%9C%E3%82%8B%E6%96%B9%E6%B3%95/

こんなの手入力では無理ですよね!? そういう時に短縮 URL を使うんです。

 http://bit.ly/tanshuku-URL

短縮 URL サービスとして有名 bit.ly が提供している独自ドメインです。
bit.ly が当初から提供されている短縮 URL で、それを現在もサービス名としています。

 Bitly | URL Shortener, Custom Links & Link Management

一時短縮 URL サービスが普及していた時期があります。Twitter です。
Twitter は tweet の文字数制限があるので、短縮 URL がよく使われています。
(開始当初は 1 tweet 140 文字にリンクする URL も含まれていました)
でも、Twitter が公式に t.co を採用した事で、サービスの状況が変わりました。

 t.co / Twitter

 Twitterのリンクサービス(http://t.co)について

でも、なくなったわけではないのです。
自分がよく見ているのは Windows 10 で PowerShell を起動した時ですね。

PowerShell を起動した時

マイクロソフトは短縮 URL として aka.ms を使っています。
……えっ、ms=マイクロソフト じゃないですか。


前提条件

次の前提です。

  • 転送元・転送先は次で設定
    /example よりも /example1・/example2 は前に記載すると良いでしょう。
    /example で /example1・/example2 が一致してしまう場合があるためです。
転送元 転送先
https://example.org/example1 https://example.net.eu.org/1/
https://example.org/example2 https://example.net.eu.org/2/
https://example.org/example https://example.net.eu.org/
  • 転送元 https://example.org/example の example を任意に設定
    この場合ドメイン example.org へ設定する事になります。
    t.co や bit.ly のようなランダム生成ではありません。
    転送元・先で文字数がほぼ一緒ですが、そこは気にせずに…… 😅
  • 転送は 301 または 302。省略できる時は省略表記も含めて
  • 特別な仕組みを作らず、できるだけシンプルに実現

転送する数は少なめで、テキストエディタ(メモ帳・vi など)で追加して、
容易に実現できる前提です。これなら処理速度も速そうですし。

ある程度数が多くなる短縮 URL の運用であれば、
goo.gl の代わりとして Google さんが提案していた
Firebase Dynamic Links を使ってみるのはいかがでしょうか?

 Firebase Dynamic Links

 Transitioning Google URL Shortener to Firebase Dynamic Links | Google Developers Blog


Apache

VPS・専用サーバで VirtualHost 設定済みで、
その独自ドメインの DocumentRoot の場所に .htaccess を入れて実現します。
すでに .htaccess が存在している場合は、ファイルに追記していきます。
Apache 採用のレンタルサーバでも使用可能なので、使えるところは多いでしょう。
確実にログが残るので、使用状況を調査できるメリットもありますね。

Google さんなどで検索すると、Apache の実現方法として
次のような Rewrite を用いた方法がよく出てきます。

RewriteEngine on

RewriteRule ^/example1$ https://example.net.eu.org/1/ [L,R=301]
RewriteRule ^/example2$ https://example.net.eu.org/2/ [L,R=302]
RewriteRule ^/example$  https://example.net.eu.org/   [L,R]

RewriteEngine on は一度記載があれば追記不要です。
R の後ろがない場合は 302 転送になります。

この場合、正規表現を使う必要があります。
完全一致のため、^~$ で囲む感じです。ちょっと面倒なのです。

でも、今回の場合、 Rewrite を使わずに、Redirect で実現できます。

Redirect 301 /example1 https://example.net.eu.org/1/
Redirect 302 /example2 https://example.net.eu.org/2/
Redirect     /example  https://example.net.eu.org/

この方がスッキリするでしょう? Rewrite 無効でも動作します。
英文表記もあり permanent=301、temp=302 です。省略は 302 になります。

Redirect は /example の後ろに文字がある場合、これを継承します。
なので、ドメインの引っ越しをした際の転送例として使われています。

Redirect / https://example.net.eu.org/

Caddy

 redir | Caddy Documentation (v2)
 http.redir | Caddy Documentation (v1)

Caddy v1・v2 共に Caddyfile へ redir で記載します。
複数のドメイン名があれば、対象ドメイン内の {~} 内に並べていきます。

example.org {
  redir /example1 https://example.net.eu.org/1/ 301
  redir /example2 https://example.net.eu.org/2/ 302
  redir /example  https://example.net.eu.org/
}

301・302 がない場合は 301 転送になります。
gzip (v1) ・ encode zstd gzip (v2) を付けて圧縮しても OK です。
短いヘッダでも意外とレスポンスがはやくなります。

Caddy v2 ではステータスコードを返せるものとして respond もあります。
respond /example "OK" 200 という感じに簡単な返信をファイル生成なしに返せます。

 respond | Caddy Documentation (v2)


Firebase Hosting

 リダイレクト | Firebase - Hosting 動作をカスタマイズする

先程も記載していた Google さんが提供しているクラウドサービス Firebase、
Hosting で独自ドメイン割り当てと一緒に全体的な転送もコンソールで容易にできますが、
firebase.json に記載する方法で、細かく転送を指定する事もできます。

"hosting": {
  "redirects": [
    { "source": "/example1", "destination": "https://example.net.eu.org/1/", "type": 301 },
    { "source": "/example2", "destination": "https://example.net.eu.org/2/", "type": 302 },
    { "source": "/example",  "destination": "https://example.net.eu.org/",   "type": 301 }
  ]
}

JSON 表記なのでちょっと長くなりますが…… , 区切りで追加していきます。


Vercel (旧 ZEIT Now・now.sh)

▲ redirects | ▲ Docs - Guides - Configuration Reference

vercel.json に redirects を記載して実現できます。
Now 時代の設定ファイル now.json もまだ使用できるようです。

{
"redirects": [
    { "source": "/example1", "destination": "https://example.net.eu.org/1/" },
    { "source": "/example2", "destination": "https://example.net.eu.org/2/",  "permanent": false },
    { "source": "/example",  "destination": "https://example.net.eu.org/" }
  ]
}

こちらも JSON 表記です。
複数ある場合は , で続けます。permanent がない場合は 308、
"permanent": false は 307 になります。それぞれ 301・302 の代わりです。

  "routes": [
    { "src": "/example1", "status": 301, "headers": { "Location": "https://example.net.eu.org/1/" } },
    { "src": "/example2", "status": 302, "headers": { "Location": "https://example.net.eu.org/2/" } },
    { "src": "/example" , "status": 301, "headers": { "Location": "https://example.net.eu.org/" } }
  ]

routes を用いた表記もできますが、現在は非推奨になっています。

指定は 1024 までとなっていますが、
プログラミング言語を用いた動的処理も可能なため、
処理方法を変えて更に数を増やす事が可能です。

Vercel は AWS や GCP を用いています。東京にも CDN があります。
その点ではレスポンスがはやくて安定動作しているかもしれません。


短縮 URL のテストをする場合……

転送も Web ブラウザのキャッシュに残りますが、
すぐに転送先に変化してしまうので、キャッシュの削除が容易ではなくなります。
そこで、Google Chrome の シークレット ウインドウ を使うと、
キャッシュを参照せず・残さずに最新状態で動作を確認できます。

Google Chrome シークレット ウインドウ


今だったら安値で短縮 URL が運用できる!

数年前まで短縮 URL を行うのには問題があったんですね。
本当に短いドメイン名にしようとするとプレミアムドメイン扱いで
通常は大手企業でないと運用ができなかったのです。\

しかし、現在独自ドメインの種類が増えていて、
(.com .jp などのトップレベルドメインで現在 1500 種類を超えてます)
3~4 文字.種類 であれば、通常価格でも登録しやすくなっています。
ドメイン費用は年間千円~数千円で済む、という事です。探してみて下さい。
でも、有名どころは扱ってるところが少ないです。ここが種類豊富に探せますよ。

また、サーバレベルでも、今はアクセスが多くなっても
CDN(ウェブアクセラレータ)サービスがありますし、
VPS・専用サーバを用いず、Web サービスで容易に実現できる手段もあります。
数が少なめであれば、個人で短縮 URL を運用する事も大変ではないですよ。

とはいっても不特定多数に無料開放して、
登録も自由にしてしまうのは悪用される可能性大なので、
自社・自分制作のサービス専用など限定利用にとどめておくのが無難でしょう。


追加 2020/02/05

優先順位と JSON 表記の考慮で、転送先・転送先を複数記載した内容に修正しました。

あと nginx を入れていなかったので……

nginx

 rewrite | nginx Module ngx_http_rewrite_module

通常は rewrite を用います。

server {
  listen 443 ssl;
  server_name example.org;

  rewrite ^/example1$ https://example.net.eu.org/1/ permanent;
  rewrite ^/example2$ https://example.net.eu.org/2/ redirect;
  rewrite ^/example$  https://example.net.eu.org/   permanent;
}

正規表現になるので ^~$ で囲みます。permanent=301、redirect=302 です。

return を用いる方法もあります。if や location で参照元を指定します。

server {
  listen 443 ssl;
  server_name example.org;

  location /example1 {
    return 301 https://example.net.eu.org/1/;
  }
  location /example2 {
    return 302 https://example.net.eu.org/2/;
  }
  location /example {
    return 301 https://example.net.eu.org/;
  }
}

追加 2020/04/19

正しく設定しているか調べるために、curl を使うのも良いですね。

現在 Windows 10 でも curl が含まれています。
ただし、PowerShell で curl だと Invoke-WebRequest のエイリアスになっています。
curl.exe にするのが手軽に使えるでしょう。

> curl.exe -s -I https://example.org/example1

コマンド プロンプト または Git Bash だと curl は期待する動作をしてくれます。

こんな感じに出力します。

$ curl -s -I https://example.org/example1
HTTP/1.1 301 Moved Permanently
Date: Sun, 19 Apr 2020 07:02:32 GMT
Content-Type: text/plain
Connection: keep-alive
location: https://example.net.eu.org/1/
x-now-trace: hnd1
server: now
x-now-id: hnd1:88cjr-1587279752226-f52e0a4ef211
strict-transport-security: max-age=63072000; includeSubDomains; preload
cache-control: s-maxage=0

さて、これは上で説明している中で、何を使用した場合の出力結果でしょうか?


追加 2020/04/22

▲ ZEIT が ▲ Vercel に変わりました。このページで紹介していたので変更しています。


追加 2021/01/18

Apache でレンタルサーバではなく、VPS・専用サーバなどで完全に管理できる状態の場合、
RewriteMap を使う方法もあります。(RewriteMap は .htaccess で使用不可能)

設定ファイル(.conf)の該当ドメイン <VirtualHost> 内にこのような記載を加えます。

RewriteEngine on
RewriteMap shortlinks txt:/home/user/links.txt
RewriteRule ^/(.+)$ ${shortlinks:$1} [R=301,L]

links.txt は次の記載です。

example1 https://example.net.eu.org/1/
example2 https://example.net.eu.org/2/
example https://example.net.eu.org/

追加 2021/03/16

 Workers - Bulk redirects | Cloudflare Docs

若干コード記載が必要になりますが、 Cloudflare Workers でも実現できます。
指定していない URL を参照した場合、Cloudflare 側で設定されている本来の動作になります。
通常は設定されている配信サーバを参照しにいく事になりますが、
プレビューを行う場合はサーバの設定がないので、エラー表示で正常です。

const redirectMap = new Map([
  ["/example1", "https://example.net.eu.org/1/"],
  ["/example2", "https://example.net.eu.org/2/"],
  ["/example",  "https://example.net.eu.org/"],
])

async function handleRequest(request) {
  const location = redirectMap.get(new URL(request.url).pathname)
  if (location) {
    return Response.redirect(location, 301)
  }
  return fetch(request)
}

addEventListener("fetch", async event => {
  event.respondWith(handleRequest(event.request))
})

完全無料で使用している場合、Cloudflare の ページ ルール は 3 項目のみで、
転送が多くなると対応できなくなりますが、
Cloudflare Workers 側で対処する事ができます。
Cloudflare Workers は無料だと 1 日 10 万リクエストまでの制限がありますが、
Cloudflare のエッジサーバで動作するのはメリットが大きいです。


追加 2021/04/12

🎈 Kidspod; → イチゴジャム レシピ 短縮 URL - fu-sen/k.bal.gdn | GitHub

転送 URL を実際に採用してみました。


追加 2021/04/19

 Pages - Redirects | Cloudflare Docs

 Cloudflare Pages がファイル _redirects を用いた転送に対応しています。

/example1 https://example.net.eu.org/1/ 301
/example2 https://example.net.eu.org/2/ 302
/example https://example.net.eu.org/

追加時点で 100 行まで、ワイルドカードなどは非対応です。
場合によっては Cloudflare が対応する他の方法で行う必要があるでしょう。


追加 2021/05/31

 Create redirects for GitLab Pages | GitLab Docs

 GitLab Pages が _redirects を用いた転送に対応していました。

/example1 https://example.net.eu.org/1/ 301
/example2 https://example.net.eu.org/2/ 302
/example https://example.net.eu.org/

_redirects ファイルなので、書式は Cloudflare Pages に同じです。
この形式に対応するところが増えてきた気がします。


追加 2021/05/16

🦕 Deno Deploy

Deno Deploy は Cloudflare Workers と API が互換になっています。
上で紹介している Cloudflare Workers のソースは
そのまま Deno Deploy でも動作可能です。

Cloudflare Workers での独自ドメイン使用は Cloudflare へのサイト登録が必要ですが、
Deno Deploy はその必要なく独自ドメインを設定できるので、
他のサーバ・Web サービスを使用したい場合、Deno Deploy が良いケースがあります。

Cloudflare は 200 ヶ所以上のエッジサーバがあるので、
世界的に提供する場合は Cloudflare Workers が有利ですが、
Deno Deploy のエッジサーバは Cloudflare と同じ東京・大阪からなので、
日本国内向けであれば、Deno Deploy でもほぼ変わらないレスポンスを期待できます。