Is it possible to have a one line command in python to do a simple ftp server? I'd like to be able to do this as quick and temporary way to transfer files to a linux box without having to install a ftp server. Preferably a way using built in python libraries so there's nothing extra to install.
Obligatory Twisted example:
twistd -n ftp
And probably useful:
twistd ftp --help
Usage: twistd [options] ftp [options].
WARNING: This FTP server is probably INSECURE do not use it.
Options:
-p, --port= set the port number [default: 2121]
-r, --root= define the root of the ftp-site. [default:
/usr/local/ftp]
--userAnonymous= Name of the anonymous user. [default: anonymous]
--password-file= username:password-style credentials database
--version
--help Display this help and exit.
Check out pyftpdlib from Giampaolo Rodola. It is one of the very best ftp servers out there for python. It's used in google's chromium (their browser) and bazaar (a version control system). It is the most complete implementation on Python for RFC-959 (aka: FTP server implementation spec).
To install:
pip3 install pyftpdlib
From the commandline:
python3 -m pyftpdlib
Alternatively 'my_server.py':
#!/usr/bin/env python3
from pyftpdlib import servers
from pyftpdlib.handlers import FTPHandler
address = ("0.0.0.0", 21) # listen on every IP on my machine on port 21
server = servers.FTPServer(address, FTPHandler)
server.serve_forever()
There's more examples on the website if you want something more complicated.
To get a list of command line options:
python3 -m pyftpdlib --help
Note, if you want to override or use a standard ftp port, you'll need admin privileges (e.g. sudo).
Why don't you instead use a one-line HTTP server?
python -m SimpleHTTPServer 8000
will serve the contents of the current working directory over HTTP on port 8000.
If you use Python 3, you should instead write
python3 -m http.server 8000
See the SimpleHTTPServer module docs for 2.x and the http.server docs for 3.x.
By the way, in both cases the port parameter is optional.
The answers above were all assuming your Python distribution would have some third-party libraries in order to achieve the "one liner python ftpd" goal, but that is not the case of what #zio was asking. Also, SimpleHTTPServer involves web broswer for downloading files, it's not quick enough.
Python can't do ftpd by itself, but you can use netcat, nc:
nc is basically a built-in tool from any UNIX-like systems (even embedded systems), so it's perfect for "quick and temporary way to transfer files".
Step 1, on the receiver side, run:
nc -l 12345 | tar -xf -
this will listen on port 12345, waiting for data.
Step 2, on the sender side:
tar -cf - ALL_FILES_YOU_WANT_TO_SEND ... | nc $RECEIVER_IP 12345
You can also put pv in the middle to monitor the progress of transferring:
tar -cf - ALL_FILES_YOU_WANT_TO_SEND ...| pv | nc $RECEIVER_IP 12345
After the transferring is finished, both sides of nc will quit automatically, and job done.
For pyftpdlib users. I found this on the pyftpdlib website. This creates anonymous ftp with write access to your filesystem so please use with due care. More features are available under the hood for better security so just go look:
sudo pip3 install pyftpdlib
python3 -m pyftpdlib -w
## updated for python3 Feb14:2020
Might be helpful for those that tried using the deprecated method above.
sudo python -m pyftpdlib.ftpserver
apt-get install python3-pip
pip3 install pyftpdlib
python3 -m pyftpdlib -p 21 -w --user=username --password=password
-w = write permission
-p = desired port
--user = give your username
--password = give your password
Install:
pip install twisted
Then the code:
from twisted.protocols.ftp import FTPFactory, FTPRealm
from twisted.cred.portal import Portal
from twisted.cred.checkers import AllowAnonymousAccess, FilePasswordDB
from twisted.internet import reactor
reactor.listenTCP(21, FTPFactory(Portal(FTPRealm('./'), [AllowAnonymousAccess()])))
reactor.run()
Get deeper:
http://twistedmatrix.com/documents/current/core/examples/
The simpler solution will be to user pyftpd library. This library allows you to spin Python FTP server in one line. It doesn’t come installed by default though, but we can install it using simple apt command
apt-get install python-pyftpdlib
now from the directory you want to serve just run the pythod module
python -m pyftpdlib -p 21
I dont know about a one-line FTP server, but if you do
python -m SimpleHTTPServer
It'll run an HTTP server on 0.0.0.0:8000, serving files out of the current directory. If you're looking for a way to quickly get files off a linux box with a web browser, you cant beat it.
Related
I want to run an HTML file in localhost:8080, I'm using the command:
python3 -m http.server
Problem is when I try to open localhost:8080 it downloads the HTML file instead of displaying it.
Problem is when I try to open localhost:8080 it downloads the HTML file instead of displaying it.
You want to open http://localhost:8000 instead.
When you use the command you mentioned, python3 -m http.server, it defaults to port 8000, as explained in its startup output:
$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
We don't know what different server you have running on port 8080, but apparently it doesn't put Content-type: text/html in its output headers.
viewing webserver http headers
It's easy to view those headers, e.g. with wget use the -S switch.
You need to add an option that'll put your website on port 8080 because the http.server command defaults to port 8000.
You can do this using:
python3 -m http.server 8080
Then when you go to 0.0.0.0:8080 it should show you your webpage instead of a download prompt.
Also, you might have another instance of http.server running on port 8080.
You can find the PID of this task using:
ps -A | grep "python3"
Which should show something that looks like this:
Then you could kill it using:
kill <PID-FOR-PYTHON3-INSTANCE>
Or in my case the task that's running on port 8080 is:
kill 6856
Or, if you don't mind, just kill all Python3 tasks using:
killall python3
Which in my case would kill both Python3 tasks.
WARNING: be very, VERY careful before running the killall command, because this command will NOT save your work.
UPDATE: that blurry section in the picture is my username, I wasn't sure if it would be against the rules to include it.
Good luck.
When trying to run python bottle on port 80 I get the following:
socket.error: [Errno 10013] An attempt was made to access a socket in a way forb
idden by its access permissions
My goal is to run the web server on port 80 so the url's will be nice and tidy without any need to specify the port
for example:
http://localhost/doSomething
instead of
http://localhost:8080/doSomething
Any ideas?
Thanks
Exactly as the error says. You need to have permissions to run something on the 80th port, normal user cannot do it. You can execute the bottle webapp as root (or maybe www-data) and it should be fine as long as the port is free.
But taking security (and stability) into consideration you should look at different ways of deployment, for example nginx together with gunicorn.
Gunicorn Docs
Nginx Docs
Check your system's firewall setting.
Check whether another application already use port 80 using following commands:
On unix: netstat -an | grep :80
On Windows: netstat -an | findstr :80
According to Windows Sockets Error Codes:
WSAEACCES 10013
Permission denied.
An attempt was made to access a socket in a way forbidden by its
access permissions. An example is using a broadcast address for sendto
without broadcast permission being set using setsockopt(SO_BROADCAST).
Another possible reason for the WSAEACCES error is that when the bind
function is called (on Windows NT 4.0 with SP4 and later), another
application, service, or kernel mode driver is bound to the same
address with exclusive access. Such exclusive access is a new feature
of Windows NT 4.0 with SP4 and later, and is implemented by using the
SO_EXCLUSIVEADDRUSE option.
Sometimes dont need to want install nginx, python with gunicorn is a viable alternative with supervisor but you need to make lot of tricks for working
i assume you know install supervisor, and later install again requirements
pip3 install virtualenv
mkdir /home/user/.envpython
virtualenv /home/user/.envpython/bin/activate
source /home/user/.envpython/bin/activate
cd /home/user/python-path/
pip3 install -r requirements
create a supervisor file like that
nano /etc/supervisord.d/python-file.conf
and edit with this example, edit the program that you need, remember the python3 run in other ports > 1024
;example with path python supervisor in background
[program:python]
environment=HOME="/home/user",USER="user"
user=user
directory = /home/user/python-path
command = python3 /home/user/python-path/main.py
priority = 900
autostart = true
autorestart = true
stopsignal = TERM
;redirect_stderr = true
stdout_logfile = /home/user/.main-python-stdout.log
stderr_logfile = /home/user/.main-python-stderr.log
;example with path python gunicorn supervisor and port 80
[program:gunicorn]
;environment=HOME="/home/user",USER="user"
;user=user
directory = /home/user/python-path
command = bash /home/user/.scripts/supervisor-initiate.sh
priority = 900
autostart = true
autorestart = true
stopsignal = TERM
;redirect_stderr = true
stdout_logfile = /home/user/.main-python-stdout.log
stderr_logfile = /home/user/.main-python-stderr.log
and create the file
nano /home/user/.scripts/supervisor-initiate.sh
with the following content
source /home/user/.envpython/bin/activate
cd /home/user/python-path
gunicorn -w 1 -t 120 -b 0.0.0.0:80 main:app
i assume you file in python is called main and you initiate the app with flask or django that called "app"
only restart supervisord process
systemctl restart supervisord
and you have the app with gunicorn in the port 80, i post because i find for a very long time for this solution
Waiting works for anyone
Having a server that has to handle lots of TCP-requests from gprs-modules I think it is handy to set up something to protect this server from multiple requests from certain ip's.
Now I want to make something(within python) that will check how much times a certain ip tries to connect and if this exceeds a given amount of tries this ip will be blocked for a given amount of time (or forever).
I am wondering if there are libraries present to do this, or how I should tackle this problem in my code.
Don't tackle this from your code - this is what a firewall is designed to do.
Using iptables its trivial:
iptables -I INPUT -p tcp --dport $PORT -i eth0 -m state --state NEW -m recent --set
iptables -I INPUT -p tcp --dport $PORT -i eth0 -m state --state NEW -m recent --update --seconds 600 --hitcount 2 -j DROP
The above means "drop anything that makes more than 2 connection attempts in 10 minutes at port $PORT"
If you decide you do want to handle this in code, you don't need a separate library (although using one will probably be more efficient), you can add something like the following to your connection handler:
from collections import defaultdict, deque
from datetime import datetime
floodlog = defaultdict(deque)
def checkForFlood(clientIP):
"""check if how many times clientIP has connected within TIMELIMIT, and block if more than MAX_CONNECTEIONS_PER_TIMELIMIT"""
now = datetime.now()
clientFloodLog = floodlog[clientIP]
clientFloodLog.append(now)
if len(clientFloodLog) > MAX_CONNECTIONS_PER_TIMELIMIT:
earliestLoggedConenction = clientFloodLog.popleft()
if now - earliestLoggedConnection < TIMELIMIT:
blockIP(clientIP)
As Burhan Khalid said. You don't want to try this in your code. It's not very performant and that's what firewalls are made for.
iptables -I INPUT -p tcp --dport $PORT -i eth0 -m state --state NEW -m recent --set
iptables -I INPUT -p tcp --dport $PORT -i eth0 -m state --state NEW -m recent --update --seconds 600 --hitcount 2 -j DROP
This example is very usefull but not very handy. The problem is that you're also limiting good/trusted connections.
You need to be more flexible. On a linux-based OS you can use fail2ban. It's a very handy tool to prevent your services of bruteforce attacks by using dynamic iptables rules. On Debian/Ubuntu you can install it by using apt-get. If you're on CentOS you need to use a third party repository.
Log every connection into a logfile:
[Jun 3 03:52:23] server [pid]: Connect from 1.2.3.4
[Jun 3 03:52:23] server [pid]: Failed password for $USER from 1.2.3.4 port $DST
[Jun 3 03:52:23] server [pid]: Connect from 2.3.4.5
[Jun 3 03:52:23] server [pid]: Successful login from 2.3.4.5
Now monitor this file with fail2ban and define a regex to difference between successful and failed logins. Tell fail2ban how long it should block the IP for you and if you would like to get an email notification.
The documentation is very good so have a look onto here how you have to configure fail2ban to monitor your logile: fail2ban docu
You don't have to watch only for failed logins. You can also try to watch out for portscans. And the biggest win: don't only secure your application. Safe also your SSH, HTTP, etc logins for beeing bruteforced! ;)
For a pure Python solution, I think you could reuse something I developed for the same problem, but for the client point of view: avoiding to issue more than 'x tries per sec' to a service provider.
The code is available on GitHub: you can probably reuse most of it, but you'll need to replace the time.sleep call for your 'blacklisting' mechanism.
What is the Python 3 equivalent of python -m SimpleHTTPServer?
From the docs:
The SimpleHTTPServer module has been merged into http.server in Python 3.0. The 2to3 tool will automatically adapt imports when converting your sources to 3.0.
So, your command is python -m http.server, or depending on your installation, it can be:
python3 -m http.server
The equivalent is:
python3 -m http.server
Using 2to3 utility.
$ cat try.py
import SimpleHTTPServer
$ 2to3 try.py
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
RefactoringTool: Refactored try.py
--- try.py (original)
+++ try.py (refactored)
## -1 +1 ##
-import SimpleHTTPServer
+import http.server
RefactoringTool: Files that need to be modified:
RefactoringTool: try.py
Like many *nix utils, 2to3 accepts stdin if the argument passed is -. Therefore, you can test without creating any files like so:
$ 2to3 - <<< "import SimpleHTTPServer"
In addition to Petr's answer, if you want to bind to a specific interface instead of all the interfaces you can use -b or --bind flag.
python -m http.server 8000 --bind 127.0.0.1
The above snippet should do the trick. 8000 is the port number. 80 is used as the standard port for HTTP communications.
As everyone has mentioned http.server module is equivalent to python -m SimpleHTTPServer.
But as a warning from https://docs.python.org/3/library/http.server.html#module-http.server
Warning: http.server is not recommended for production. It only implements basic security checks.
Usage
http.server can also be invoked directly using the -m switch of the interpreter.
python -m http.server
The above command will run a server by default on port number 8000. You can also give the port number explicitly while running the server
python -m http.server 9000
The above command will run an HTTP server on port 9000 instead of 8000.
By default, server binds itself to all interfaces. The option
-b/--bind specifies a specific address to which it should bind. Both IPv4 and IPv6 addresses are supported. For example, the following
command causes the server to bind to localhost only:
python -m http.server 8000 --bind 127.0.0.1
or
python -m http.server 8000 -b 127.0.0.1
Python 3.8 version also supports IPv6 in the bind argument.
Directory Binding
By default, server uses the current directory. The option -d/--directory specifies a directory to which it should serve the files. For example, the following command uses a specific directory:
python -m http.server --directory /tmp/
Directory binding is introduced in python 3.7
In one of my projects I run tests against Python 2 and 3. For that I wrote a small script which starts a local server independently:
$ python -m $(python -c 'import sys; print("http.server" if sys.version_info[:2] > (2,7) else "SimpleHTTPServer")')
Serving HTTP on 0.0.0.0 port 8000 ...
As an alias:
$ alias serve="python -m $(python -c 'import sys; print("http.server" if sys.version_info[:2] > (2,7) else "SimpleHTTPServer")')"
$ serve
Serving HTTP on 0.0.0.0 port 8000 ...
Please note that I control my Python version via conda environments, because of that I can use python instead of python3 for using Python 3.
Just wanted to add what worked for me:
python3 -m http.server 8000 (you can use any port number here except the ones which are currently in use)
Is it possible to have a one line command in python to do a simple ftp server? I'd like to be able to do this as quick and temporary way to transfer files to a linux box without having to install a ftp server. Preferably a way using built in python libraries so there's nothing extra to install.
Obligatory Twisted example:
twistd -n ftp
And probably useful:
twistd ftp --help
Usage: twistd [options] ftp [options].
WARNING: This FTP server is probably INSECURE do not use it.
Options:
-p, --port= set the port number [default: 2121]
-r, --root= define the root of the ftp-site. [default:
/usr/local/ftp]
--userAnonymous= Name of the anonymous user. [default: anonymous]
--password-file= username:password-style credentials database
--version
--help Display this help and exit.
Check out pyftpdlib from Giampaolo Rodola. It is one of the very best ftp servers out there for python. It's used in google's chromium (their browser) and bazaar (a version control system). It is the most complete implementation on Python for RFC-959 (aka: FTP server implementation spec).
To install:
pip3 install pyftpdlib
From the commandline:
python3 -m pyftpdlib
Alternatively 'my_server.py':
#!/usr/bin/env python3
from pyftpdlib import servers
from pyftpdlib.handlers import FTPHandler
address = ("0.0.0.0", 21) # listen on every IP on my machine on port 21
server = servers.FTPServer(address, FTPHandler)
server.serve_forever()
There's more examples on the website if you want something more complicated.
To get a list of command line options:
python3 -m pyftpdlib --help
Note, if you want to override or use a standard ftp port, you'll need admin privileges (e.g. sudo).
Why don't you instead use a one-line HTTP server?
python -m SimpleHTTPServer 8000
will serve the contents of the current working directory over HTTP on port 8000.
If you use Python 3, you should instead write
python3 -m http.server 8000
See the SimpleHTTPServer module docs for 2.x and the http.server docs for 3.x.
By the way, in both cases the port parameter is optional.
The answers above were all assuming your Python distribution would have some third-party libraries in order to achieve the "one liner python ftpd" goal, but that is not the case of what #zio was asking. Also, SimpleHTTPServer involves web broswer for downloading files, it's not quick enough.
Python can't do ftpd by itself, but you can use netcat, nc:
nc is basically a built-in tool from any UNIX-like systems (even embedded systems), so it's perfect for "quick and temporary way to transfer files".
Step 1, on the receiver side, run:
nc -l 12345 | tar -xf -
this will listen on port 12345, waiting for data.
Step 2, on the sender side:
tar -cf - ALL_FILES_YOU_WANT_TO_SEND ... | nc $RECEIVER_IP 12345
You can also put pv in the middle to monitor the progress of transferring:
tar -cf - ALL_FILES_YOU_WANT_TO_SEND ...| pv | nc $RECEIVER_IP 12345
After the transferring is finished, both sides of nc will quit automatically, and job done.
For pyftpdlib users. I found this on the pyftpdlib website. This creates anonymous ftp with write access to your filesystem so please use with due care. More features are available under the hood for better security so just go look:
sudo pip3 install pyftpdlib
python3 -m pyftpdlib -w
## updated for python3 Feb14:2020
Might be helpful for those that tried using the deprecated method above.
sudo python -m pyftpdlib.ftpserver
apt-get install python3-pip
pip3 install pyftpdlib
python3 -m pyftpdlib -p 21 -w --user=username --password=password
-w = write permission
-p = desired port
--user = give your username
--password = give your password
Install:
pip install twisted
Then the code:
from twisted.protocols.ftp import FTPFactory, FTPRealm
from twisted.cred.portal import Portal
from twisted.cred.checkers import AllowAnonymousAccess, FilePasswordDB
from twisted.internet import reactor
reactor.listenTCP(21, FTPFactory(Portal(FTPRealm('./'), [AllowAnonymousAccess()])))
reactor.run()
Get deeper:
http://twistedmatrix.com/documents/current/core/examples/
The simpler solution will be to user pyftpd library. This library allows you to spin Python FTP server in one line. It doesn’t come installed by default though, but we can install it using simple apt command
apt-get install python-pyftpdlib
now from the directory you want to serve just run the pythod module
python -m pyftpdlib -p 21
I dont know about a one-line FTP server, but if you do
python -m SimpleHTTPServer
It'll run an HTTP server on 0.0.0.0:8000, serving files out of the current directory. If you're looking for a way to quickly get files off a linux box with a web browser, you cant beat it.