Using this code:
from http import server
class Serv(server.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
server.HTTPServer(('host', 80), Serv).serve_forever()
I have tried using my public IP, which didn't work, my private IP, which only worked from the same network, and localhost, which is my PC only. How can I change the host so when someone connects to my IP, it connects to my website (from my code)? Do I need my router to redirect to my PC? I know host can be my private IP or localhost, are there any other hosts I can use?
Edit: I saw an answer in another question that used Flask, I'd like to not use any dependencies as of now.
If you want to make it work from anywhere,
your application should listen on IP address 0.0.0.0
which means (in short) any IPv4 address at all :
from http import server
class Serv(server.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello, world!')
server.HTTPServer(('', 80), Serv).serve_forever()
If you are in a recent linux/GNU based OS, you may check listening ports with :
ss -ltpn
Note that after that modification, you will depend of any proxy/firewall between you and your server to get your application response.
Related
I have a python script that acts as a webhook. A part of it is as follows:
import json
import os
import urllib
import socket
import _thread
from flask import Flask
from flask import request
from flask import make_response
app=Flask(__name__)
ip = ('192.168.1.75', 9050)
#app.route('/webhook',methods=['GET','POST'])
def webhook():
_thread.start_new_thread(sendDataToDevice,(ip))
req = request.get_json(silent=True,force=True)
print("Request:")
print(json.dumps(req,indent=4))
res=makeWebHookResult(req)
res=json.dumps(res,indent=4)
r=make_response(res)
r.headers['Content-Type']='application/json'
return r
if __name__ == '__main__':
app.run(port=8080,host='localhost')
The function of the script is to send some data to a device connected to the local network.
It works flawlessly when I open my web browser and type the following on the url bar:
http://localhost:8080/webhook
I want to host the script on a server, eg. Heroku. How can I access the local device in that case?
Note: I know I can run the script on my local machine and make it visible to the internet using ngrok, but I want to keep it accessible even when my computer is switched off. Also, want a fixed link, and the links given by ngrok change on every run.
I've faced a similar issue before with IoT. Unfortunately there is no simple way to make a device be visible online. Here's a simple solution I've used. It might not be the best, but it works.
DDNS + Port Forwarding + Static IP
If you have access to your local WiFi router, then you can setup something called as DDNS (Dynamic Domain Name System). Your router will then connect to a DDNS service provider like no-ip (www.noip.com) and it will be visible on the internet. You can give a custom URL like susmit-home.noip.com.
However susmit-home.noip.com will now point only to your WiFi router and not your WiFi network. So if you want to access the local device_ip and device_port such as "192.168.1.75", 9050. Then you can setup Port Forwarding on your router for that local IP-Port combination. Usually the setup looks like this:
Local IP: device_ip (e.g. 192.168.1.75)
Local Port: device_port (e.g. 9050)
Outbound Port: any_port (e.g. 9050)
Make sure that your device_ip is a static IP on your WiFi router so that it doesn't change.
Finally in your code you can just replace the line ip = ('192.168.1.75', 9050) with ip = ('susmit-home.noip.com', 9050).
Other solutions:
A slightly more complicated solution is setting up a VPN, such that your local network and your remote server (e.g. Heroku) will all be available to each other as if they were within the same local network.
If your device is a computer or a Raspberry Pi, then you can use SSH Remote Port Forwarding to have access to your local device from the remote server.
I had a working HTTP server using BaseHTTPServer in Python, so I attempted to add an SSL cert to allow for https using LetsEncrypt, and now it won't serve any files or respond. No exceptions or errors thrown, nor will it serve any content.
server_address = ('0.0.0.0', 80)
httpd = HTTPServer(server_address, MyHandler)
# I can comment out the following line and it'll work
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile=ssl_key, certfile=ssl_cert, server_side=True)
httpd.serve_forever()
#ssl_key = '/etc/letsencrypt/live/example.com/privkey.pem'
#ssl_cert = '/etc/letsencrypt/live/example.com/fullchain.pem'
Where MyHandler is the following:
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(204)
self.send_header("Content-Type", "text/html")
self.end_headers()
return
def do_POST(self):
self.send_response(204)
self.send_header("Content-Type", "text/html")
self.end_headers()
return
Attempting to access the site via web browser from https://example.com returns a standard no-response "Server not found".
I followed the following instructions to generate a certificate using LetsEncrypt: https://certbot.eff.org/#ubuntuxenial-other
sudo apt-get install letsencrypt
Followed by:
letsencrypt certonly --standalone -d example.com
Is there any way I can easily figure out what the problem is here? Using Python 3.5. Happy to provide additional info if needed.
server_address = ('0.0.0.0', 80)
Attempting to access the site via web browser from https://example.com returns a standard no-response "Server not found".
https://host without explicit port specification means that the server is accessed on the default port for the https protocol, which is 443. But, you have setup your server to use port 80 in server_address.
There are two ways to fix this: either explicitly specify a non-standard port for https in the URL, i.e. https://host:80 or change the port in server_address from 80 to 443. The last option is probably the better one.
I'm trying to run a flask server on my desktop PC that is publicly available on the internet. I've done the following:
Set up a static IP address: 192.168.1.11 (http://i.imgur.com/Z9GEBYV.png)
Forwarded port 33 on my router to my static ip address (http://i.imgur.com/KGNQ2Qk.png)
Setup flask to use my static ip and port: 33
I'm using the following code as a test webserver
from flask import Flask, request, redirect
app = Flask(__name__)
#app.route("/")
def hello_world():
return "Test 123 "
if __name__ == "__main__":
app.run(host="0.0.0.0", port="33")
When I open my browser to: http://192.168.1.11:33/ the page displays properly, I see "Test 123"
My problem comes when trying to connect to my webserver from my public ip address When I open my browser to http://xx.xxx.xxx.xx:30 (my ip address) all I see is "this site can't be reached, xx.xxx.xxx.xx refused to connect"
I've looked up all the stack overflow answers, I've done the following:
Turned off windows firewall
Changed host from "192.168.1.11" to "0.0.0.0"
Tried a different port
screenshot of code running and error shown: http://i.imgur.com/a05GvEs.png
My question is: What do I need to do to make my flask server visible from my public ip address?
Do you have DHCP activated on your router?
If yes do you see your host as 192.168.1.11 in there?
You have to use '0.0.0.0' on host, that tells Flask to listen on all addresses.
Try specifying the port with quotes as app.run(host="0.0.0.0", port="33")
change it to app.run(host= '0.0.0.0', port="33") to run on your machines IP address.
Documented on the Flask site under "Externally Visible Server" on the Quickstart page:
http://flask.pocoo.org/docs/0.10/quickstart/#a-minimal-application
Add port forwarding to port 33 in your router
Port forwarding explained here
http://www.howtogeek.com/66214/how-to-forward-ports-on-your-router/
You must give the public ip address/LAN ip address as an argument to app.run method.
When you don't provide host argument, it works fine with http://localhost:8888/ and http://127.0.0.1:888/, but not to access outside the system where you are running the REST services
Following is the example.
app.run(host="192.168.0.29",debug=True, port=8888)
You must try and use the same ip of the development server. Thus, for instance, if the dev server is running on a PC with the address 192.168.1.11
and port 33, other clients must point at the same address: 192.168.1.11:33.
As far as my small experience, it works with the debugger disabled, but I did not check if this is an essential prerequisite.
good luck
Every webservice should be run from different port address.Single service is running from a single port.
I have python app on Bluemix and would like to make it accessible over https only. By default I can connect both via http and https. Want to restrict access via https only. So what is the best way to disable http access, or redirect request to https only?
As ralphearle mentioned in his answer, Bluemix proxy server terminates the SSL, so you can look into the X-Forwarded-Proto header to find out if request comes from http or https.
See below a simple example based on the Python starter code from Bluemix. I added the RedirectHandler class to check for the X-Forwarded-Proto header value and redirects the request to https if it not https.
import os
try:
from SimpleHTTPServer import SimpleHTTPRequestHandler as Handler
from SocketServer import TCPServer as Server
except ImportError:
from http.server import SimpleHTTPRequestHandler as Handler
from http.server import HTTPServer as Server
class RedirectHandler(Handler):
def do_HEAD(self):
if ('X-Forwarded-Proto' in self.headers and
self.headers['X-Forwarded-Proto'] != 'https'):
self.send_response(301)
self.send_header("Location", 'https://' + self.headers['Host'] + self.path)
self.end_headers()
def do_GET(self):
self.do_HEAD()
Handler.do_GET(self)
# Read port selected by the cloud for our application
PORT = int(os.getenv('PORT', 8000))
# Change current directory to avoid exposure of control files
os.chdir('static')
httpd = Server(("", PORT), RedirectHandler)
try:
print("Start serving at port %i" % PORT)
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
The Bluemix proxy server terminates the SSL, so that all traffic looks like HTTP to your app. However, the proxy also adds a special HTTP header named $WSSC with a value that can be either http or https. Check this header and, if the value is set to http, then change it to https.
As Adam pointed out in his comment, the IBM forum has further discussion of this approach: https://developer.ibm.com/answers/questions/16016/how-do-i-enforce-ssl-for-my-bluemix-application.html
I need client IP address using python. I have tried below code but its not working in server:
from socket import gethostname, gethostbyname
ip = gethostbyname(gethostname())
print ip
On the server, I get '127.0.0.1' every time. Is there any way to find IP address of the client?
You're getting the IP address of your server, not of your server's clients.
You want to look at the request's REMOTE_ADDR, like this:
from bottle import Bottle, request
app = Bottle()
#app.route('/hello')
def hello():
client_ip = request.environ.get('REMOTE_ADDR')
return ['Your IP is: {}\n'.format(client_ip)]
app.run(host='0.0.0.0', port=8080)
EDIT #1: Some folks have observed that, for them, the value of REMOTE_ADDR is always the same IP address (usually 127.0.0.1). This is because they're behind a proxy (or load balancer). In this case, the client's original IP address is typically stored in header HTTP_X_FORWARDED_FOR. The following code will work in either case:
#app.route('/hello')
def hello():
client_ip = request.environ.get('HTTP_X_FORWARDED_FOR') or request.environ.get('REMOTE_ADDR')
return ['Your IP is: {}\n'.format(client_ip)]
EDIT #2: Thanks to #ArtOfWarfare's comment, I learned that REMOTE_ADDR is not required per PEP-333. Couple of observations:
The CGI spec does require REMOTE_ADDR:
The REMOTE_ADDR variable MUST be set to the network address of the client sending the request to the server.
However, PEP-333 does not explicitly require HTTP_REMOTE_ADDR, only going as far as this (emphasis mine):
A server or gateway SHOULD attempt to provide as many other CGI variables as are applicable.
All of the (admittedly few) web frameworks that I'm familiar with set HTTP_REMOTE_ADDR. AFAICT, it's a de facto "standard." But technically, YMMV.
Server might be behind a proxy. Use this for proxy and forward support:
request.environ.get('HTTP_X_FORWARDED_FOR') or request.environ.get('REMOTE_ADDR')
If you're trying to get the external IP, you will need to get it from an external source, i.e whatismyip.com or somewhere that offers an api. If that's what you're looking for, take a look at the Requests module http://docs.python-requests.org/