4 min read
t.gluek.info

Персональный легковесный редиректор ссылок в Telegram, работающий на собственном домене t.gluek.info.

Служит независимой альтернативой официальному шортлинкеру t.me, помогая открывать каналы, чаты, посты, стикеры и настройки в условиях региональных или провайдерских блокировок домена t.me, не нагружая браузер лишними скриптами и внешними трекерами.

Проблема

  1. Блокировки домена t.me: В некоторых сетях и у отдельных провайдеров домен t.me подвергается блокировкам или искусственному замедлению. В результате пользователи не могут открыть канал или перейти по ссылке.
  2. Ограничения deep link (tg://): Прямой HTTP-редирект (301/302) на кастомную схему tg://resolve?... блокируется большинством современных мобильных и десктопных браузеров (Chrome, Safari) с ошибкой ERR_UNKNOWN_URL_SCHEME, если переход инициирован заголовком ответа, а не явным кликом пользователя.
  3. Мусорный трафик и сканеры: При использовании неразборчивого catch-all обработчика боты и сканеры уязвимостей (/.env, /wp-admin) получали бы 200 OK и пытались генерировать фиктивные ссылки.

Архитектура решения

Сервис работает полностью на уровне веб-сервера Caddy без единой строчки бэкенд-кода (Node.js, Go, Python или PHP не требуются).

Преимущества серверной маршрутизации в Caddy

  • Строгая валидация путей (Whitelist): Caddy проверяет пути регулярными выражениями. Любые посторонние запросы, сканеры ботов или битые URL сразу отсекаются и отправляются на страницу проекта или 404, не запуская клиентский код.
  • Серверные мета-теги (SSR): Заголовки страницы (<title>) и прямой URL для кнопки формируются сервером на этапе отдачи страницы через плейсхолдеры Caddy ({re.user.1}, {re.post.1} и т.д.).
  • Мгновенный переход + фоллбэк: JavaScript в браузере сразу инициирует открытие Telegram, а если браузер запросил подтверждение — пользователь видит карточку с чёткой кнопкой прямого перехода (Open in Telegram).
  • Векторная фавиконка в стиле Telegram: Caddy самостоятельно отдаёт легковесную SVG-фавиконку для /favicon.ico и /favicon.svg без графических файлов на диске.
  • Интернациональный интерфейс: Все карточки оформлены на английском языке в лаконичном стиле t.me.

Поддерживаемые форматы ссылок

Формат t.gluek.infoСхема tg:// в приложенииНазначение
/Gluektg://resolve?domain=GluekПрофиль, публичный канал или бот
/my_bot?start=ref123tg://resolve?domain=my_bot&start=ref123Бот с параметрами запуска
/gluekinfo/123tg://resolve?domain=gluekinfo&post=123Пост в публичном канале
/c/1234567890/42tg://privatepost?channel=1234567890&post=42Пост в закрытом канале
/group/12/34tg://resolve?domain=group&thread=12&post=34Сообщение в ветке форума
+inviteCode / /joinchat/...tg://join?invite=inviteCodeПриглашение в чат или канал
+79991234567tg://resolve?phone=79991234567Чат по номеру телефона
/addstickers/pack_nametg://addstickers?set=pack_nameУстановка стикерпака
/addemoji/pack_nametg://addemoji?set=pack_nameУстановка кастомных эмодзи
/addlist/list_hashtg://addlist?slug=list_hashДобавление папки с чатами
/proxy?... / /socks?...tg://proxy?... / tg://socks?...Классические MTProto / SOCKS5 прокси
/webproxy?...tg://webproxy?...Новый экспериментальный WEB Proxy (WebSocket/HTTPS)

Конфигурация Caddyfile

Ниже приведена полная конфигурация виртуального хоста для Caddyfile:

t.gluek.info {
    # Фавиконка в стиле Telegram (SVG)
    @favicon path /favicon.ico /favicon.svg
    handle @favicon {
        header Content-Type "image/svg+xml"
        header Cache-Control "public, max-age=604800"
        respond <<SVG
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="12" fill="#24A1DE"/><path fill="#ffffff" d="M5.4 12l11.6-4.5c.5-.2 1 .1.9.7l-2 9.4c-.1.6-.6.8-1.1.5l-3.3-2.4-1.6 1.5c-.2.2-.4.3-.7.3l.2-3.4 6.2-5.6c.3-.3-.1-.4-.4-.2l-7.7 4.9-3.3-1c-.7-.2-.7-.7.2-1z"/></svg>
SVG 200
    }

    # Общие заголовки
    header Content-Type "text/html; charset=utf-8"
    header Cache-Control "no-cache"

    # 1. Приватные посты в закрытых каналах: /c/1234567890/42
    @private_post path_regexp priv ^/c/([0-9]+)/([0-9]+)/?$
    handle @private_post {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Private Channel Post — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>window.location.href="tg://privatepost?channel={re.priv.1}&post={re.priv.2}";</script></head><body><div class="card"><h2>Private Channel</h2><p>Opening post #{re.priv.2}...</p><a class="btn" href="tg://privatepost?channel={re.priv.1}&post={re.priv.2}">Open in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 2. Стикеры, эмодзи и папки: /addstickers/pack, /addemoji/pack, /addlist/hash
    @packs path_regexp packs ^/(addstickers|addemoji|addlist)/([a-zA-Z0-9_]+)/?$
    handle @packs {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Telegram {re.packs.1} — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>
const type = "{re.packs.1}";
const param = type === "addlist" ? "slug" : "set";
window.location.href = `tg://${type}?${param}={re.packs.2}`;
</script></head><body><div class="card"><h2>Add to Telegram</h2><p>Installing {re.packs.2}...</p><a class="btn" href="tg://{re.packs.1}?set={re.packs.2}">Install in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 3. Настройки прокси (MTProto, SOCKS5, WEB Proxy): /proxy?... /socks?... /webproxy?...
    @proxy path_regexp proxy ^/(proxy|socks|webproxy)/?$
    handle @proxy {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Telegram Proxy — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>window.location.href="tg://{re.proxy.1}?{query}";</script></head><body><div class="card"><h2>Connect to Proxy</h2><p>Applying {re.proxy.1} settings...</p><a class="btn" href="tg://{re.proxy.1}?{query}">Connect in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 4. Ссылка на телефон: /+79991234567
    @phone path_regexp phone ^/\+([0-9]{7,15})/?$
    handle @phone {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Telegram Contact — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>window.location.href="tg://resolve?phone={re.phone.1}";</script></head><body><div class="card"><h2>Contact</h2><p>Opening chat with +{re.phone.1}...</p><a class="btn" href="tg://resolve?phone={re.phone.1}">Open in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 5. Темы форумов (topic + post): /group/12/34
    @topic path_regexp topic ^/([a-zA-Z0-9_]+)/([0-9]+)/([0-9]+)/?$
    handle @topic {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Topic in @{re.topic.1} — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>window.location.href="tg://resolve?domain={re.topic.1}&thread={re.topic.2}&post={re.topic.3}";</script></head><body><div class="card"><h2>Topic in @{re.topic.1}</h2><p>Opening discussion thread...</p><a class="btn" href="tg://resolve?domain={re.topic.1}&thread={re.topic.2}&post={re.topic.3}">Open in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 6. Пост в канале: /Gluek/123
    @post path_regexp post ^/([a-zA-Z0-9_]+)/([0-9]+)/?$
    handle @post {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Post in @{re.post.1} — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>window.location.href="tg://resolve?domain={re.post.1}&post={re.post.2}";</script></head><body><div class="card"><h2>Post in @{re.post.1}</h2><p>Opening post #{re.post.2}...</p><a class="btn" href="tg://resolve?domain={re.post.1}&post={re.post.2}">Open in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 7. Инвайты: /+inviteHash или /joinchat/inviteHash
    @invite path_regexp invite ^/(?:\+|joinchat/)([a-zA-Z0-9_-]+)/?$
    handle @invite {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Telegram Invite — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style><script>window.location.href="tg://join?invite={re.invite.1}";</script></head><body><div class="card"><h2>Telegram Invite</h2><p>Opening invitation link...</p><a class="btn" href="tg://join?invite={re.invite.1}">Join in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div></body></html>
HTML 200
    }

    # 8. Пользователь / канал / бот: /Gluek?start=123
    @user path_regexp user ^/([a-zA-Z0-9_]+)/?$
    handle @user {
        respond <<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>@{re.user.1} — t.gluek.info</title><link rel="icon" href="/favicon.svg" type="image/svg+xml"><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0f172a;color:#fff;text-align:center}.card{background:#1e293b;padding:2rem;border-radius:1rem;border:1px solid #334155;max-width:380px;width:90%}.btn{display:block;margin-top:1.5rem;background:#24A1DE;color:#fff;text-decoration:none;padding:.8rem;border-radius:.5rem;font-weight:600}.footer{margin-top:1.5rem;font-size:.8rem;color:#94a3b8}.footer a{color:#94a3b8}</style></head><body><div class="card"><h2>@{re.user.1}</h2><p>Opening channel or profile...</p><a id="btn" class="btn" href="tg://resolve?domain={re.user.1}">Open in Telegram</a><div class="footer">Redirector <a href="https://gluek.info/projects/t-gluek-info/">t.gluek.info</a></div></div><script>
const query = "{query}" ? "&{query}" : "";
const tgUrl = "tg://resolve?domain={re.user.1}" + query;
const btn = document.getElementById("btn");
if (btn) btn.href = tgUrl;
window.location.href = tgUrl;
</script></body></html>
HTML 200
    }

    # 9. Всё остальное (корень или невалидные пути) -> на описание проекта
    handle {
        redir https://gluek.info/projects/t-gluek-info/ 302
    }
}