0887 371 498 support@itservice-bg.net
Starlink ми къса SSH и VPN сесиите — защо се случва и как да го спрем
14.07.2026 · Самуил Арсов · MikroTik, Ubuntu, Рутери

Starlink ми къса SSH и VPN сесиите — защо се случва и как да го спрем

От известно време минах на Starlink за интернет на едно от местата, от които работя. Скоростта и латентността са напълно прилични, но много бързо забелязах един досаден проблем: SSH сесиите ми започнаха да „умират“. Отварям терминал към сървъра, поработвам, отскачам за няколко минути — и когато се върна, терминалът е замръзнал. Натисна ли клавиш, след секунда получавам класическото:

client_loop: send disconnect: Broken pipe
# или
Write failed: broken pipe

Същото се случва и с VPN-а ми — тунелът пада точно по същия начин, след кратко бездействие. А най-неприятното: в един момент вече не можех да вляза в собствения си MikroTik рутер зад Starlink, защото връзката до него минава именно през този тунел.

Ако и вие сте на Starlink (или на мобилен/4G интернет) и виждате същото — не е повреден кабел, не е бъгав сървър и не е вашият Ubuntu. Причината е в начина, по който Starlink прави NAT. В тази статия обяснявам какво точно се случва, защо Starlink го прави (и защо не е нарочно) и как с две прости настройки нещата се оправят напълно.

Симптомът: сесията пада само когато „кротува“

Ключовото наблюдение е, че сесията никога не пада, докато активно пишеш или тегли данни. Пада само след като е стояла без трафик известно време — при мен около 10 минути. Точно това е важната следа: проблемът не е в самата връзка, а в нещо, което забравя за връзката, когато тя утихне.

Накратко: прекъсва се бездействаща TCP сесия. Активният трафик я държи жива; тишината я убива. Това веднага сочи към NAT с агресивен таймаут, а не към прекъсване на линка.

Виновникът: CGNAT (Carrier-Grade NAT)

Starlink, както почти всички сателитни и мобилни оператори, не дава истински публичен IP на всеки клиент. Вместо това хиляди абонати споделят една „шепа“ публични адреси, а операторът пъха всички зад голям NAT в мрежата си. Това се нарича CGNAT — Carrier-Grade NAT (NAT на ниво оператор). На практика вашият рутер е зад два NAT-а: вашия домашен и този на Starlink.

За да работи NAT, устройството, което го прави, трябва да пази таблица на връзките — т.нар. conntrack таблица. За всяка активна TCP/UDP сесия има ред в тази таблица, който казва „пакетите за тази връзка отиват към този вътрешен клиент“. Без този ред връщащият се трафик просто няма накъде да отиде.

Защо Starlink „чисти“ връзките — и защо не е нарочно

Ето и същината. За да не расте безкрайно, всеки запис в conntrack таблицата има таймаут за бездействие. Ако през определено време по дадена сесия не мине нито един пакет, записът се изтрива, за да освободи място. Стандартните таймаути в Linux са щедри (за установена TCP сесия — по подразбиране дни). Но операторите с CGNAT нарочно ги свиват драстично — при Starlink на практика около 10 минути за бездействащ TCP.

Важно е да се разбере, че това не е злоба и не е насочено срещу вас. Това е инженерен компромис за мащаб:

По-кратък таймаут означава… Защо е добре за оператора
По-малка conntrack таблица По-малко използвана памет (RAM) — един NAT обслужва милиони едновременни сесии.
По-бързо търсене в таблицата По-малката таблица се събира по-добре в кеша на процесора → всеки пакет се обработва по-бързо.
По-бърз рутер при същия хардуер По-ниска латентност и по-висок капацитет — процесорите не се задавят от огромна таблица.

Тоест — точно защото „чисти“ бездействащите сесии, NAT-ът на оператора остава бърз: пази малко в паметта, процесорите не се задавят и таблицата остава компактна. За абонат, който гледа видео или сърфира, това е напълно невидимо — тези връзки не стоят без трафик. Проблемът се вижда само при дълготрайни, тихи сесии като SSH терминал, който е отворен, но в момента не пишеш нищо, или VPN тунел в покой.

Механизмът стъпка по стъпка: отваряш SSH → NAT създава запис → мълчиш 10 мин → таймаутът изтича → NAT трие записа → сървърът отговаря, но връщащият пакет вече няма ред в таблицата → пакетът се губи → операционната система в един момент го отчита като Broken pipe.

Решение 1: SSH keepalive (пращай „жив съм“ на всеки 30 сек)

Щом проблемът е, че сесията утихва и NAT я забравя — решението е тя никога да не утихва. Караме SSH клиента да праща по едно мъничко служебно пакетче през интервал, по-кратък от таймаута на оператора. Всеки такъв пакет нулира таймера в conntrack таблицата и записът остава жив.

За бърз тест го подавам направо на командата (точно с това започнах и нещата веднага се оправиха):

ssh -o ServerAliveInterval=30 potrebitel@moya-server.bg

Какво прави тази опция: на всеки 30 секунди без данни клиентът праща криптиран keepalive до сървъра и очаква отговор. Това е достатъчно често, за да не остане връзката „тиха“ за 10 минути. Ако искате да сте още по-стриктни, добавете и ServerAliveCountMax — колко пропуснати отговора да се изтърпят, преди клиентът да се откаже:

ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=5 potrebitel@moya-server.bg

Разбира се, не е удобно да пишете това всеки път. За постоянно го слагам веднъж в ~/.ssh/config на моя Ubuntu Desktop и после всяко ssh го наследява автоматично:

# ~/.ssh/config
Host *
    ServerAliveInterval 30
    ServerAliveCountMax 5

Готово — от този момент нито една SSH сесия не пада заради Starlink, независимо колко дълго я оставям отворена.

Бонус: същото и откъм сървъра

Ако администрирате сървъра, можете да поставите огледалната настройка и там, за да пази той връзките към всички клиенти (полезно, когато не всеки клиент е конфигуриран). В /etc/ssh/sshd_config:

# /etc/ssh/sshd_config
ClientAliveInterval 30
ClientAliveCountMax 5

След промяната презаредете услугата: sudo systemctl reload ssh.

Решение 2: keepalive на VPN-а (L2TP на MikroTik)

Абсолютно същата логика важи и за VPN. При мен MikroTik рутерът е зад CGNAT-а на Starlink — а зад CGNAT не може да се насочи порт отвън към него (нямате публичен адрес, който да е само ваш). Затова достъпът до такъв рутер се прави обратно: самият MikroTik се набира навън и вдига L2TP тунел към VPN сървър с постоянен адрес, а после аз влизам в рутера през тунела.

Проблемът е, че ако по тунела няма трафик, CGNAT-ът на Starlink изтрива и неговата сесия — точно както при SSH — и тунелът увисва. Затова се налагаше да чакам преизграждане, а понякога изобщо не можех да вляза. Лекът е keepalive на L2TP клиента, така че тунелът да праща периодично служебни пакети и NAT-ът да не го забравя.

На MikroTik (RouterOS) L2TP клиентът има параметър keepalive-timeout. Свеждам го до 30 секунди:

/interface l2tp-client
set [find name="l2tp-out1"] keepalive-timeout=30

С това рутерът праща Hello по тунела на всеки 30 сек. и записът в conntrack таблицата на Starlink остава жив — тунелът вече не пада „от само себе си“. Проверка на състоянието:

/interface l2tp-client print detail
# статусът трябва да е "connected", а не да превърта

Ако ползвате L2TP/IPsec (тунелът е криптиран с IPsec), добавете и по-агресивен DPD (Dead Peer Detection) в IPsec профила, за да поддържа и той връзката жива:

/ip ipsec profile
set [find name="default"] dpd-interval=30s dpd-maximum-failures=5

Бонус: истинска устойчивост — mosh и tmux

Keepalive решава проблема в 99% от случаите. Но ако интернетът наистина изчезне за минута (сателитен hand-off, дъжд, местене на антената), никакъв keepalive няма да спаси една чиста SSH сесия. За такива случаи има два инструмента, които ползвам:

  • mosh — заместител на SSH, който работи върху UDP и преживява смяна на IP и прекъсвания: връзката „замръзва“ и се възстановява сама, без Broken pipe. Идеален за нестабилен/мобилен интернет.
  • tmux / screen — държат сесията ви на сървъра. Дори да ви изхвърли, влизате пак и правите tmux attach — всичко продължава оттам, откъдето е спряло. Задължителни при дълги операции (ъпдейти, копиране, компилиране).

Заключение

„Скъсаният терминал“ зад Starlink изглежда като мистична повреда, но има съвсем земно обяснение: CGNAT с кратък таймаут за бездействие, който операторът поддържа нарочно — за да е рутерът му бърз и таблицата му компактна. Това не е бъг, а компромис за мащаб, и не е насочен срещу вас.

Решението е също толкова просто: дръжте връзката „жива“ с малко периодичен трафик. За SSH — ServerAliveInterval 30 в ~/.ssh/config. За VPN — keepalive-timeout=30 на L2TP клиента (плюс DPD при IPsec). Две настройки, и работата зад сателита става също толкова спокойна, колкото по кабел.

Изграждаме и поддържаме стабилни фирмени мрежи, VPN свързаност между офиси и MikroTik конфигурации — включително зад CGNAT/сателитен интернет. Ако имате подобен проблем, свържете се с нас.