Twisted web server behind apache - no resource found - python

I am running twisted.web.server on localhost at port 8001 and apache2 with mod_proxy.
Apache is set to proxy according to the following config
http://localhost/jarvis ----> http://localhost:8001/
The httpd config for this rule is
ProxyPass /jarvis http://localhost:8001/
ProxyPassReverse /jarvis http://localhost:8001/
The twisted app's code fragment for server config is as follows:
if __name__ == '__main__':
root = Resource()
root.putChild("clientauth", boshProtocol())
logging.basicConfig()
factory = Site(root)
reactor.listenTCP(8001, factory)
reactor.run()
When I go to
http://localhost:8001/clientauth
it runs as expected.
However when I use
http://localhost/jarvis/clientauth
It give the error - "No such child resource."
As i understand - the request is correctly proxied to the twisted web server. But why is the child resource not identified?

You are missing a RewriteRule. I haven't tested it, but the fix for your problem is more or less like this:
RewriteRule ^/jarvis/(.*) /$1
Be sure to have mod_rewrite enabled.
Here is a link I usually use for reference: http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
Good luck!

Related

How can I have my flask-app run on my sites subdomain?

For example, I want to run flask-app on http://api.domain.com . However, I have no idea how to do this and the flask documentation serves no help. I am using a shared namecheap web server via SSH to run python. I have ports 8080, 8181 and 8282 open.
Server-sided code:
from flask import Flask
from flask import Blueprint
app = Flask(__name__)
app.config['SERVER_NAME'] = 'domain.com'
#app.route('/status')
def status():
return 'Status : Online'
bp = Blueprint('subdomain', __name__, subdomain="api")
app.register_blueprint(bp)
if __name__ == '__main__':
app.run(host=app.config["SERVER_NAME"],port=8181,debug=True)
When I visit http://www.api.domain.com/status , it returns a 404 error.
Nothing displays on the SSH console.
Any help if very much appreciated.
First things first:
http (i.e. a web server without a SSL certificate) is insecure. You should set up a certificate and always use port 443 to the outside.
Then, on namecheap, you need to define a CNAME entry to point to the subdomain.
In Namecheap, click domain -> Manage, then Advanced DNS
Create a new record, select CNAME as the Type, and enter the subdomain name (just the top level) as the HOST, then the IP where you server is as the value (TTL (time to live) is the time it takes to change when you want to change it next time, 1, 10min is useful to debug stuff, but DNS may not honor that anyways...)
Wait a few minutes, and you should be able to reach your server at the subdomain name.
Now, if you use the same IP as a webserver for example, but a different port, that is basically not gonna do what you want. The DNS will forward subdomain traffic to your (same) server IP, so if your webserver is on port 443, you will also reach it with https://api.domain.com. If your API uses port 8080 or 8081, you will need to always specify the port to actually reach the API server at the subdomain (i.e api.domain.com:8080 ).
The DNS merely forwards the subdomain name to the IP you tell it to.
I solved this using the tornado in Python. I already answered this question and it's working fine
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(int(5000),address="ip_address_of_your_server_machine")
IOLoop.instance().start()
Now you can access this page like www.example.com:5000
Actually Flask is not meant to run a server by itself, it's only for debugging, if you want to run an web app you should run behind a Apache or Nginx with some wsgi, here is an simple example on Ubuntu 18.04 LTS:
https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uswgi-and-nginx-on-ubuntu-18-04

Allow urls containing "www." on openshift hosted website

I have a (very) simple flask app hosted on open-shift.
It has one route:
#app.route('/')
def display_content():
return render_template("content.html.jnj2")
and a simple wsgi file (as described in the open-shift flask setup tutorial):
from wsgiref.simple_server import make_server
httpd = make_server('localhost', 8051, application)
httpd.serve_forever()
This works fine when I navigate to "myappname-mydomain.rhcloud.com", but gives an "ERR_NAME_NOT_RESOLVED" when I navigate to "www.myappname-mydomain.rhcloud.com".
I've done some googling etc, can't see anyone else with a similar problem.. I'm not aware of having changed any open-shift settings or anything.
Your app-domain.rhcloud.com address that is provided by OpenShift does NOT include a cname for www.app-domain.rhcloud.com, that's why it's not working. You can use your app-domain.rhcloud.com, or you can map your own alias like example.com or www.example.com using this guide: https://developers.openshift.com/en/managing-domains-ssl.html#using-a-custom-domain

