Персональный легковесный редиректор ссылок в Telegram, работающий на собственном домене t.gluek.info.
Служит независимой альтернативой официальному шортлинкеру t.me, помогая открывать каналы, чаты, посты, стикеры и настройки в условиях региональных или провайдерских блокировок домена t.me, не нагружая браузер лишними скриптами и внешними трекерами.
Проблема
- Блокировки домена
t.me: В некоторых сетях и у отдельных провайдеров доменt.meподвергается блокировкам или искусственному замедлению. В результате пользователи не могут открыть канал или перейти по ссылке. - Ограничения deep link (
tg://): Прямой HTTP-редирект (301/302) на кастомную схемуtg://resolve?...блокируется большинством современных мобильных и десктопных браузеров (Chrome, Safari) с ошибкойERR_UNKNOWN_URL_SCHEME, если переход инициирован заголовком ответа, а не явным кликом пользователя. - Мусорный трафик и сканеры: При использовании неразборчивого 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:// в приложении | Назначение |
|---|---|---|
/Gluek | tg://resolve?domain=Gluek | Профиль, публичный канал или бот |
/my_bot?start=ref123 | tg://resolve?domain=my_bot&start=ref123 | Бот с параметрами запуска |
/gluekinfo/123 | tg://resolve?domain=gluekinfo&post=123 | Пост в публичном канале |
/c/1234567890/42 | tg://privatepost?channel=1234567890&post=42 | Пост в закрытом канале |
/group/12/34 | tg://resolve?domain=group&thread=12&post=34 | Сообщение в ветке форума |
+inviteCode / /joinchat/... | tg://join?invite=inviteCode | Приглашение в чат или канал |
+79991234567 | tg://resolve?phone=79991234567 | Чат по номеру телефона |
/addstickers/pack_name | tg://addstickers?set=pack_name | Установка стикерпака |
/addemoji/pack_name | tg://addemoji?set=pack_name | Установка кастомных эмодзи |
/addlist/list_hash | tg://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
}
}