홈 서버 만들기 11. FTPS: vsftpd

May 10, 2018

서버 – 클라이언트 사이의 파일 전송에 널리 사용되는 FTP 서버를 구축한다. 앞선 글 07. SSL/TLS 인증서를 참고해서 발급받은 인증서를 결합하면 연결 과정이 암호화되어 보안이 강화되는 FTPS를 사용할 수 있다. 리눅스의 FTP 서버 프로그램으로 널리 쓰이는 vsftpd를 이용해서 FTPS를 구축한다.

vsftpd 설치

sudo apt-get update
sudo apt-get install vsftpd

패키지 저장소 내용을 업데이트하고, vsftpd를 설치한다.

vsftpd 설정

sudo nano /etc/vsftpd.conf

nano 편집기로 vsftpd의 설정 파일 vsftpd.conf을 연다.

vsftpd 3.0.3 버전의 vsftpd.conf 파일을 기준으로, 내가 설정한 내용을 순서대로 모두 나열하면 아래와 같다. 빨간색 부분은 기본값을 변경한 것이고, 파란색 부분은 vsftpd.conf 파일에 없는 내용을 새로 추가한 것이다.

listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
#anon_upload_enable=YES
#anon_mkdir_write_enable=YES
dirmessage_enable=YES
use_localtime=NO
xferlog_enable=YES
connect_from_port_20=YES
#chown_uploads=YES
#chown_username=whoever
#xferlog_file=/var/log/vsftpd.log
#xferlog_std_format=YES
#idle_session_timeout=600
#data_connection_timeout=120
#nopriv_user=ftpsecure
#async_abor_enable=YES
#ascii_upload_enable=YES
#ascii_download_enable=YES
#ftpd_banner=Welcome to blah FTP service.
#deny_email_enable=YES
#banned_email_file=/etc/vsftpd.banned_emails
#chroot_local_user=YES
chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES
local_root=/home/mydata
passwd_chroot_enable=YES
#ls_recurse_enable=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/letsencrypt/live/example.com/cert.pem
rsa_private_key_file=/etc/letsencrypt/live/example.com/privkey.pem
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
require_ssl_reuse=YES
ssl_ciphers=HIGH
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1=YES
pasv_enable=YES
pasv_min_port=55100
pasv_max_port=55120
pasv_address=123.123.123.123
#pasv_addr_resolve=YES
userlist_enable=YES
userlist_file=/etc/vsftpd.user_list
userlist_deny=NO
utf8_filesystem=YES

이 옵션들의 내용을 살펴보면 아래와 같다. vsftpd 웹사이트의 설명을 함께 참고하면 좋다.

기본 설정

listen=YES  → 독립된 (standalone) FTP 서버로 작동하도록 했다.
listen_ipv6=NO  → 나의 환경에는 아직 IPv6가 보급되지 않아서 NO로 설정했다.
write_enable=YES  → 앞의 주석 #을 제거해서 FTP를 통해 쓰기가 가능하도록 설정했다.
local_umask=022  → 앞의 주석 #을 제거해서 umask를 022로 지정하면 FTP를 통해 생성되는 파일의 권한이 644, 디렉토리의 권한이 755로 설정된다.
use_localtime=NO  → 내 경우엔 NO로 설정해야 Filezilla 등의 FTP 클라이언트 프로그램에서 파일의 생성 시간이 올바르게 표기되었다.

상위 디렉토리 접근 설정

local_enable=YES

vsftpd.conf 파일의 앞부분에 있는 local_enable=YES 항목을 기본값 YES 그대로 두면 FTP 접속 계정으로 우분투 서버에 생성되어 있는 사용자 계정을 그대로 사용하게 된다. 이때 FTP에 접속했을 때 기본으로 열리는 각 사용자의 홈 디렉토리는 /etc/passwd 파일에 지정된 우분투 서버 상의 각 사용자의 홈 디렉토리가 그대로 사용된다. 사용자가 자신의 홈 디렉토리를 빠져나와서 서버의 다른 부분에까지 접근할 수 있게 할지 여부는 vsftpd.conf 파일의 중간 부분에 있는 chroot 설정으로 제어한다. 아래에서 여러 가지 경우를 살펴본다.