Running Tornado in apache

My end goal is to implement a WebSocket server using python.
I'm accomplishing this by importing tornado in my python scripts. I've also installed mod_wsgi in apache, and their script outputs Hello World!, so WSGI seems to be working fine. Tornado is also working fine as far as I can tell.
The issue comes when I use tornado's wsgi "Hello, world" script:
import tornado.web
import tornado.wsgi
import wsgiref.simple_server
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
if __name__ == "__main__":
application = tornado.wsgi.WSGIApplication([
(r"/", MainHandler),
])
server = wsgiref.simple_server.make_server('', 8888, application)
server.serve_forever()
First, I get a 500 error and the log tells me WSGI can't find 'application'.
So I remove if __name__ == "__main__", and the page loads infinitely.
I assume this is because of server.serve_forever() so I removed it in an attempt to see Hello, world
But now I just get 404: Not Found. It's not my apache 404 page, and I know that the server can find my main .wsgi file...
You can't use websockets with Tornado's WSGIApplication. To use Tornado's websocket support you have to use Tornado's HTTPServer, not apache.
The WSGIApplication handlers are relative to the webserver root. If your application url is /myapp, your 'application' must look like this:
application = tornado.wsgi.WSGIApplication([
(r"/myapp", MainHandler),
(r"/myapp/login/etc", LoginEtcHandler),
])
Oh, and it seems like the documentation is shit (as usual) and __name__ will look something like this when running under apache: _mod_wsgi_8a447ce1677c71c08069303864e1283e.
So! a correct "Hello World" python script will look like this:
/var/www/wsgi-scripts/myapp.wsgi:
import tornado.web
import tornado.wsgi
import wsgiref.simple_server
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('Hello World')
application = tornado.wsgi.WSGIApplication([
(r"/myapp", MainHandler),
])
And in the apache config (not .htaccess):
WSGIScriptAlias /myapp /var/www/wsgi-scripts/myapp.wsgi
To use tornado in apache,add a mod-wsgi plugin to apache.
apt-get install libapache2-mod-wsgi
Write a tornado wsgi server with
.wsgi
NOTE:Dont use__name__
Configure the apache.conf to run your server.To configure use this mod-wsgi guide
If you still want to combine them both, you can use Apache as a proxy that will just be the 1st point in front of the user - but actually reroute the traffic to your local Tornado server ( In / Out )
In my case for example, my Apache listen in port 443 ( some default config )
Then I run my tornado in port 8080, and given a path - will redirect
#File: conf.d/myapp.conf
<VirtualHost *:80>
ErrorLog "logs/myapp_error_log"
ProxyPreserveHost On
ProxyRequests off
ProxyPreserveHost On
<Proxy *>
Require all granted
</Proxy>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^TRACE
RewriteRule .* - [F]
ProxyPassMatch "/myapp/(.*)" "http://localhost:8080/myapp/$1"
ProxyPassReverse "/myapp/" "http://localhost:8080/myapp/"
</VirtualHost>
If you're using RedHat "family" OS also turn on the ability to forward network connections:
setsebool -P httpd_can_network_connect 1

Setup gevent with Lighttpd, weird stuff

