'Getting "Connection refused" when transferring a file to FTP server with ftplib in Python

I am currently working on a python script to upload text files to an FTP server but am getting the following error ConnectionRefusedError: [Errno 61] Connection refused, and for the life of me I can't seem to figure out the issue. I believe it is either an issue with the FTP server (which I can connect to with the same credentials via FileZilla). Which led me to believe it could be a coding issue, but after much research, everything looks to be done correctly. So I decided, against my better judgement, to come here on my knees asking for some help. Even if that help is only determining that the issue is with the server and not my code. That will at least give me the next place to troubleshoot.

Thank you in advance for any insight you can provide!

Here is the code:

import ftplib

def ftp_upload(ftp_obj, path, ftype='TXT'):
    """
    A function for uploading files to an FTP server
    @param ftp_obj: The file transfer protocol object
    @param path: The path to the file to upload
    """
    if ftype == 'TXT':
        with open(path) as fobj:
            ftp.storlines('STOR ' + path, fobj)
    else:
        with open(path, 'rb') as fobj:
            ftp.storbinary('STOR ' + path, fobj, 1024)

if __name__ == '__main__':
    ftp = ftplib.FTP(host='domain or i.p. address')
    ftp.login(user = 'username', passwd = 'password')

    path = input('Please provide path to file: ')
    ftp_upload(ftp, path)

    pdf_path = '/path/to/something.pdf'
    ftp_upload(ftp, pdf_path, ftype='PDF')

    ftp.quit()

Here is the complete traceback:

Traceback (most recent call last):
File "ftp_text_file.py", line 21, in <module>
ftp_upload(ftp, path)
File "ftp_text_file.py", line 11, in ftp_upload
ftp.storlines('STOR ' + path, fobj)
File   "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ftplib.py", line 528, in storlines
with self.transfercmd(cmd) as conn:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ftplib.py", line 397, in transfercmd
return self.ntransfercmd(cmd, rest)[0]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ftplib.py", line 359, in ntransfercmd
source_address=self.source_address)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 722, in create_connection
raise err
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 713, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 61] Connection refused

Update: Provided the verbose logs from FileZilla showing I can connect and upload a file.

Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 0
Status:         Resolving address of my_domain
Status:         Connecting to FTP_server_ip_address:21...
Status:         Connection established, waiting for welcome message...
Trace:          CFtpControlSocket::OnReceive()
Response:   220 (vsFTPd 3.0.3)
Trace:          CFtpLogonOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    USER user 
Trace:          CFtpControlSocket::OnReceive()
Response:   331 Please specify the password.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    PASS **********
Trace:          CFtpControlSocket::OnReceive()
Response:   230 Login successful.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 6
Command:    SYST
Trace:          CFtpControlSocket::OnReceive()
Response:   215 UNIX Type: L8
Trace:          CFtpLogonOpData::ParseResponse() in state 6
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 7
Command:    FEAT
Trace:          CFtpControlSocket::OnReceive()
Response:   211-Features:
Trace:          CFtpControlSocket::OnReceive()
Response:    UTF8
Response:    EPRT
Response:    EPSV
Response:    MDTM
Response:    PASV
Response:    REST STREAM
Response:    SIZE
Response:    TVFS
Response:   211 End
Trace:          CFtpLogonOpData::ParseResponse() in state 7
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 9
Command:    OPTS UTF8 ON
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Always in UTF8 mode.
Trace:          CFtpLogonOpData::ParseResponse() in state 9
Status:         Logged in
Trace:          Measured latency of 35 ms
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         Retrieving directory listing...
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 1
Command:    PWD
Trace:          CFtpControlSocket::OnReceive()
Response:   257 "/home/punc" is the current directory
Trace:          CFtpChangeDirOpData::ParseResponse() in state 1
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 2
Trace:          CFtpRawTransferOpData::Send() in state 1
Command:    TYPE I
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Switching to Binary mode.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 2
Command:    PORT 192,168,1,131,195,121
Trace:          CFtpControlSocket::OnReceive()

