Sửa lỗi Ansible "Failed to create temporary directory" trên Remote Host

intermediate🔧 Ansible2026-05-07| Ansible 2.9+, Linux remote hosts (Ubuntu, CentOS, RHEL, Debian), kết nối qua SSH

Error Message

Failed to create temporary directory. In some cases, you may have been able to authenticate and did not have permissions on the target directory. Please make sure your login shell is set correctly for your user and the environment is configured properly.
#ansible#tmp#permissions#remote#ssh

Lỗi Gặp Phải

fatal: [web01]: FAILED! => {
    "msg": "Failed to create temporary directory. In some cases, you may have been able to authenticate and did not have permissions on the target directory. Please make sure your login shell is set correctly for your user and the environment is configured properly."
}

Lỗi này xuất hiện ngay sau khi SSH kết nối thành công — Ansible xác thực được rồi nhưng lập tức thất bại khi cố tạo thư mục tạm trước khi chạy bất kỳ task nào. Kết nối SSH hoạt động bình thường, vậy vấn đề nằm sâu hơn một tầng.

Nguyên Nhân

Trước khi thực thi bất kỳ module nào, Ansible tải lên một script Python nhỏ vào thư mục tạm của máy chủ từ xa. Nếu không ghi được vào đó, mọi thứ dừng lại trước khi một task nào được chạy. Nguyên nhân thường rơi vào một số trường hợp sau:

  • /tmp được mount với cờ noexec — Ansible tải script lên đó nhưng không thể thực thi
  • User từ xa không có quyền ghi vào thư mục tạm
  • Login shell bị hỏng, hoặc được đặt là /sbin/nologin hoặc /bin/false
  • $HOME hoặc $TMPDIR không thể ghi hoặc không tồn tại
  • SELinux hoặc AppArmor chặn quyền truy cập filesystem
  • remote_tmp trong ansible.cfg trỏ đến đường dẫn không tồn tại

Cách Khắc Phục Từng Bước

Bước 1 — Xác minh SSH và quyền ghi cơ bản thủ công

SSH vào bằng đúng user mà Ansible dùng, rồi kiểm tra thư mục tạm:

ssh deploy@web01

# User có thể ghi vào /tmp không?
touch /tmp/ansible_test && echo "OK" && rm /tmp/ansible_test

# Kiểm tra cờ mount của /tmp
mount | grep /tmp

Thấy noexec trong kết quả mount? Đó là thủ phạm — chuyển thẳng sang Bước 2.

Bước 2 — Xử lý noexec trên /tmp

Khi /tmp được mount với noexec, hãy chuyển hướng thư mục tạm của Ansible sang nơi có thể thực thi. Thêm vào ansible.cfg:

[defaults]
remote_tmp = ~/.ansible/tmp

Hoặc ghi đè theo từng play nếu không muốn chỉnh config toàn cục:

- hosts: webservers
  vars:
    ansible_remote_tmp: /var/tmp/.ansible
  tasks:
    - name: your task here
      ...

/var/tmp thường không được mount với noexec, nên là lựa chọn dự phòng đáng tin cậy. Hãy xác nhận nó có thể ghi được trước khi dùng.

Bước 3 — Kiểm tra login shell của user từ xa

Shell không hợp lệ khiến môi trường không được cấu hình — Ansible xác thực được nhưng không làm gì tiếp được:

# Trên máy chủ từ xa
grep deploy /etc/passwd
# Đúng: deploy:x:1001:1001::/home/deploy:/bin/bash
# Sai:  deploy:x:1001:1001::/home/deploy:/sbin/nologin

Sửa shell bị hỏng bằng:

sudo usermod -s /bin/bash deploy

Bước 4 — Xác nhận $HOME tồn tại và có thể ghi

ssh deploy@web01
ls -la ~
echo $HOME

Không có thư mục home? Tạo mới:

sudo mkhomedir_helper deploy
# hoặc làm thủ công
sudo mkdir -p /home/deploy && sudo chown deploy:deploy /home/deploy

Bước 5 — Kiểm tra biến môi trường TMPDIR

TMPDIR trỏ đến đường dẫn không tồn tại sẽ làm Ansible thất bại dù /tmp hoạt động bình thường:

ssh deploy@web01 'echo $TMPDIR'

Nếu nó trỏ đến nơi không tồn tại, hãy unset hoặc tạo đường dẫn đó. Nhân tiện, hãy cân nhắc bật pipelining:

[ssh_connection]
pipelining = True

Pipelining truyền code module qua stdin thay vì ghi file tạm trước. Cách này tránh hoàn toàn dạng lỗi này — và giảm số lần SSH round-trip, giúp playbook chạy nhanh hơn như một bonus.

Bước 6 — Kiểm tra SELinux hoặc AppArmor

Trên RHEL/CentOS với SELinux đang enforcing, tìm các AVC denial nhắm vào đường dẫn tạm:

sudo ausearch -m avc -ts recent | grep ansible
# hoặc
sudo journalctl -xe | grep denied

Kiểm tra nhanh — tạm thời chuyển sang chế độ permissive (đừng để vậy):

sudo setenforce 0
# Chạy lại playbook để xác nhận SELinux có phải nguyên nhân không
sudo setenforce 1

Nếu lỗi biến mất, hãy viết policy rule SELinux đúng cách. Tắt enforcement chỉ là bước kiểm tra, không phải cách khắc phục.

Bước 7 — Chạy với verbosity tối đa

Vẫn chưa tìm ra? Tăng verbosity lên 4 và lọc theo đường dẫn tạm để xem chính xác Ansible đang làm gì:

ansible-playbook site.yml -i inventory -vvvv 2>&1 | grep -i tmp

Kết quả sẽ hiển thị đúng thư mục Ansible cố ghi vào — thường giúp nhận ra nguyên nhân gốc rễ ngay lập tức.

Kiểm Tra Sau Khi Sửa

# Ping máy chủ — lệnh này kiểm tra toàn bộ quá trình thiết lập thư mục tạm
ansible web01 -m ping -i inventory

# Kết quả mong đợi:
web01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

SUCCESS ở đây có nghĩa Ansible đã tạo được file tạm và thực thi module thành công. Vấn đề đã được giải quyết.

Mẹo Thêm

Với các pipeline CI/CD mà bạn không kiểm soát được cờ mount của /tmp, hãy cố định remote_tmp vào một thư mục con dưới $HOME. Nó luôn có thể ghi, luôn có thể thực thi, và không phụ thuộc vào cách ops team mount ổ đĩa:

[defaults]
remote_tmp = ~/.ansible/tmp
local_tmp  = ~/.ansible/tmp

Kết hợp với pipelining được bật, bạn đã loại bỏ hoàn toàn dạng lỗi liên quan đến file tạm cho hầu hết các cấu hình:

[ssh_connection]
pipelining = True

Một lưu ý quan trọng: pipelining yêu cầu requiretty phải được tắt trong /etc/sudoers khi dùng become. Thêm Defaults !requiretty vào sudoers, nếu không sudo sẽ từ chối chạy khi không có TTY và bạn sẽ đổi lỗi này lấy lỗi khác.

Nếu bạn đang thiết lập quyền cho remote_tmp thủ công và không nhớ các giá trị octal, Unix Permissions Calculator trên ToolCraft giúp bạn tính toán mà không cần nhẩm trong đầu.

Related Error Notes