I have wary odd problem. I configured Lighttpd to pass /test to fastcgi backend.
just added this in config
fastcgi.server = ("/test" =>
("127.0.0.1" =>
(
"host" => "127.0.0.1",
"port" => 7101,
"docroot" => "/",
"check-local" => "disable"
)
)
)
Now, when i start flup example, and hit 127.0.0.1:80/test everything work fine. Tested uWSGI to, still fine.
flup example:
#!/usr/bin/env python
from flup.server.fcgi import WSGIServer
def myapp(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World']
WSGIServer(myapp, bindAddress = ('127.0.0.1',7101)).run()
Now, only problem is when I start gevent it won't work. Lighttpd mod_fastcgi says that backend just blocked.
Funny part is when I alter handler to return just string, cause WSGI require iterable, and hit 127.0.0.1:7101 from my browser it work as expected. This should be WSGIServer, how can it work this way?
Here is gevent code:
#!/usr/bin/python
"""WSGI server example"""
from gevent.wsgi import WSGIServer
def app(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
#return ["Hello World", StopIteration] # this is WSGI test, not working
return "Hello World"
# when set like this, frontend :80 still wont work (500 Internal error),
# but 127.0.0.1:7101 work like standard http
if __name__ == '__main__':
WSGIServer(('', 7101), app).serve_forever()
Bottom line is , why only gevent wont work in this setup, and both flup and uWSGI are working? Is there some secret setting not mention in official example here.
Because gevent.wsgi.WSGIServer is not a fcgi server, it's only http server. Your can proxy your requests from lighttpd to gevent as http, or use wsgi.
U can see that flup here states it SPEAK FastCGI (not HTTP), and uWSGI here says "Born as a WSGI-only server".
Now Gevent says here "Fast WSGI server based on libevent-http", that confused me, but then I try gunicorn, and it steel failed.
Then i found here "Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX". That means that gevent and gunicorn WSGI handlers are HTTP request not FastCGI, but ,as Fedor Gogolev said, for your handlers they are WSGI servers.
So for Flup and uWSGI u configure lighttpd (or any other web server) to use fastcgi module, but for gunicorn and gevent u use proxy module, and for them u don't have to use frontend at all!If don't have static stuff to serve or other reason u can omit frontend cause gunicorn state it is wary fast and stable.

Deploying a Flask application with CGI [duplicate]

This question already has answers here:
Deploy flask application on 1&1 shared hosting (with CGI)
(3 answers)
Closed 4 years ago.
I have written a small application using the Flask framework. I try to host this using cgi. Following the documentation I created a .cgi file with the following content:
#!/usr/bin/python
from wsgiref.handlers import CGIHandler
from yourapplication import app
CGIHandler().run(app)
Running the file results in following error:
...
File "/usr/lib/pymodules/python2.7/werkzeug/routing.py", line 1075, in bind_to_environ
wsgi_server_name = environ.get('HTTP_HOST', environ['SERVER_NAME'])
KeyError: 'SERVER_NAME'
Status: 500 Internal Server Error
Content-Type: text/plain
Content-Length: 59
In my application I have set:
app.config['SERVER_NAME'] = 'localhost:5000'
When I run the application with the Flask development server it works perfectly well.
As you can tell I'm very new to this stuff and I have search for others with similar errors but with no luck. All help is appreciated.
I will try to show what I've done and it is working in Godaddy sharing host account:
In the cgi-bin folder in MYSITE folder, I added the following cgi file:
#!/home/USERNAME/.local/bin/python3
from wsgiref.handlers import CGIHandler
from sys import path
path.insert(0, '/home/USERNAME/public_html/MYSITE/')
from __init__ import app
class ProxyFix(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
environ['SERVER_NAME'] = ""
environ['SERVER_PORT'] = "80"
environ['REQUEST_METHOD'] = "GET"
environ['SCRIPT_NAME'] = ""
environ['QUERY_STRING'] = ""
environ['SERVER_PROTOCOL'] = "HTTP/1.1"
return self.app(environ, start_response)
if __name__ == '__main__':
app.wsgi_app = ProxyFix(app.wsgi_app)
CGIHandler().run(app)
As you can see the init file in the MYSITE folder have the flask app.
The most important thing is to set the permissions right. I setted 755 to this folder permission AS WELL AS to "/home/USERNAME/.local/bin/python3" folder!! Remember that the system needs this permission to open flask.
To open the cgi I have the following .htaccess file in MYSITE folder:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /home/USERNAME/public_html/MYSITE/cgi-bin/application.cgi/$1 [L]
So it will render the cgi file when someone enters your page.
This is posted as an answer following the comments above for the sake of completeness.
As discussed above, cgi scripts should execute by some server. Here's the abstract from CGI 1.1 RFC:
The Common Gateway Interface (CGI) is a simple interface for running
external programs, software or gateways under an information server in
a platform-independent manner. Currently, the supported information
servers are HTTP servers.
For the environment variables (which were missing and triggered the error) see sectuib 4.1 in the RFC.

Categories