There is now such an environment.
Deploy a vsftpd server on a Rocky 10.0 or Rocky 10.1 operating system. Create a user named ftpuser, which cannot be used for local login. Create two virtual users, ftp1 and ftp2, and map them to ftpuser.
It seems very simple and basic; we just need to give this requirement to AI, and it can generate a solution for us.
However, AI often misses two key points.
First, although I’ve disabled the ftpuser user from logging in locally—meaning I can’t use this user to access bash, enter the username and password locally, or use SSH, telnet, etc., to log in to the local server—I still want it to be usable for logging into my vsftpd server. The reason is that starting with Rocky 9, the /etc/shells configuration file doesn’t have the /sbin/nologin line by default. CentOS 7, on the other hand, does have this line by default. Therefore, on Rocky 9 or Rocky 10, we need to add the /sbin/nologin line to /etc/shells. You can use echo "/sbin/nologin" >> /etc/shells.
Second, we mostly use libdb to generate virtual user configuration files, employing the db_load command.
However, in Rocky10, configuration files generated in this way cannot be used for virtual user authentication in the vsftpd service. In other words, virtual users created this way cannot log in to the FTP server.
Starting with Rocky 10, the old Berkeley DB (libdb) is deprecated by default. Even if you can download the libdb tool from the ehpl repository, virtual users created using files generated in this way can no longer be used to log in to the vsftpd server. PAM’s virtual user database has been fully switched to GDBM format. However, you can use Python to create virtual user configuration files:
cd /etc/vsftpd
vi vuser.txt
ftp1
123456
ftp2
123456
python3
import dbm, os, pathlib
txt = pathlib.Path(‘/etc/vsftpd/vuser.txt’)
db = dbm.open(‘/etc/vsftpd/vuser’, ‘n’)
lines = txt.read_text().splitlines()
for user, pwd in zip(lines[::2], lines[1::2]):
… db[user.encode()] = pwd.encode()
…
db.close()
exit()
