Sửa lỗi unknown terminal type qua SSH không cần root
Lỗi “unknown terminal type” qua SSH làm chương trình curses dừng vì server thiếu entry terminfo. Tạo entry trong home, không cần root hay đổi TERM.
Ý nghĩa của lỗi “unknown terminal type”
Lỗi kiểu terminal không xác định khi dùng SSH nghĩa là tên trong TERM không có entry tương ứng trong cơ sở dữ liệu terminfo trên server. Terminal emulator đặt tên đó trên laptop của bạn. Cơ sở dữ liệu cần nhận diện tên này nằm trên máy từ xa. Khi tra cứu thất bại, mọi chương trình curses trên server đó đều dừng trước khi vẽ nội dung, vì chúng không có mô tả về các khả năng của terminal bạn đang dùng.
Cách sửa mà vẫn giữ đầy đủ tính năng của terminal emulator là chạy một lệnh: biên dịch entry terminfo riêng vào ~/.terminfo trên server. ncurses tìm trong thư mục home của bạn trước mọi thư mục hệ thống, nên không cần root và không ảnh hưởng đến người dùng khác.
TERM là tên, terminfo là cơ sở dữ liệu
TERM chứa một chuỗi, và chuỗi đó chỉ là một key. terminfo là cơ sở dữ liệu đã biên dịch chứa các mô tả terminal, còn key là cách để chương trình tìm đúng mô tả. Một mô tả ghi lại terminal có bao nhiêu màu, những byte nào di chuyển con trỏ đến dòng 12 cột 40, phím F5 gửi những byte nào và terminal có thể hiển thị gạch chân có định dạng hay không. ncurses, thư viện mà gần như mọi giao diện người dùng dạng văn bản trên Linux đều sử dụng, đọc mô tả đó khi khởi động. Các chương trình như top, less, nano và watch không thể hiển thị dù chỉ một màn hình nếu thiếu mô tả này.
Xem entry của chính bạn:
echo "$TERM"
tput longname
infocmp -1 | head -20tput longname in mô tả ở dạng con người có thể đọc của entry mà TERM chỉ đến. Với xterm-256color, lệnh này in:
xterm with 256 colorsinfocmp -1 giải mã ngược toàn bộ entry và in mỗi capability trên một dòng. Nếu cả hai lệnh đều chạy được, cơ sở dữ liệu trên máy này biết terminal đó. Bạn cũng cần trạng thái này ở đầu bên kia của kết nối SSH.
Vì sao lỗi chỉ xảy ra qua SSH
SSH gửi tên terminal và không gửi thêm thông tin nào khác. Khi client yêu cầu pseudo terminal, TERM sẽ được gửi cùng yêu cầu đó. Tài liệu OpenSSH nêu rõ: “biến môi trường TERM luôn được gửi khi pseudo terminal được yêu cầu vì protocol bắt buộc điều này”. Vì vậy, login shell trên VPS nhận được TERM=xterm-ghostty, hoặc xterm-kitty, hoặc tên mà emulator của bạn đang dùng. Mô tả tương ứng với tên đó vẫn nằm trên laptop, trong database của laptop. Một server được xây dựng trước khi emulator của bạn tồn tại sẽ không biết tên này. Bản thân kết nối SSH không sao chép các mô tả terminal, và đây là thiết kế có chủ ý: protocol chỉ truyền tên, không truyền toàn bộ thông tin capability.
Bạn có thể tái hiện lỗi trên chính máy của mình bằng một tên chắc chắn không tồn tại:
TERM=xterm-nosuchthing tput colors
echo "$?"tput: unknown terminal "xterm-nosuchthing"Exit status là 3. ncurses ghi nhận mã này là loại terminal không xác định hoặc database bị thiếu. Mọi chương trình curses đều thực hiện cùng một lần tra cứu. Vì vậy, một tên bị thiếu tạo ra thông báo khác nhau từ từng chương trình, nhưng nguyên nhân phía sau chỉ có một. nano dừng với Error opening terminal: xterm-nosuchthing., đây là lỗi chuẩn của ncurses khi không thể load mô tả lúc khởi động. vim in ra E558: Terminal entry not found in terminfo. less in ra WARNING: terminal is not fully functional. Một pager chỉ hoạt động được một phần và một editor từ chối khởi động có vẻ như các lỗi không liên quan. Chúng thực chất cùng thiếu một file.
ncurses tìm entry ở đâu
ncurses tìm theo một thứ tự cố định, được ghi trong terminfo(5):
$TERMINFO, nếu biến này được đặt. Chỉ thư mục đó được tìm kiếm.$HOME/.terminfo.- mọi thư mục được liệt kê trong
$TERMINFO_DIRS. - các vị trí được tích hợp khi biên dịch; trên Debian và Ubuntu gồm
/etc/terminfo,/lib/terminfovà/usr/share/terminfo.
Chạy infocmp -D trên server để in danh sách mà bản build ncurses của chính server đó sử dụng, thay vì tin vào các đường dẫn trên. Bước 2 là điểm mấu chốt. Thư mục home của bạn được tìm kiếm trước mọi thư mục hệ thống, vì vậy chỉ cần một file trong ~/.terminfo là đủ sửa lỗi tra cứu cho tài khoản của bạn, không cần cài package và không cần root.
Cách 1: dùng TERM mà server đã biết
Cách bỏ chặn nhanh nhất là chỉ định một terminal khác cho một lần kết nối:
TERM=xterm-256color ssh user@203.0.113.10Để áp dụng vĩnh viễn cho host đó, thêm cấu hình vào ~/.ssh/config trên laptop của bạn:
Host vps1
HostName 203.0.113.10
User deploy
SetEnv TERM=xterm-256colorSetEnv yêu cầu client chạy OpenSSH 7.8 trở lên, được phát hành vào tháng 8 năm 2018. TERM là biến duy nhất không cần server cho phép: tài liệu hướng dẫn ghi rằng “Tương tự SendEnv, ngoại trừ biến TERM, server phải được cấu hình để chấp nhận biến môi trường”. Vì vậy, cách này vẫn hoạt động với sshd đã được harden và hoàn toàn không có dòng AcceptEnv.
Cái giá phải trả là mọi khả năng mà emulator của bạn mô tả ngoài xterm-256color cơ bản. Các khả năng đó gồm màu 24-bit được quảng bá qua capability RGB và gạch chân có style qua Smulx. Chương trình không còn thấy các capability này, nên sẽ chuyển về 256 màu và gạch chân thường. Màn hình vẫn hoạt động. Chỉ là nó ít khả năng hơn terminal bạn đã chọn.
Không nên giải quyết bằng cách thêm export TERM=xterm-256color vào .bashrc trên server. File đó được chạy cho mọi kết nối, kể cả kết nối từ terminal mà server đã biết tên, nên nó sẽ hạ cấp cả những session vốn đã hoạt động đúng. Hãy giữ override ở client, nơi bạn biết mình đang chạy emulator nào.
Sửa 2: gửi entry terminfo lên server một lần
Đây là cách sửa vẫn giữ nguyên emulator của bạn. Decompile entry trên máy cục bộ, pipe qua SSH rồi compile ở máy đích:
infocmp -x | ssh user@203.0.113.10 -- tic -x -infocmp -x in entry của TERM hiện tại dưới dạng source text, bao gồm cả các capability mở rộng (do người dùng tự định nghĩa). tic -x compile source đó trở lại thành binary description trên server. -x ở cả hai phía rất quan trọng, vì nếu thiếu nó thì các capability như Smulx sẽ bị loại bỏ trong quá trình truyền, khiến bạn triển khai một bản terminal của chính mình đã bị hạ cấp.
tic ghi vào system directory nếu có thể, rồi fallback sang $HOME/.terminfo khi user không có quyền ghi tại đó. Account thông thường trên VPS sẽ dùng home directory, đúng với mục đích ở đây. Bạn cũng có thể chỉ định destination:
infocmp -x | ssh user@203.0.113.10 -- tic -x -o '~/.terminfo' /dev/stdinDấu ngoặc kép quanh ~/.terminfo không phải để trang trí. ssh nối các từ của command thành một string rồi truyền cho remote shell, nên ~ không có dấu ngoặc kép sẽ được local shell mở rộng trước. Sau đó bạn gửi một /home/yourname/.terminfo literal đến máy mà account của bạn có thể mang tên khác. tic sẽ fail với lỗi permission, hoặc ghi vào một path mà ncurses không bao giờ tìm kiếm. Hãy đặt dấu ngoặc kép quanh dấu ngã để remote shell mở rộng nó.
Đăng nhập rồi kiểm tra:
ssh user@203.0.113.10
tput longname
ls -R ~/.terminfotput longname in ra description của terminal, cho biết việc lookup đã thành công. ls hiển thị compiled file bên trong một subdirectory được đặt tên theo chữ cái đầu tiên của tên terminal. Sau đó chạy top, hoặc dùng watch -n1 uptime để redraw qua cùng library, nhằm xác nhận một chương trình curses thực sự render được màn hình.
Chi phí là một bước cho mỗi server, và entry nằm trong home directory của một account trên một máy duy nhất. Nếu rebuild VPS thì entry sẽ mất. Đưa command này vào công cụ bạn dùng để provision và quản lý nhiều server cùng lúc để host mới có entry được compile sẵn.
Cách 3: cài cơ sở dữ liệu terminfo mở rộng
Nếu bạn có quyền root và muốn tên này được nhận diện cho mọi tài khoản trên máy:
sudo apt update
sudo apt install ncurses-term
tput -T xterm-ghostty longnamencurses-term chứa các mô tả terminal bị bỏ lại trong bản cài đặt cơ bản. Nó sửa lỗi nhận diện tên cho root và mọi người dùng khác, trong khi cách 2 không làm được điều đó.
Cách này chỉ hữu ích khi entry của terminal bạn có trong bản ncurses được bản phân phối đóng gói, vì vậy hãy kiểm tra thay vì giả định. Ubuntu 24.04 cung cấp ncurses-bin 6.4+20240113-1ubuntu2.1 (tính đến tháng 8 năm 2026). Entry của Ghostty được bổ sung upstream trong ncurses 6.5-20241228, là bản mới hơn, nên apt install ncurses-term trên Ubuntu 24.04 không thể tạo entry xterm-ghostty, dù bạn chạy lệnh này bao nhiêu lần. tput -T <name> longname là lệnh kiểm tra: nó in mô tả khi entry tồn tại và unknown terminal với exit status 3 khi entry không tồn tại.
Để cài một entry duy nhất trên toàn hệ thống thay vì cài cả package, hãy sao chép source rồi compile bằng quyền 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 trong lệnh thứ hai cấp phát một pseudo terminal để sudo có thể yêu cầu nhập password. Nếu không có nó, sudo có thể thoát với sudo: no tty present and no askpass program specified.
Để emulator tự truyền file
Một số emulator có helper tự thực hiện fix 2. kitty có một ssh kitten: kitten ssh myserver kết nối và tự động sao chép terminfo của kitty lên host từ xa. Tài liệu của kitty cũng nêu cách thực hiện thủ công, infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin, trong đó dấu tilde được escape vì lý do đã mô tả ở trên. Ghostty có tài liệu về infocmp -x xterm-ghostty | ssh YOUR-SERVER -- tic -x -, đồng thời cung cấp shell integration (ssh-env và ssh-terminfo) cùng một action +ssh để tự động thực hiện cả hai fix.
Các helper này chạy đúng những command mà bạn vừa chạy thủ công. Việc biết cách thực hiện thủ công vẫn quan trọng, vì helper không thể hoạt động khi connection bắt đầu từ nơi khác, trên jump host hoặc bên trong một script.
Khi lỗi quay lại
Trong sudo -i. Một login shell chạy dưới root đã có HOME=/root, còn sudo giữ TERM của bạn. ncurses lúc này tìm trong /root/.terminfo, nhưng thư mục đó không chứa entry của bạn, nên chỉ root gặp lại lỗi. Xác nhận bằng sudo -i env rồi đọc các dòng HOME và TERM. Cài entry vào thư mục hệ thống hoặc đặt một bản sao vào /root/.terminfo.
Bên trong tmux hoặc screen. Các chương trình này đặt TERM riêng cho những chương trình chạy bên trong, thường là screen-256color hoặc tmux-256color. Một server cũ biết screen-256color nhưng có thể không biết tmux-256color, nên shell bên ngoài vẫn hoạt động bình thường trong khi mọi thứ bên trong session đều lỗi. Nguyên nhân giống nhau, chỉ khác tên. Chạy tput -T tmux-256color longname trên server để xem nó có entry nào trong hai entry đó. Một workbench terminal xây dựng trên tmux che giấu vấn đề này cho đến khi bạn attach vào một host chưa được sửa.
Trên server mới. ~/.terminfo áp dụng riêng cho từng account và từng máy, nên VPS được rebuild sẽ lại bắt đầu với thư mục trống.
Màn hình hiển thị đúng nhưng phím hoạt động sai. Nếu màn hình hiển thị bình thường nhưng phím Home, End hoặc các phím function lại chèn ký tự lạ, tên đã được phân giải thành một entry không khớp với terminal của bạn. Chuỗi phím và khả năng hiển thị đều lấy từ cùng một entry terminfo, nên entry gần đúng chỉ cho ra các phím gần đúng. Đây là kết quả thường gặp của cách sửa 1 trên emulator có chuỗi phím khác xterm. Cách sửa 2 mới giải quyết được vấn đề, vì chỉ entry thực của emulator mới chứa đúng các chuỗi đó.
FAQ
Tại sao tôi chỉ thấy "unknown terminal type" qua SSH?
Vì cơ sở dữ liệu chứa entry của terminal phải nằm trên server. Terminal emulator cài mô tả của nó trên máy đang chạy, nên các chương trình cục bộ có thể tìm thấy mà bạn không cần làm gì thêm. SSH chỉ gửi giá trị của TERM, vì protocol truyền tên đó cùng yêu cầu pseudo-terminal. ncurses trên máy từ xa tra tên trong cơ sở dữ liệu từ xa nhưng không tìm thấy, nên initscr thất bại và chương trình dừng.
Tôi có thể sửa lỗi này mà không cần root trên server không?
Có. ncurses tìm $HOME/.terminfo trước mọi thư mục hệ thống, nên chỉ cần có entry ở đó là đủ cho account của bạn. Chạy infocmp -x | ssh user@host -- tic -x - một lần trên mỗi server. tic sẽ ghi vào home directory của bạn khi không thể ghi vào system path, đây là trường hợp thông thường với account không có quyền cao. Đăng nhập rồi chạy tput longname để xác nhận việc tra cứu đã hoạt động.
Tôi mất gì khi đặt TERM=xterm-256color cho một host?
Bạn mất mọi capability mà terminal emulator của bạn mô tả ngoài entry xterm-256color, chẳng hạn màu 24-bit qua RGB và gạch chân có style qua Smulx. Các chương trình không nhìn thấy những capability đó nên dùng fallback gần nhất. Chuỗi phím function cũng có thể khác terminal thực tế của bạn. Đặt cấu hình trên client trong ~/.ssh/config thay vì trong một .bashrc trên server, vì cách đó sẽ hạ capability của các session từ những terminal vốn đã hoạt động.
Tại sao lỗi xuất hiện lại sau sudo -i?
sudo -i khởi động một login shell với quyền root bằng HOME=/root, nhưng vẫn giữ giá trị TERM của bạn. Khi đó ncurses tìm /root/.terminfo thay vì home directory của bạn và không tìm thấy gì, nên root gặp cùng lỗi mà account của bạn không còn gặp nữa. Chạy sudo -i env và kiểm tra các dòng HOME và TERM. Compile entry vào system directory bằng sudo tic -x -o /usr/share/terminfo, hoặc copy entry vào /root/.terminfo.
apt install ncurses-term có luôn sửa được lỗi này không?
Không. Nó chỉ thêm các entry đã có trong bản ncurses mà distribution của bạn đóng gói. Ubuntu 24.04 ship ncurses 6.4 (ncurses-bin 6.4+20240113-1ubuntu2.1, tính đến tháng 8 năm 2026), còn entry của Ghostty được thêm upstream trong ncurses 6.5-20241228, nên package đó không thể chứa entry này. Kiểm tra bằng tput -T <name> longname trước khi dựa vào package, và tự đưa entry vào khi kết quả kiểm tra vẫn báo unknown terminal.