#chroot_local_user=YES
#chroot_list_enable=YES
#chroot_list_file=/etc/vsftpd.chroot_list

chroot 옵션을 위와 같이 모두 #으로 주석 처리한 기본값인 상태에서는 모든 사용자가 자신의 홈 디렉토리보다 상위 디렉토리로 빠져나갈 수 있다. 따라서 모든 사용자가 서버 내부의 다른 곳으로 접근할 수 있게 된다.

chroot_local_user=YES
#chroot_list_enable=YES
#chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES

이렇게 chroot_local_user=YES만 주석 #을 제거하고 allow_writeable_chroot=YES를 추가하면 모든 사용자가 자신의 홈 디렉토리를 빠져나갈 수 없다. allow_writeable_chroot=YES는 vsftpd.conf 파일에 없는 항목이므로 직접 추가해야 한다. 추가하지 않으면 어떤 사용자도 FTP에 접속 자체가 안 된다.

chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES

이렇게 모두 주석 #을 제거하고 allow_writeable_chroot=YES를 추가하면 /etc/vsftpd.chroot_list 파일에 기록된 사용자만 자신의 홈 디렉토리보다 상위 디렉토리로 빠져나갈 수 있고, 다른 사용자는 자신의 홈 디렉토리를 못 빠져나간다. allow_writeable_chroot=YES는 vsftpd.conf 파일에 없는 항목이므로 직접 추가해야 한다. 추가하지 않으면 /etc/vsftpd.chroot_list 파일에 기록되지 않은 사용자는 FTP에 접속 자체가 안 된다. /etc/vsftpd.chroot_list 파일을 편집할 때는 sudo nano /etc/vsftpd.chroot_list 명령으로 nano 편집기로 열어서 허용할 사용자를 1줄에 1명씩 기록하고 저장한다. 만일 /etc/vsftpd.chroot_list 파일에 아무도 기록되어 있지 않으면 아무도 자신의 홈 디렉토리를 빠져나갈 수 없다.

#chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES

이렇게 chroot_local_user=YES#으로 주석 처리하면 /etc/vsftpd.chroot_list 파일에 기록된 사용자만 자신의 홈 디렉토리를 못 빠져나가고, 다른 사용자는 자신의 홈 디렉토리보다 상위 디렉토리로 빠져나갈 수 있다. 앞서 chroot_local_user=YES의 주석 #을 제거했을 때와는 반대로 작동하는 것이다. allow_writeable_chroot=YES는 vsftpd.conf 파일에 없는 항목이므로 직접 추가해야 한다. 추가하지 않으면 /etc/vsftpd.chroot_list 파일에 기록된 사용자는 FTP에 접속 자체가 안 된다. /etc/vsftpd.chroot_list 파일을 편집할 때는 sudo nano /etc/vsftpd.chroot_list 명령으로 nano 편집기로 열어서 차단할 사용자를 1줄에 1명씩 기록하고 저장한다. 만일 /etc/vsftpd.chroot_list 파일에 아무도 기록되어 있지 않으면 모두가 자신의 홈 디렉토리를 빠져나갈 수 있다.

홈 디렉토리 제어

local_root=/home/mydata

vsftpd.conf 파일에 local_root= 옵션을 추가하면 모든 사용자의 홈 디렉토리가 이 옵션에 지정한 /home/mydata로 변경되고, chroot 설정은 /home/mydata 를 기준으로 빠져나갈 수 있거나 없도록 설정된다.

passwd_chroot_enable=YES

