How to share files and web dev projects over your local network, using Python

Ports

Alice and Bob are sitting at home, hacking on their laptops, each connected to their home wifi network. Alice is getting started with Django, and runs:

$ django-admin.py startproject mysite
$ cd mysite
$ python manage.py runserver 8080
Validating models...

0 errors found
October 07, 2013 - 17:12:31
Django version 1.5.4, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8080/
Quit the server with CONTROL-C.

Alice opens her browser to look at her new Django website. Because of a previous web development project, localhost autocompletes to localhost:3000, which she accidentally tries to load. Her browser displays a connection refused error. Whoops, thinks Alice. My browser tried to get data from a port number that the Django built-in server application isn’t listening to, and nothing else is listening to that port, so it refused the connection.

Interfaces

Alice corrects the port number, and when she visits localhost:8080 in her browser, she sees the default Django ‘It works!’ page.

“Hey, Bob!” Alice cries to her housemate in the other room, “Check out my awesome Django site!” She quickly pastes the localhost:8080 link into a chat window for Bob.

Bob clicks the link. “Alice, I’m not seeing your site. I just get a connection refused error.”

“Oh, sorry, I gave you a link referring to localhost, which is a hostname for whatever computer requests it. It only works on my computer since I’m hosting the site. Let me send you a different link…” Alice sends Bob winterfell:8080, since winterfell is the name of her computer.

“That link didn’t work either,” replies Bob.

Alice is confused. She does some research, and comes across an article explaining that not only do computers have port numbers, they also have interfaces. She runs:

$ ifconfig

and gets back


eth1 Link encap:Ethernet HWaddr f0:de:f1:bf:61:75
      UP BROADCAST MULTICAST MTU:1500 Metric:1
      RX packets:0 errors:0 dropped:0 overruns:0 frame:0
      TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:1000
      RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
      Interrupt:20 Memory:f2500000-f2520000

lo Link encap:Local Loopback
      inet addr:127.0.0.1 Mask:255.0.0.0
      inet6 addr: ::1/128 Scope:Host
      UP LOOPBACK RUNNING MTU:65536 Metric:1
      RX packets:64904 errors:0 dropped:0 overruns:0 frame:0
      TX packets:64904 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:0
      RX bytes:13965657 (13.9 MB) TX bytes:13965657 (13.9 MB)

wlan1 Link encap:Ethernet HWaddr 60:d8:19:c7:0f:91
      inet addr:172.27.0.17 Bcast:172.27.0.255 Mask:255.255.255.0
      inet6 addr: fe80::62d8:19ff:fec7:f91/64 Scope:Link
      UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
      RX packets:3800909 errors:0 dropped:0 overruns:0 frame:0
      TX packets:2102641 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:1000
      RX bytes:217109512 (217.1 MB) TX bytes:346745106 (346.7 MB)

Oh, thinks Alice, my computer has three interfaces listed here. eth1 must be my laptop’s ethernet jack, which isn’t plugged in right now. lo is probably localhost, which is only accessible inside my computer. And that means wlan1 is my wifi card, which I’m connecting to the Internet with right now.

Alice also reads that by default, the Django built-in webserver only serves on the ‘localhost’ (also known as 127.0.0.1) interface. From this Alice surmises, Bob wasn’t able to access my site because Django’s web server is only listening to port 8080 on the localhost interface–my wifi card’s interface doesn’t have anything listening to port 8080.

Alice learns that she can change this default behavior by changing the IP address that her site is served on to

$ python manage.py runserver 0.0.0.0:8080

0.0.0.0 means that the server will listen to the given port (in this case 8080) on all interfaces, not just localhost.

Alice does this, then asks Bob to try the link again. He does.

“Cool, Alice! …but isn’t this built into Django?”

“Shush, it’s in alpha.”


Sharing the contents of any directory

The next day, Alice’s friend Carol visits and she and Alice want to watch a movie together. The movie is on Carol’s laptop, which has a small screen and mostly-broken speakers. Alice, on the other hand, has an excellent computer connected to a huge HD monitor and great sound system.

“Alice, I’d like to watch the movie on your computer, but I don’t have a flash drive to easily move the movie file over,” says Carol. “What should we do?”

Alice, who has been reading a bit more about Python and servers, says, “I know! Do you have Python installed on your laptop?”

Carol does, so Alice opens a terminal, cds into the directory where the movie file is, and runs

$ python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...

Alice has previously learned that unlike the built-in Django web server, SimpleHTTPServer by default listens to all interfaces at whatever port you specify (or port 8000 if unspecified), so she does not have to provide 0.0.0.0 for the IP address.

Alice then opens the video player program on her computer, finds the option to stream from a URL, and enters

fuji:8080/awesome_movie.mp4

into the URL field, where fuji is the name of Carol’s laptop and awesome_movie.mp4 is the file name for the video.

Alice hits play, and after only a bit of buffering (for Alice and Bob’s wifi router is quite fast and high quality) she and Carol happily settle down and watch the movie.

  • http://prologic.shortcircuit.net.au/ James Mills

    I don’t get this point of this post? :)

  • aldeka

    See title!

  • Maximilien Riehl

    I like django’s current mechanism better. In the second case, if we suppose the file is in Alice’s home, she’s also serving her .pypirc and other sensitive files. Nice!

    The decision to listen on all interfaces should be an informed one.

    Definitely an issue of security vs. comfort, but if you don’t know what interfaces are it seems to be a bad idea to listen to all of them by default!

  • http://www.blogshop.co.uk/ Blogshop

    great

  • http://www.blogshop.co.uk/ Blogshop

    nice

  • Thijs Triemstra

    What if the static part of the django site is hosted by apache on let’s say http://site.static. This will result in 404’s on the external machine in the network. Is that configured on the webrouter?

  • aldeka

    Perhaps this wasn’t obvious — this post was meant for relatively new web developers and others who want quick-and-dirty sharing. If you know enough to have set up Apache locally for your Django static files, you probably know enough to serve Django over the local network yourself!

  • aldeka

    I’m not sure how you read this as an argument that the default Django web server behavior ought to be changed–I don’t think it should be. I am explaining how to share your work within your local network for a limited period of time.

  • Maximilien Riehl

    Oh, okay. I thought it was thinly veiled irony, given that the django approach requires several insights from Alice (in the real world she’d probably give up) whereas the builtin python webserver “just works™”.