My goal is for my Flask app to switch databases based on the subdomain.
The subdomain dispatcher described in the docs is useful and I'm using something based off it
Everything seems to work fine but only 2 instances seem to work at a given time despite the SubDomainDispatcher having multiple instances loaded. The other instances give out 404s.
My create_app function is as follows:
def create_app(subdomain):
app = Flask("proj", static_folder="../static", template_folder="../templates")
with app.app_context():
app.config.from_object('proj.config')
app.config.update(
SQLALCHEMY_DATABASE_URI = 'mysql://root:password#localhost:3306/' + subdomain + '_proj',
HOST = subdomain + app.config["HOST"],
)
from proj.models import db, Models
engine = sqlalchemy.create_engine("mysql://root:passwordT#localhost:3306")
engine.execute("CREATE DATABASE IF NOT EXISTS "+subdomain+"_proj")
engine.execute("use "+subdomain+"_proj")
db.init_app(app)
db.create_all()
mail = Mail(app)
store = DictStore()
KVSessionExtension(store, app)
import proj.views
return app
I'm using Apache with mod_wsgi:
Apache Config
<VirtualHost *:80>
ServerName mywebsite.com
ServerAdmin admin#mywebsite.com
WSGIScriptAlias / /var/www/proj/app.wsgi
WSGIDaemonProcess application user=www-data group=www-data processes=5 threads=20
<Directory /var/www/proj/proj/>
Order allow,deny
Allow from all
</Directory>
#Alias /static /var/www/FlaskApp/FlaskApp/static
#<Directory /var/www/FlaskApp/FlaskApp/static/>
# Order allow,deny
# Allow from all
#</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
wsgi file
import sys
sys.path.insert(0, '/var/www/proj')
from subdomain import SubdomainDispatcher
from proj import create_app
application = SubdomainDispatcher(create_app)
Seems like some sort of race condition but I don't see where or why it would be happening. I've tried reducing the amount of processes and threads to 1 each but that also did not see to work.
Any advice is greatly appreciated as I've been struggling with this for awhile.
After a few other eyes took a look, the problem is that imports will only run once causing routes to only ever be associated to the first app created.
Essentially views are only ever instantiated once for the first app/subdomain hit.
The solution is instead of importing you have function in each module initializing the routes.
As so in views.py:
def init_views(app):
#app.route('/page')
def page():
return "asdf"
Thus each app has it's own copy of the routes instead of only the first.
What a doozy.
Related
I know this question has been asked several times, but I am all out of ideas and have been reading everywhere about this.
I am running Ubuntu 17.04 and Apache 2.4.25 to host a web server. I have generated my own SSL certificate. Since doing this, I am unable to view any images over SSL. Currently, I can confirm the path is working, the file is in tact and URL is correct, as I can access this typing the http URL into my browser.
If I go to the web inspector whilst loading my site, if I click on any image it gives me a 404 error.
How do I get these images to load over SSL.
My apache2 config is:
<VirtualHost *:80>
ServerName localhost
ServerAdmin info#****.com
DocumentRoot /var/www/****.com/pay
Redirect /secure https://****.com/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:443>
SSLEngine On
SSLCertificateFile /etc/ssl/certs/****.com.crt
SSLCertificateKeyFile /etc/ssl/private/****.com.key
SSLCACertificateFile /etc/ssl/certs/ca-certificates.crt
SetEnv SECRET_KEY ****
SetEnv PUBLISHABLE_****
ServerAdmin info#****.com
ServerName www.****.com
DocumentRoot /var/www/****.com/pay/static
WSGIDaemonProcess webtool threads=5 python-path=/var/www/****.com/pay
WSGIScriptAlias / /var/www/****.com/pay/webtool.wsgi
EnableMMAP off
EnableSendfile off
<Directory /var/www/****.com/pay>
Options +ExecCGI
WSGIProcessGroup webtool
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
and I have a python script running to do my routes:
import os
import stripe
import cgi
print "Context-type: text/html"
from flask import Flask, render_template, request, redirect, send_from_directory
from flask import request
from flask import json
stripe_keys = {
'secret_key': os.environ['SECRET_KEY'],
'publishable_key': os.environ['PUBLISHABLE_KEY']
}
stripe.api_key = stripe_keys['secret_key']
app = Flask(__name__, static_url_path='')
#app.route('/')
def index():
return render_template('index.html', key=stripe_keys['publishable_key'])
#app.route("/hello")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(host="127.0.0.1", port="5050")
#app.route("/charge", methods=['POST'])
def charge():
# Amount in cents
amount = 500
customer = stripe.Customer.create(
email=request.form['stripeEmail'],
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
receipt_email=request.form['stripeEmail'],
amount=amount,
currency='usd',
description='Donation'
)
return render_template('charge.html', amount=amount)
I cannot work out if I need to set a route in my python script to allow images to be fetched, or I am missing something else.
I am calling the image in my index.html file with:
with the 'img' folder being in the same location as index.html. Please help.
Your image requests are being sent to WSGI, if you want Apache to handle them, you'll have to "undo" the WSGIScriptAlias of /.
I'm not a WSGI user, but it seems like you could block this from
running conditionally by putting this in your vhost:
RewriteEngine ON
RewriteRule ^/img/ - [L]
Even though this is a no-op, it should block this part of WSGi from running.
I have multiple routes which have the same URL root.
Example:
abc/def/upload
abc/def/list
abc/def/page/{page_id}
Can I define abc/def to be URL root. (Something similar to what can be done in Java using Spring or Apache CXF)
Thanks
In flask-restful it is possible to prefix all your routes on api initialization:
>>> app = Flask(__name__)
>>> api = restful.Api(app, prefix='/abc/def')
You can then wire your resources ignoring any prefixes:
>>> api.add_resource(MyResource, '/upload')
>>> ...
You can use the APPLICATION_ROOT key for your app's config.
app.config['APPLICATION_ROOT'] = "/abc/def"
source - Add a prefix to all Flask routes
I needed similar so called "context-root". I did it in conf file under /etc/httpd/conf.d/ using WSGIScriptAlias :
myapp.conf
<VirtualHost *:80>
WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py
<Directory /home/<myid>/myapp>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
So now I can access my app as : http://localhost:5000/myapp
See the guide - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html
Just use Blueprint from Flask:
app = Flask(__name__)
bp = Blueprint('', __name__, url_prefix="/abc/def")
def upload():
pass
def list():
pass
bp.add_url_rule('/upload', 'upload', view_func=upload)
bp.add_url_rule('/list', 'list', view_func=list)
...
app.register_blueprint(bp)
I've built an API in Flask, using Twilio's Restful extension. Everything works perfectly on Flask's development server. However once I move the app over to Apache and mod_wsgi, some routes stopped working
Apache config:
Listen 1337
<VirtualHost *:1337>
ServerName layer
ServerAdmin webmaster#localhost
DocumentRoot /var/www/layer
WSGIDaemonProcess layer user=this_is_me group=www-data threads=5
WSGIScriptAlias / /var/www/layer/app.wsgi
WSGIScriptReloading On
<Directory /var/www/layer>
WSGIProcessGroup layer
WSGIApplicationGroup %{GLOBAL}%
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order deny,allow
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel info
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
In app.wsgi:
from src import app
application = app.create_app()
In app.py:
#!flask/bin/python
from flask import Flask, request, jsonify, Response
from flask.ext.restful import Resource, Api
from view import treeView, createBranchView, branchView, lineView, bulkView
def create_app():
app = Flask(__name__)
api = Api(app, catch_all_404s=True)
logging.basicConfig(filename=os.path.abspath('exlayer.log'), level=logging.DEBUG)
#Some stand alone routes
#app.route('/')
def index():
### Some code here ###
return jsonify({'status': 200, 'success':True})
#app.route('/create/', methods = ['POST'])
def create_tree():
### Some more code ###
return jsonify(dict(status=200, success=True))
## The rest of the routes
api.add_resource(treeView.dataTree, '/<tree_name>/')
api.add_resource(lineView.lineData, '/<tree_name>/line/<line_id>/')
api.add_resource(bulkView.bulkData, '/<tree_name>/bulk/<bulk_id>/')
api.add_resource(createBranchView.createBranch, '/<tree_name>/branch/')
api.add_resource(branchView.branchData, '/<tree_name>/branch/<branch_identifier>/')
app.config.from_pyfile('../config/config.py')
return app
In bulkView
So here's where things get interesting, if I send a get request to this route I get a Method Not Allowed 405 error. If I send a delete request it works fine. Virtually the same exact code runs in lineView without a problem.
from flask import Flask, request, jsonify, Response
from flask.ext.restful import Resource, Api
from src import helper
class bulkData(Resource):
def get(self, tree_name, bulk_id):
## Some code here ##
return jsonify({'status': 200, 'success':True})
def delete(self, tree_name, bulk_id):
## Some code here ##
return jsonify({'status': 200, 'success':True})
In branchView
Requests to either route concerning branches 404s. Checked the permissions on the files, tried splitting the classes up into separate files. No idea what's wrong :(
Use of os.path.abspath() and ../config/config.py will both cause problems because the working directory of your process will not be where your project is under Apache. Calculate absolute paths relative to os.path.dirname(file). See the mod_wsgi documentation:
http://code.google.com/p/modwsgi/wiki/ApplicationIssues#Application_Working_Directory
I am trying to get django to work on apache with mod_wsgi. My djang.wsgi code is:
import os, sys
sys.path.append('C:/djcode/mysite')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
And my configuration in 'httpd' is:
Alias /static/ "C:/djcode/mysite/static/"
<Directory C:/djcode/mysite/static/>
Order deny,allow
Allow from all
</Directory>
WSGIScriptAlias / C:/djcode/mysite/apache/django.wsgi
<Directory C:/djcode/mysite/apache>
Order deny,allow
Allow from all
</Directory>
Alias /files/ "C:/djcode/mysite/files/"
<Directory C:/djcode/mysite/files/>
Order deny,allow
Allow from all
</Directory>
In the folder 'files' are files where I read data (not databases) which are used to output in templates.
The urls.py code is as follows:
urlpatterns = patterns('',
('^all/$', all),
('^(sport)/$', gen),
('^(teknology)/$', gen),
...
When I start Apache, localhost, the message is "It works!". But when I try localhost/all' or localhost/mysite or localhost/mysite/all, the browser says "The requested URL /all was not found on this server`. I can not understand where does it fail
Where is the definition or class for all? It's technically the controller. Can you post it?
This line routes it:
('^all/$', all)
But we don't know what all is.
Please make sure, you have the VirtualHost configuration correctly setup in the httpd.conf file. Try using localhost first (as the ServerName) and see if it works.
Am running with Python 2.7, Apache + mod_wsgi on CentOS 6.3
Things work fine when I am on localhost. However, when I run the code on a vm in Azure, I do not see the session information being persisted across pages.
Basically in my views, I have something like:
#frontend.route('/')
def index():
session['foo'] = 'bar'
print session['foo']
return redirect(url_for("frontend.page2"))
#frontend.route('page2')
def page2():
print session
The print output is:
bar
<SecureCookieSession {}>
My wsgi configuration for apache is:
WSGISocketPrefix /var/run/wsgi
<VirtualHost *:80>
ServerName example.com
ServerAlias example.com
WSGIDaemonProcess myproj threads=5 processes=5
WSGIScriptAlias / /home/mydir/myproj/apache/myproj.wsgi
<Directory /home/mydir/myproj>
WSGIScriptReloading On
WSGIProcessGroup myproj
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
I have the secret_key set:
app.secret_key = os.urandom(24)
I have tried with both setting SERVER_NAME but it doesn't help:
app.config['SERVER_NAME'] = 'example.com'
Any ideas on how I can debug this more?
Thanks!
Don't use app.secret_key = os.urandom(24)!
You're supposed to enter a static value here, not read from os.urandom each time. You've probably misunderstood the example in the docs, it shows you how you can read random data from os.urandom, but it also clearly states:
Just take that thing and copy/paste it into your code and you’re done
If you read it at runtime, then each of your worker processes will have a different secret key! That means if a request is handled by a different worker, the session will break because the cookie is signed with the wrong secret key.