Как установить и настроить Shlink на VPS
Если вы устали от того, что бесплатные сокращатели ссылок режут статистику, показывают чужую рекламу на редиректе или могут в любой момент заблокировать домен, решение простое — поднять свой. Shlink делает то же самое, что bit.ly или clck.ru, но данные, домен и API-ключи остаются полностью у вас. Ниже — рабочая установка на VPS через Docker Compose, с базой, кешем, доменом и SSL.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое Shlink и зачем он нужен
Shlink — открытый URL-сокращатель на PHP, который можно развернуть на своём сервере и использовать как полноценный сервис: с REST API, CLI-утилитой и отдельным веб-клиентом для управления ссылками и просмотра статистики. В отличие от облачных сокращателей у него нет ограничений по количеству ссылок, нет чужой рекламы на промежуточной странице редиректа и нет риска, что сервис однажды остановит работу вместе с вашей историей переходов.
Из практически полезного:
- собственный короткий домен (например
go.вашдомен.ru) вместоbit.ly/xxxxx; - кастомные слаги (
go.site.ru/promo2026вместо случайного набора символов); - REST API для автоматической генерации ссылок из ваших скриптов, CRM или рассылок;
- аналитика переходов: страна, устройство, браузер, referrer — без передачи данных третьим лицам;
- поддержка нескольких доменов на одной инсталляции.
Из ограничений — это не готовый SaaS: обновления, бэкапы и мониторинг лежат на вас. Дальше разберём весь путь от чистого VPS до рабочего сокращателя.
Требования к серверу и подготовка
Shlink — компактное PHP-приложение, поэтому ресурсов ему нужно немного. Для проекта с умеренной нагрузкой (десятки-сотни редиректов в минуту) достаточно небольшого VPS:
| Параметр | Минимум | Комфортно |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 1 GB (со swap) | 2 GB |
| Диск | 15 GB SSD | 20-30 GB SSD |
| ОС | Ubuntu 24.04 LTS | Ubuntu 24.04 LTS |
Понадобится:
- VPS с публичным IP и Ubuntu 24.04.
- Домен или поддомен, A-запись которого указывает на IP сервера (короткие ссылки будут выглядеть как
go.вашдомен.ru/slug). - Установленный Docker и Docker Compose plugin — если их ещё нет, разверните с нуля по инструкции Ubuntu 24.04: установка Docker с нуля.
Проверьте, что Docker установлен и запущен:
docker --version
docker compose version
Если оба вывели версии — можно переходить к установке.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверУстановка Shlink через Docker Compose
Создаём рабочую директорию и структуру для данных БД:
mkdir -p ~/shlink/data/mysql ~/shlink/data/shlink
cd ~/shlink
Файл .env с секретами (сгенерируйте свои пароли, не используйте примеры ниже):
cat > .env <<'EOF'
DB_ROOT_PASSWORD=замените_на_свой_пароль
DB_PASSWORD=замените_на_свой_пароль
INITIAL_API_KEY=замените_на_свой_ключ
GEOLITE_LICENSE_KEY=
EOF
GEOLITE_LICENSE_KEY можно оставить пустым — без него Shlink просто не будет определять страну посетителя в статистике. Бесплатный ключ MaxMind GeoLite2 получают на сайте maxmind.com после регистрации, это отдельный шаг, не обязательный для запуска.
Теперь docker-compose.yml:
services:
shlink_db:
image: mariadb:11
container_name: shlink_db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MARIADB_DATABASE: shlink
MARIADB_USER: shlink
MARIADB_PASSWORD: ${DB_PASSWORD}
volumes:
- ./data/mysql:/var/lib/mysql
networks:
- shlink_net
shlink_redis:
image: redis:7-alpine
container_name: shlink_redis
restart: unless-stopped
networks:
- shlink_net
shlink:
image: shlinkio/shlink:stable
container_name: shlink
restart: unless-stopped
depends_on:
- shlink_db
- shlink_redis
environment:
DEFAULT_DOMAIN: go.вашдомен.ru
IS_HTTPS_ENABLED: "true"
DB_DRIVER: maria
DB_NAME: shlink
DB_USER: shlink
DB_PASSWORD: ${DB_PASSWORD}
DB_HOST: shlink_db
REDIS_SERVERS: redis://shlink_redis:6379
GEOLITE_LICENSE_KEY: ${GEOLITE_LICENSE_KEY}
INITIAL_API_KEY: ${INITIAL_API_KEY}
ports:
- "127.0.0.1:8080:8080"
volumes:
- ./data/shlink:/etc/shlink/data
networks:
- shlink_net
shlink_web_client:
image: shlinkio/shlink-web-client:stable
container_name: shlink_web_client
restart: unless-stopped
ports:
- "127.0.0.1:8081:80"
networks:
- shlink_net
networks:
shlink_net:
driver: bridge
Замените go.вашдомен.ru на реальный поддомен. Оба сервиса — сам Shlink (порт 8080) и веб-клиент для управления (порт 8081) — слушают только 127.0.0.1, наружу их откроет nginx. Запускаем:
docker compose up -d
docker compose logs -f shlink
При первом старте контейнер сам накатит миграции базы данных — в логах должно появиться сообщение о готовности приложения. Если контейнер shlink перезапускается в цикле, почти всегда причина в неверном пароле к БД или в том, что shlink_db ещё не успел подняться — подождите 15-20 секунд и проверьте docker compose ps.
Домен, reverse proxy и SSL
Короткие ссылки и админку удобно развести по разным поддоменам: go.вашдомен.ru — публичный домен для редиректов и API, links.вашдомен.ru — панель управления, закрытая от посторонних. Оба должны указывать A-записью на IP вашего VPS.
Конфиг nginx (/etc/nginx/sites-available/shlink):
server {
listen 80;
server_name go.вашдомен.ru;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name links.вашдомен.ru;
# доступ только для доверенных IP, остальным — 403
allow 203.0.113.10;
deny all;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
}
}
Подробный разбор, как правильно поднять nginx именно как reverse proxy перед Docker-контейнерами, — в статье nginx как reverse proxy на VPS. Активируем конфиг и выпускаем сертификаты через certbot:
ln -s /etc/nginx/sites-available/shlink /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d go.вашдомен.ru -d links.вашдомен.ru
Полный процесс выпуска и автопродления Let's Encrypt сертификатов описан отдельно — см. установку Let's Encrypt SSL на VPS. Альтернатива nginx + certbot — Caddy, который получает сертификат автоматически при первом запуске, без ручных команд; если это ближе вашему стеку, посмотрите Caddy с авто-SSL на VPS.
Ограничение доступа к links.вашдомен.ru по IP или через Basic Auth — не опция, а необходимость: у shlink-web-client нет собственной системы логина, доступ к нему определяется только тем, кто знает API-ключ, введённый в браузере (ключ хранится в localStorage). Если панель открыта всему интернету, найти способ подобрать или перехватить ключ — вопрос времени.
Создание ссылок: API, CLI и веб-интерфейс
API-ключ уже задан переменной INITIAL_API_KEY в .env — при первом старте Shlink создаст его автоматически. Дополнительные ключи (например, отдельный для каждого сотрудника или интеграции) генерируются через CLI:
docker exec -it shlink shlink api-key:generate --name "маркетинг"
Создать короткую ссылку можно прямо из консоли:
docker exec -it shlink shlink short-url:create \
--long-url="https://вашсайт.ru/landing/promo" \
--custom-slug="promo2026"
Или через REST API — это удобно, если ссылки генерируются автоматически из вашего кода, CRM или почтовой рассылки:
curl -X POST https://go.вашдомен.ru/rest/v3/short-urls \
-H "X-Api-Key: ваш_api_key" \
-H "Content-Type: application/json" \
-d '{
"longUrl": "https://вашсайт.ru/landing/promo",
"customSlug": "promo2026",
"tags": ["email", "sept2026"]
}'
В ответе API вернёт готовый короткий URL и метаданные ссылки. Для тех, кто не хочет работать с консолью, есть веб-клиент на links.вашдомен.ru: при первом входе он спросит адрес API-сервера (https://go.вашдомен.ru) и API-ключ, после чего покажет привычный интерфейс — список ссылок, создание новых, теги, QR-коды.
Аналитика, бэкапы и обновление
Каждый переход по короткой ссылке Shlink пишет в базу: время, IP (без хранения в открытом виде, только для геолокации), User-Agent, referrer. В веб-клиенте это превращается в графики по дням, топ стран (если подключен GeoLite2), устройствам и источникам трафика — без передачи данных в Google Analytics или другие внешние системы.
Резервное копирование — это, по сути, дамп базы данных и каталог data/shlink с локальными файлами приложения:
docker compose exec shlink_db mariadb-dump -u root -p shlink > shlink_backup_$(date +%F).sql
tar -czf shlink_data_$(date +%F).tar.gz ./data/shlink
Для регулярных автоматических бэкапов MySQL/MariaDB с ротацией и проверкой целостности имеет смысл сразу настроить cron-задачу по образцу из статьи бэкап MySQL на VPS — там же разобраны типичные ошибки вроде бэкапа «на живую» без --single-transaction.
Обновление до новой версии — обычный pull + пересоздание контейнеров, миграции БД Shlink накатывает сам при старте:
docker compose pull
docker compose up -d
docker compose logs -f shlink
Перед обновлением на мажорную версию (например, со 3.x на 4.x) стоит один раз прочитать changelog проекта на GitHub — там иногда встречаются breaking changes в переменных окружения или структуре API.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Обязательно ли использовать MySQL/MariaDB, или можно проще?
Нет, для небольшого личного проекта Shlink поддерживает SQLite — тогда не нужен отдельный контейнер с базой. Но при росте нагрузки или если вы захотите несколько инстансов Shlink за балансировщиком, MySQL/MariaDB или PostgreSQL надёжнее.
Нужен ли Redis обязательно?
Нет, это опциональный слой кеширования, который снижает нагрузку на базу при большом количестве переходов. Для старта можно запустить и без него, убрав переменную REDIS_SERVERS и сервис shlink_redis из compose-файла.
Как защитить админ-панель, если нет времени настраивать IP-ограничения?
Временный вариант — Basic Auth на уровне nginx (auth_basic + htpasswd) поверх location для links.вашдомен.ru. Это не заменяет полноценную защиту, но закрывает панель от случайных сканеров и ботов.
Можно ли перенести ссылки с bit.ly или другого сервиса?
Да, через API short-url:create с указанием customSlug, совпадающего со старым — если формат позволяет. Массовый перенос удобнее сделать скриптом, который читает экспорт старого сервиса и последовательно вызывает API.
Сколько ссылок и переходов выдержит такая установка?
Точных цифр не дам — многое зависит от того, включён ли Redis, ресурсов VPS и того, как настроена база. Для проекта с несколькими тысячами ссылок и умеренным трафиком описанной конфигурации (1-2 vCPU, 2 GB RAM) обычно хватает с запасом.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →