Ошибка unknown terminal type при подключении по SSH
Ошибка возникает из-за отсутствия записи в базе terminfo на сервере. Исправьте проблему без прав root, скомпилировав описание терминала в домашнем каталоге пользователя.
Что означает ошибка "unknown terminal type"
Ошибка неизвестного типа терминала при подключении по SSH означает, что имя в TERM отсутствует в базе данных terminfo на сервере. Ваш эмулятор задает это имя на локальном компьютере. База данных, которая должна распознать это имя, находится на удаленной машине. Если поиск завершается неудачей, любая программа, использующая curses на этом сервере, останавливается до вывода какой-либо информации, так как у нее нет описания возможностей вашего терминала.
Решение, которое сохраняет все функции вашего эмулятора, выполняется одной командой: скомпилируйте собственную запись terminfo в ~/.terminfo на сервере. Библиотека ncurses выполняет поиск в вашем домашнем каталоге перед любым системным каталогом (ранее проверяется только переменная $TERMINFO, если она задана), поэтому для этого не требуются права root, и изменения не затрагивают других пользователей.
TERM — это имя, terminfo — это база данных
TERM содержит одну строку, и эта строка является лишь ключом. terminfo — это скомпилированная база данных описаний терминалов, а ключ определяет, как программа находит нужное описание. Описание фиксирует, сколько цветов поддерживает терминал, какие байты перемещают курсор в строку 12, столбец 40, какие байты отправляет клавиша F5 и умеет ли терминал отображать стилизованное подчеркивание. ncurses, библиотека, на которой построены почти все текстовые пользовательские интерфейсы в Linux, считывает это описание при запуске. Программы вроде top, less, nano и watch не могут отрисовать ни одного экрана без него.
Посмотрите на свою запись:
echo "$TERM"
tput longname
infocmp -1 | head -20tput longname выводит описание в человекочитаемом виде для того, что указано в TERM. Для xterm-256color она выводит:
xterm with 256 colorsinfocmp -1 декомпилирует запись и выводит по одной возможности на строку. Она пропускает расширенные (пользовательские) возможности, если вы не добавите -x, как в infocmp -1 -x. Если обе команды работают, база данных на этой машине знает этот терминал. Это состояние, которое вам необходимо иметь и на удаленной стороне SSH-соединения.
Почему это ломается только по SSH
SSH передает только имя и ничего больше. Когда клиент запрашивает псевдотерминал, TERM отправляется вместе с этим запросом. Руководство OpenSSH прямо указывает: «переменная окружения TERM всегда отправляется при запросе псевдотерминала, так как это требуется протоколом». Поэтому ваша оболочка входа на VPS получает TERM=xterm-ghostty, или xterm-kitty, или любое другое имя, которое использует ваш эмулятор. Описание, соответствующее этому имени, остается на вашем ноутбуке, в локальной базе данных. Сервер, созданный до появления вашего эмулятора, ничего не знает об этом имени. Ничто в самом SSH-соединении не копирует описания терминалов, и это сделано намеренно: протокол передает имя, а не дамп возможностей.
Воспроизведите сбой на своей машине с именем, которого заведомо не существует:
TERM=xterm-nosuchthing tput colors
echo "$?"tput: unknown terminal "xterm-nosuchthing"Код завершения равен 3, что в документации ncurses означает неизвестный тип терминала или отсутствие базы данных. Каждая программа на базе curses выполняет один и тот же поиск, поэтому одно отсутствующее имя вызывает разные сообщения у разных программ, хотя причина у них общая. nano завершается с Error opening terminal: xterm-nosuchthing. — это стандартная ошибка ncurses, возникающая, когда программа не может загрузить описание при запуске. vim выводит E558: Terminal entry not found in terminfo. less выводит WARNING: terminal is not fully functional. Пейджер, который работает частично, и редактор, который отказывается запускаться, выглядят как несвязанные ошибки. На самом деле это один и тот же отсутствующий файл.
Где ncurses ищет описание терминала
ncurses выполняет поиск в строго определенном порядке, описанном в terminfo(5):
$TERMINFO, если эта переменная задана. Она проверяется первой.$HOME/.terminfo.- Все каталоги, перечисленные в
$TERMINFO_DIRS. - Пути, заданные при компиляции; в Debian и Ubuntu это
/etc/terminfo,/lib/terminfoи/usr/share/terminfo.
Запустите infocmp -D на сервере, чтобы вывести список путей, используемый вашей сборкой ncurses, вместо того чтобы полагаться на пути выше. Шаг 2 — это основной способ решения задачи. Ваш домашний каталог проверяется раньше любого системного, поэтому один файл в ~/.terminfo исправляет поиск для вашей учетной записи без установки пакетов и прав root. Единственное исключение — шаг 1: если echo "$TERMINFO" выводит какой-либо путь на сервере, этот каталог проверяется первым, и описание с тем же именем в нем будет иметь приоритет над вашим.
Исправление 1: используйте TERM, который уже известен серверу
Самый быстрый способ снять блокировку — указать другой терминал для одного подключения:
TERM=xterm-256color ssh user@203.0.113.10Сделайте это постоянным для данного хоста в ~/.ssh/config на вашем ноутбуке:
Host vps1
HostName 203.0.113.10
User deploy
SetEnv TERM=xterm-256colorИспользование SetEnv для переопределения TERM требует OpenSSH 8.7 или новее на клиенте, выпущенного в августе 2021 года. Более старые клиенты отправляют TERM вашего эмулятора независимо от этой строки. TERM — это единственная переменная, которая не требует разрешения сервера: в руководстве сказано: «Аналогично SendEnv, за исключением переменной TERM, сервер должен быть готов принять переменную окружения». Поэтому это работает даже против защищенного sshd без какой-либо строки AcceptEnv.
Цена вопроса: всё, что ваш эмулятор описывает сверх обычного xterm-256color. Это включает 24-битный цвет, заявленный через возможность RGB, и стилизованные подчеркивания через Smulx. Программы, полагающиеся на запись в terminfo, больше не видят эти возможности, поэтому они переключаются на 256 цветов и обычное подчеркивание, если вы не настроите их на отправку последовательностей принудительно. Vim, например, всё ещё может отображать 24-битный цвет с помощью set termguicolors, так как его встроенные последовательности t_8f и t_8b работают для большинства терминалов. Экран работает. Он просто обладает меньшими возможностями, чем выбранный вами терминал.
Не решайте эту проблему добавлением export TERM=xterm-256color в ваш .bashrc на сервере. Этот файл выполняется при каждом подключении, включая подключения с терминала, имя которого сервер знает, поэтому он ухудшает сессии, которые уже работали корректно. Оставляйте переопределение на клиенте, где вы знаете, какой эмулятор используете.
Способ 2: однократная отправка записи terminfo на сервер
Это решение позволяет сохранить настройки вашего эмулятора. Декомпилируйте запись локально, передайте её через SSH и скомпилируйте на удаленной стороне:
infocmp -x | ssh user@203.0.113.10 -- tic -x -infocmp -x выводит запись для вашего текущего TERM в виде исходного текста, включая расширенные (пользовательские) возможности. tic -x компилирует этот исходный код обратно в бинарное описание на сервере. Использование -x с обеих сторон критически важно: без него такие возможности, как Smulx, теряются при передаче, и вы получаете урезанную копию настроек своего терминала.
tic записывает данные в системный каталог, если это возможно, и переключается на $HOME/.terminfo, если у пользователя нет прав на запись. Обычная учетная запись на VPS использует домашний каталог, что вам и нужно. Вы также можете указать путь назначения:
infocmp -x | ssh user@203.0.113.10 -- tic -x -o '~/.terminfo' /dev/stdinКавычки вокруг ~/.terminfo — это не украшение. ssh объединяет слова команды в одну строку и передает её удаленной оболочке, поэтому не взятый в кавычки ~ будет сначала раскрыт вашей локальной оболочкой. В результате вы отправите литерал /home/yourname/.terminfo на машину, где ваша учетная запись может называться иначе. tic завершится ошибкой доступа или запишет файл по пути, который ncurses никогда не проверяет. Используйте кавычки для тильды, чтобы её раскрыла удаленная оболочка.
Войдите в систему и проверьте:
ssh user@203.0.113.10
tput longname
ls -R ~/.terminfoЕсли tput longname выводит описание вашего терминала, значит, поиск прошел успешно, а ls показывает скомпилированный файл в подкаталоге, названном по первой букве имени терминала. Затем запустите top или watch -n1 uptime, которая обновляет экран через ту же библиотеку, чтобы убедиться, что полноценная программа на базе curses корректно отрисовывает экран.
Цена решения: один шаг для каждого сервера, при этом запись хранится в домашнем каталоге конкретной учетной записи на одной машине. При переустановке VPS запись будет удалена. Добавьте эту команду в инструменты, которые вы используете для автоматизированной настройки и управления несколькими серверами одновременно, чтобы новый хост сразу содержал скомпилированную запись.
Исправление 3: установка расширенной базы данных terminfo
Если у вас есть права root и вы хотите, чтобы имя терминала распознавалось для всех учетных записей на сервере:
sudo apt update
sudo apt install ncurses-term
tput -T xterm-ghostty longnamencurses-term содержит описания терминалов, которые отсутствуют в базовой установке. Это исправляет имя для root и для всех остальных пользователей, чего не делает исправление 2.
Это помогает только в том случае, если запись вашего терминала существует в версии ncurses, включенной в ваш дистрибутив, поэтому проверяйте, а не предполагайте. Ubuntu 24.04 поставляет ncurses-bin 6.4+20240113-1ubuntu2.2 (по состоянию на октябрь 2026 года). Запись Ghostty была добавлена в апстрим ncurses 6.5-20241228, что является более новой версией, поэтому apt install ncurses-term в Ubuntu 24.04 не может создать запись xterm-ghostty, как бы часто вы её ни запускали. tput -T <name> longname — это способ проверки: команда выводит описание, если запись присутствует, и unknown terminal с кодом завершения 3, если её нет.
Чтобы установить одну запись для всей системы вместо всего пакета, скопируйте исходный код и скомпилируйте его от имени root:
infocmp -x | ssh user@203.0.113.10 -- 'cat > /tmp/term.src'
ssh -t user@203.0.113.10 -- sudo tic -x -o /usr/share/terminfo /tmp/term.srcФлаг -t во второй команде выделяет псевдотерминал, чтобы sudo мог запросить пароль. Без него sudo может завершиться с ошибкой sudo: no tty present and no askpass program specified.
Позвольте эмулятору выполнить перенос
Некоторые эмуляторы поставляют вспомогательные инструменты, которые выполняют исправление 2 за вас. kitty имеет ssh kitten: kitten ssh myserver подключается и автоматически копирует terminfo для kitty на удаленный хост. В его документации также приводится ручной способ, infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin, где тильда экранирована по описанной выше причине. Ghostty документирует infocmp -x xterm-ghostty | ssh YOUR-SERVER -- tic -x -, а начиная с версии 1.2.0 включает дополнительные (опциональные) функции интеграции с оболочкой (ssh-env и ssh-terminfo), которые автоматизируют оба исправления. В его документации также описана обертка ghostty +ssh, которая по состоянию на октябрь 2026 года существует только в версиях для разработки и отсутствует в релизах 1.3.x.
Эти вспомогательные инструменты выполняют те же команды, которые вы только что ввели вручную. Знание ручного способа по-прежнему важно, так как инструмент не может сработать, если соединение инициируется в другом месте, на jump host или внутри скрипта.
Когда ошибка возвращается
В условиях sudo -i. Login shell для пользователя root имеет HOME=/root, а sudo сохраняет ваш TERM. Теперь ncurses ищет /root/.terminfo, где ваша запись отсутствует, поэтому ошибка возвращается только для root. Проверьте это с помощью sudo -i env и прочитайте строки HOME и TERM. Добавьте запись в системный каталог или разместите копию в /root/.terminfo.
Внутри tmux или screen. Эти программы устанавливают собственные TERM для запущенных внутри них процессов, обычно это screen-256color или tmux-256color. Старый сервер знает screen-256color и может не знать tmux-256color, поэтому внешняя оболочка работает корректно, а всё внутри сессии выдает ошибку. Причина та же, но имя другое. Запустите tput -T tmux-256color longname на сервере, чтобы узнать, какой из этих вариантов используется. Рабочее окружение на базе tmux скрывает эту проблему до того дня, пока вы не подключитесь к хосту, который еще не настроили.
На новом сервере. ~/.terminfo привязана к конкретной учетной записи и машине, поэтому на переустановленном VPS она снова будет пустой.
Экран отрисовывается, но клавиши работают неверно. Если изображение выводится корректно, но клавиши Home, End или функциональные клавиши вставляют посторонние символы, значит, имя разрешилось в запись, которая не соответствует вашему терминалу. Последовательности клавиш берутся из той же записи terminfo, что и возможности отрисовки, поэтому приблизительная запись дает приблизительную работу клавиш. Это обычный результат применения исправления 1 на эмуляторе, последовательности клавиш которого отличаются от xterm. Исправление 2 является верным решением, так как только реальная запись вашего эмулятора содержит правильные последовательности.
FAQ
Почему при подключении по SSH я вижу ошибку "unknown terminal type"?
Потому что база данных с описаниями терминалов должна находиться на сервере. Ваш эмулятор устанавливает описание на той машине, где он запущен, поэтому локальные программы находят его без дополнительных действий. SSH передает только значение переменной TERM, так как протокол переносит это имя вместе с запросом на создание псевдотерминала. Удаленная библиотека ncurses ищет это имя в удаленной базе данных, не находит его, поэтому initscr завершается с ошибкой, и программа прекращает работу.
Можно ли исправить это без прав root на сервере?
Да. ncurses выполняет поиск в $HOME/.terminfo перед любыми системными директориями. Ранее проверяется только переменная $TERMINFO, установленная на сервере, поэтому в обычном случае записи в домашней директории достаточно для вашей учетной записи. Выполните infocmp -x | ssh user@host -- tic -x - один раз для каждого сервера. tic записывает данные в вашу домашнюю директорию, если у программы нет прав на запись в системный путь, что является стандартной ситуацией для непривилегированного пользователя. Войдите в систему и выполните tput longname, чтобы убедиться, что поиск теперь работает корректно.
Что я теряю, устанавливая TERM=xterm-256color для хоста?
Все возможности, которые ваш эмулятор описывает сверх записи xterm-256color, например, 24-битный цвет через RGB и стилизованные подчеркивания через Smulx. Программы, полагающиеся на запись terminfo, не видят эти возможности и используют ближайший доступный вариант, если вы не настроите их иначе (как это делает опция termguicolors в Vim для поддержки цветов). Последовательности функциональных клавиш также могут отличаться от тех, что использует ваш реальный терминал. Устанавливайте эту настройку на клиенте в ~/.ssh/config, а не в .bashrc на сервере, так как это ухудшит работу сессий для терминалов, которые уже функционировали корректно.
Почему ошибка возвращается после sudo -i?
sudo -i запускает login shell от имени root с флагом HOME=/root, сохраняя при этом значение вашей переменной TERM. В этом случае ncurses ищет данные в /root/.terminfo вместо вашей домашней директории и ничего не находит, поэтому root сталкивается с той же ошибкой, которую вы уже устранили для своей учетной записи. Выполните sudo -i env и проверьте строки HOME и TERM. Скомпилируйте запись в системную директорию с помощью sudo tic -x -o /usr/share/terminfo или скопируйте её в /root/.terminfo.
Всегда ли apt install ncurses-term решает проблему?
Нет. Эта команда добавляет только те записи, которые присутствовали в версии ncurses, упакованной в вашем дистрибутиве. Ubuntu 24.04 поставляется с ncurses 6.4 (ncurses-bin 6.4+20240113-1ubuntu2.2, по состоянию на октябрь 2026 года), а запись для Ghostty была добавлена в апстрим только в ncurses 6.5-20241228, поэтому в текущем пакете её быть не может. Проверяйте наличие записи с помощью tput -T <name> longname, прежде чем полагаться на пакет, и добавляйте описание терминала самостоятельно, если проверка по-прежнему сообщает о неизвестном типе.