이 옵션은 우분투 서버의 각 사용자 설정이 담긴 /etc/passwd 파일을 참고해서 chroot 제한을 적용할 디렉토리를 결정하는 옵션이다. /etc/passwd 파일의 내용 중에서, 각 사용자의 홈 디렉토리 경로에서 원하는 위치에 .을 찍으면 그 위치보다 상위 디렉토리로는 못 빠져나가는 제한이 걸린다.

위의 두 가지 옵션을 동시에 사용하면 사용자별 홈 디렉토리를 조정할 수 있다. 서버의 모든 디렉토리에 접근 가능한 사용자의 홈 디렉토리는 local_root=/home/mydata 옵션을 추가해서 /home/mydata로 고정하고, 자신의 홈 디렉토리를 빠져나갈 수 없는 사용자들의 홈 디렉토리는 passwd_chroot_enable=YES 옵션을 추가해서 /home/mydata가 아닌 자기 계정의 기본 홈 디렉토리가 되도록 할 수 있다. 예를 들어 varins 사용자라면 /etc/passwd 파일에서 varins 항목인 varins:x:1000:1000:name,,,:/home/varins:/bin/bash 를 찾아서 varins:x:1000:1000:name,,,:/home/varins/./:/bin/bash 이렇게 홈 디렉토리 경로 끝에 /./을 추가하면 local_root=/home/mydata 옵션이 있더라도 varins의 홈 디렉토리는 계정의 기본 디렉토리인 /home/varins가 되고, 이 위치보다 상위 경로로 못 빠져나가게 된다.

FTPS SSL/TLS 인증서 설정

rsa_cert_file=/etc/letsencrypt/live/example.com/cert.pem
rsa_private_key_file=/etc/letsencrypt/live/example.com/privkey.pem
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
require_ssl_reuse=YES
ssl_ciphers=HIGH
ssl_sslv2=NO
ssl_sslv3=NO
ssl_tlsv1=YES

rsa_cert_file=rsa_private_key_file= 항목에 앞선 글 07. SSL/TLS 인증서를 참고해서 발급받은 인증서 파일의 경로를 입력해서 FTPS를 구성한다. ssl_enable=YES로 보안 연결을 활성화하고, 그 아래에 위와 같이 보안 설정에 필요한 내용을 추가로 기재한다.

도메인을 보유하고 있지 않은 경우에는 자기 서명 인증서(Self-Signed Certificate)를 사용할 수 있는데, sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/private/vsftpd.pem 명령으로 자기 서명 인증서를 발급할 수 있다. -days 365는 유효기간이 365일인 인증서를 발급하라는 옵션이고, 발급한 인증서는 /etc/ssl/private/vsftpd.pem 에 저장된다. rsa_cert_file=rsa_private_key_file= 항목에 모두 이 경로를 입력한다.

패시브 모드 설정

pasv_enable=YES
pasv_min_port=55100
pasv_max_port=55120
pasv_address=123.123.123.123
#pasv_addr_resolve=YES

FTP 서버가 기본적으로 패시브 모드로 작동하도록 설정하는 것이 클라이언트 측의 방화벽이나 인터넷 공유기 환경을 고려했을 때 편리한데, 먼저 pasv_enable=YES로 패시브 모드를 켠다. pasv_min_port=pasv_max_port=에 패시브 모드에 사용할 포트 번호 범위의 최소값과 최대값을 지정한다. 서버 컴퓨터가 인터넷 공유기의 하단에 있다면 여기에 지정한 포트 번호 범위는 인터넷 공유기의 포트 포워딩 기능을 통해서 모두 서버 컴퓨터를 향하도록 포워딩 되어야 한다. 또한 pasv_address=에 서버 컴퓨터의 공인 IP 주소를 입력해서 서버 컴퓨터가 인터넷 공유기의 하단에 있더라도 사설 IP 주소가 아닌 올바른 공인 IP 주소를 클라이언트에게 전달하도록 한다. 만일 공인 IP주소 대신에 도메인을 입력했다면 pasv_addr_resolve=YES 옵션을 추가해야 한다.

접속 허용 설정