Response:   200 PORT command successful. Consider using PASV.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 4
Command:    LIST
Trace:          CTransferSocket::OnAccept(0)
Trace:          CTransferSocket::OnConnect
Trace:          CTransferSocket::TransferEnd(1)
Trace:          CFtpControlSocket::TransferEnd()
Trace:          CFtpControlSocket::OnReceive()
Response:   150 Here comes the directory listing.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 6
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 7
Trace:          CFtpControlSocket::OnReceive()
Response:   226 Directory send OK.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 3
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         Directory listing of "/home/punc" successful
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 0
Status:         Resolving address of my_domain
Status:         Connecting to FTP_server_ip_address:21...
Status:         Connection established, waiting for welcome message...
Trace:          CFtpControlSocket::OnReceive()
Response:   220 (vsFTPd 3.0.3)
Trace:          CFtpLogonOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    USER user 
Trace:          CFtpControlSocket::OnReceive()
Response:   331 Please specify the password.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 5
Command:    PASS **********
Trace:          CFtpControlSocket::OnReceive()
Response:   230 Login successful.
Trace:          CFtpLogonOpData::ParseResponse() in state 5
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpLogonOpData::Send() in state 9
Command:    OPTS UTF8 ON
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Always in UTF8 mode.
Trace:          CFtpLogonOpData::ParseResponse() in state 9
Status:         Logged in
Trace:          Measured latency of 50 ms
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CFtpControlSocket::FileTransfer()
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpFileTransferOpData::Send() in state 0
Status:         Starting upload of /Users/user/tiny_dancer/Testing/Platinum Pest Control/API_text_results/Eps 256 Platinum Pest-Pest Control Tulsa.txt
Trace:          CFtpChangeDirOpData::Send() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 2
Command:    CWD /home/punc
Trace:          CFtpControlSocket::OnReceive()
Response:   250 Directory successfully changed.
Trace:          CFtpChangeDirOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpChangeDirOpData::Send() in state 3
Command:    PWD
Trace:          CFtpControlSocket::OnReceive()
Response:   257 "/home/punc" is the current directory
Trace:          CFtpChangeDirOpData::ParseResponse() in state 3
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpFileTransferOpData::SubcommandResult() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpFileTransferOpData::Send() in state 5
Trace:          CFtpRawTransferOpData::Send() in state 1
Command:    TYPE A
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Switching to ASCII mode.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 2
Command:    PORT 192,168,1,131,195,122
Trace:          CFtpControlSocket::OnReceive()
Response:   200 PORT command successful. Consider using PASV.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 4
Command:    STOR Eps 256 Platinum Pest-Pest Control Tulsa.txt
Trace:          CTransferSocket::OnAccept(0)
Trace:          CTransferSocket::OnConnect
Trace:          CTransferSocket::TransferEnd(1)
Trace:          CFtpControlSocket::TransferEnd()
Trace:          CFtpControlSocket::OnReceive()
Response:   150 Ok to send data.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 6
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 7
Trace:          CFtpControlSocket::OnReceive()
Response:   226 Transfer complete.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpFileTransferOpData::SubcommandResult() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         File transfer successful, transferred 8,341 bytes in 1 second
Status:         Retrieving directory listing of "/home/punc"...
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 0
Trace:          CFtpChangeDirOpData::Send() in state 0
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 2
Trace:          CFtpRawTransferOpData::Send() in state 1
Command:    TYPE I
Trace:          CFtpControlSocket::OnReceive()
Response:   200 Switching to Binary mode.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 1
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 2
Command:    PORT 192,168,1,131,195,123
Trace:          CFtpControlSocket::OnReceive()
Response:   200 PORT command successful. Consider using PASV.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 2
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 4
Command:    LIST
Trace:          CTransferSocket::OnAccept(0)
Trace:          CTransferSocket::OnConnect
Trace:          CTransferSocket::TransferEnd(1)
Trace:          CFtpControlSocket::OnReceive()
Response:   150 Here comes the directory listing.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 4
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpRawTransferOpData::Send() in state 5
Trace:          CFtpControlSocket::TransferEnd()
Trace:          CFtpControlSocket::OnReceive()
Response:   226 Directory send OK.
Trace:          CFtpRawTransferOpData::ParseResponse() in state 7
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Trace:          CControlSocket::ParseSubcommandResult(0)
Trace:          CFtpListOpData::SubcommandResult() in state 3
Trace:          CControlSocket::SendNextCommand()
Trace:          CFtpListOpData::ListSend() in state 4
Status:         Calculating timezone offset of server...
Command:    MDTM Eps 256 Platinum Pest-Pest Control Tulsa.txt
Trace:          CFtpControlSocket::OnReceive()
Response:   213 20180120104523
Trace:          CFtpListOpData::ParseResponse() in state 4
Status:         Timezone offset of server is 0 seconds.
Trace:          CFtpControlSocket::ResetOperation(0)
Trace:          CControlSocket::ResetOperation(0)
Status:         Directory listing of "/home/punc" successful


Solution 1:[1]

Your Python code is using passive mode.

With FileZille you can connect only in an active mode, but not in passive.

You generally should use the passive mode. As it does not work, you have to fix firewall/NAT configuration.
See my article https://winscp.net/eng/docs/ftp_modes


Another possibility is that the FTP server reports wrong IP address in the PASV response. We cannot tell that as you have obfuscated a primary IP address in the log. But indeed 192.168.1.131 is IP address reserved for private networks. So unless you are connecting to the server within a private network, the IP address is wrong. This is also covered on the previously linked article.

In vsftpd FTP server, you configure an external IP address using pasv_address directive.
https://security.appspot.com/vsftpd/vsftpd_conf.html

Less optimal solution is working this around on the local side:
Cannot list FTP directory using ftplib – but FTP client works


Or you can, of course, use the active mode in your Python script. But that’s rather a workaround than a solution.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1