FTP에 특정 사용자만 접속할 수 있도록 제어할 수 있는데, userlist_deny=를 YES로 지정하느냐 NO로 지정하느냐에 따라 반대의 결과가 설정된다. 아래에서 모두 살펴본다.

userlist_enable=YES
userlist_file=/etc/vsftpd.user_list
userlist_deny=NO

이렇게 userlist_deny=NO로 설정하면 /etc/vsftpd.user_list 파일에 기록된 사용자들만 접속을 허용하고 다른 사용자들은 접속을 거부한다. /etc/vsftpd.user_list 파일에 아무도 기록되어 있지 않으면 아무도 접속할 수 없다. /etc/vsftpd.user_list 파일을 편집할 때에는 sudo nano /etc/vsftpd.user_list 명령으로 nano 편집기로 열어서 접속을 허용할 사용자를 1줄에 1명씩 기록하고 저장한다.

userlist_enable=YES
userlist_file=/etc/vsftpd.user_list
userlist_deny=YES

이렇게 userlist_deny=YES로 설정하면 /etc/vsftpd.user_list 파일에 기록된 사용자들만 접속을 거부하고 다른 사용자들은 접속을 허용한다. /etc/vsftpd.user_list 파일에 아무도 기록되어 있지 않으면 모두가 접속할 수 있다. /etc/vsftpd.user_list 파일을 편집할 때에는 sudo nano /etc/vsftpd.user_list 명령으로 nano 편집기로 열어서 접속을 거부할 사용자를 1줄에 1명씩 기록하고 저장한다.

UTF8 인코딩 설정

utf8_filesystem=YES

한글 파일명을 원활하게 처리하기 위해 utf8_filesystem=YES 앞의 주석 #을 제거해서 UTF-8 인코딩을 사용하도록 한다.

모든 설정이 끝났으면 Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

vsftpd 재시작

sudo systemctl restart vsftpd

vsftpd를 재시작해서 설정 내용을 적용한다.

방화벽 설정

sudo iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
sudo iptables -A INPUT -p tcp -m tcp -m multiport --dports 55100:55120 -j ACCEPT

iptables 방화벽에 FTP가 사용하는 TCP 21번 포트를 허용하는 규칙을 생성하고, 앞서 pasv_min_port=pasv_max_port=에 설정한 포트 범위도 허용하는 규칙을 생성한다. (기본적인 방화벽 세팅은 03. 우분투 서버 18.04 LTS 기본 설정에서 완료했다.)

sudo netfilter-persistent save
sudo netfilter-persistent reload

iptables 방화벽의 설정 내용을 저장하고 리로드한다. (iptables-persistent는 03. 우분투 서버 18.04 LTS 기본 설정에서 설치했다.)

인터넷 공유기 포트 포워딩

FTP는 기본적으로 21번 포트를 사용한다. 가정에서 인터넷 공유기를 사용하고 있다면 공유기의 포트 포워딩 기능을 사용해서 TCP 21번 포트가 서버 컴퓨터로 향하도록 열어주어야 외부에서 FTP 접속이 가능해진다. 그런데 이 21번 포트는 널리 알려진 포트라서 열어 놓을 경우 외부의 누군가가 무작위로 IP 주소를 대입해서 접속을 시도하는 일이 발생하곤 한다. 이런 무작위 접속 시도를 피하려면 포트 포워딩을 설정할 때 외부 21번 포트는 열지 말고, 다른 임의의 숫자의 외부 포트를 열어서 이를 내부 21번 포트로 매핑하고, 이 내부 21번 포트가 서버 컴퓨터로 향하도록 포워딩 하는 것이 좋다. 물론 이렇게 설정하면 외부에서 FTP에 접속할 때 클라이언트 프로그램에 21번 포트 대신에 포워딩한 포트 번호를 입력해야 한다. 아울러 앞서 pasv_min_port=pasv_max_port=에 지정한 패시브 모드에 사용하는 포트 범위(TCP)도 모두 서버 컴퓨터를 향하도록 포워딩해야 한다.

FTP 클라이언트 프로그램에서 접속

클라이언트 프로그램에서 “FTPS” 또는 “TLS를 통한 명시적 FTP”를 사용하도록 설정하고, 호스트에는 서버의 공인 IP주소 또는 이와 연결된 도메인을 입력하고, 포트는 21번 또는 다른 포트를 포워딩 했다면 포워딩한 포트 번호를 입력해서 접속한다. 클라이언트 프로그램에 따라 한글 파일명이 제대로 안 나타난다면 추가로 인코딩을 UTF-8로 지정한다.

서버 컴퓨터가 인터넷 공유기의 하단에 있을 때, 만일 내부 네트워크에서 공인 IP 주소나 도메인을 입력하지 않고 사설(내부) IP 주소를 입력해서 패시브 모드로 접속한다면, 서버는 pasv_address= 설정으로 클라이언트에게 항상 서버의 공인 IP 주소를 전달하고 있는데 클라이언트는 사설 IP 주소로 접속을 시도하기 때문에 IP 주소가 서로 매치되지 않아서 클라이언트 프로그램에 따라 접속 오류가 발생할 수 있다. 이때에는 클라이언트 프로그램에서 패시브 모드 대신에 액티브 모드를 사용하는 것으로 지정하고 21번 포트로 접속하면 된다. 액티브 모드가 작동하려면 vsftpd.conf 파일에 connect_from_port_20= 항목이 YES로 되어 있어야 하는데 이것이 기본값이므로 한 번 확인해준다.

 

홈 서버 만들기 목차 
https://varins.com/category/server

01. 하드웨어 구성과 전기 요금
02. 우분투 서버 18.04 LTS 설치
03. 우분투 서버 18.04 LTS 기본 설정
04. 파일 복원: Btrfs 스냅샷
05. 네트워크 파일 공유: Samba (SMB)
06. Dynamic DNS: 구글 도메인 + ddclient
07. SSL/TLS 인증서: Let's Encrypt (Wildcard)
08. 웹 서버: Nginx, 서버 블록, https 보안연결
09. 웹사이트: php + MariaDB + WordPress
10. 서버 모니터링: Monitorix + Nginx Proxy
11. FTPS: vsftpd
12. VPN: IKEv2 (strongSwan)
13. Torrent: Transmission
14. 클라우드 스토리지: Nextcloud (Nginx, MariaDB)
15. 온라인 오피스: 온리오피스 (Docker, Nginx)
16. 트랜스코딩: Plex
17. VNC RDP 클라이언트: Guacamole (Docker, Nginx)
18. 가상 머신: QEMU-KVM + libvirt + virt-install
19. 시스템 업그레이드: i3 8300T, 970 EVO 전력 사용량
20. 서버 모니터링: netdata + Nginx Proxy

Comments (8)

  • DongHyeon

    July 7, 2018 at 1:28 am

    안녕하세요.
    ftp접속 문제에 대해서 한가지 묻고 싶은게 있습니다.
    파일질라로 접속을 해보면 아래 처럼 뜨는데 무슨 문제일까요?
    인터넷에서 파일질라 설정에서 시간 초과 설정을 늘려보라고 해서 해봤는데도
    안되네요… 일단 테스트 삼아 21포트를 사용중입니다.
    나머지 세팅은 블로그에 있는 그대로 했습니다.

    상태: 인증서 검증…
    상태: TLS 연결 수립.
    상태: 로그인
    상태: 디렉터리 목록 조회…
    명령: PWD
    응답: 257 “/home/donghyeon” is the current directory
    명령: TYPE I
    응답: 200 Switching to Binary mode.
    명령: PASV
    응답: 227 Entering Passive Mode (서버아이피입니다,64).
    명령: LIST
    오류: 데이터 연결을 수립하지 못함: ETIMEDOUT – 연결 시간 초과
    응답: 425 Failed to establish connection.
    오류: 디렉터리 목록 조회 실패

    1. Varins

      July 11, 2018 at 8:19 am

      안녕하세요,
      우선 인터넷 회선 공급 회사(ISP)에 따라서 20번, 21번 포트가 막혀있을 수 있습니다.
      그리고 21번 포트를 사용하신다는 것이 정확히 어떤 상황인지 모르겠습니다만, 패시브 모드를 사용하지 않는다는 뜻이라면 클라이언트에서 액티브 모드로 접속해야 할 것이고, 패시브 모드 포트에 21번을 지정했다면 그렇게 할 이유가 없으므로 다른 포트로 바꿔보세요. 물론 모두 인터넷 공유기에서 포트 포워딩 되어야 하고 iptables에서 열어주어야 합니다.
      또한 서버 IP 로그를 알 수 없는데 pasv_address 옵션에는 내부 IP가 아닌 공인 IP가 지정되어야 합니다.

  • young

    July 23, 2018 at 2:43 am

    상태: 연결 수립, 환영 메시지를 기다림…
    응답: 220 (vsFTPd 3.0.3)
    명령: AUTH TLS
    응답: 234 Proceed with negotiation.
    상태: TLS 초기화…
    상태: 인증서 검증…
    상태: TLS 연결 수립.
    명령: USER you42
    응답: 331 Please specify the password.
    명령: PASS **************
    오류: GnuTLS 오류 -15: An unexpected TLS packet was received.
    오류: 서버에 연결하지 못함

    비밀번호를 다르게 치면 530에러가 뜨고 익명접속을 허가하고 익명으로 접속하면 접속이 됩니다.
    tls없이 일반ftp로 접속하려고 해도 접속이 안되더군요.

    어떤게 문제일까요?

  • deaba

    July 23, 2018 at 3:03 am

    결국 접속에 성공하긴 했습니다.

    ssl_enable 이 옵션을 NO로 바꾸니까 에러가 사라지는대신에

    path/mydata 디렉토리를 인식할수 없다고 뜨더군요
    local_root를 주석처리하고

    그래서 상위로 못들어가게 막는부분인

    #chroot_local_user=YES
    #chroot_list_enable=YES
    #chroot_list_file=/etc/vsftpd.chroot_list
    #allow_writeable_chroot=YES

    이부분을 전부 주석처리 해버리니까 결국 접속은 됩니다만 제대로 고치고 싶습니다.
    조언을 구해봅니다.

    1. Varins

      July 25, 2018 at 9:01 am

      본문에 vsftpd.conf 파일 예시와 설명이 일치하지 않는 문제가 있었네요. /path/mydata 의 path 는 원하는 임의의 경로라는 의미였습니다. vsftpd.conf 파일 예시의 /path/mydata를 /home/mydata로 수정해서 예시와 설명을 일치시켰습니다. 감사합니다.

  • deaba

    July 23, 2018 at 3:36 am

    여러번 올리게 되어 죄송합니다.

    디렉토리 부분은 path 부분을 home으로 고치니 무리없이 돌아가고 chroot 부분도
    전부 적용하여 돌아가는것을 확인했습니다만

    ssl 부분만은 yes로 바꾸면 에러가 나오네요

    인증부분이 다른것도 안되면 이거다 하겠는데 워드프레스와 넥스트클라우드는
    무리없이 돌아가고 인증되 되고 있는거 보면 이상하네요

  • deaba

    July 23, 2018 at 4:06 am

    믿을수 없게도;;;;

    갑자기 모든것이 다 해결되었습니다. 인증까지 완벽하네요
    혼자 북치고 장구치고 하는 꼴이 되었네요

    좋은 글 게시해 주셔서 거듭 감사인사드립니다.

    1. Varins

      July 25, 2018 at 9:02 am

      잘 작동한다니 저도 기쁩니다.
      좋은 말씀 감사드립니다.

Leave a comment

Your email address will not be published. Required fields are marked *

Prev Post Next Post