Reputation: 21
I'm trying to deploy a Flask web app I built to be deployed on an Apache server. I'm using Raspbian (Jessie) OS on a Raspberry Pi 3. The app runs perfect on the flask built-in dev web server, but I have been unable to deploy it on the Apache sever.
This is what I did:
sudo apt-get update
sudo apt-get -y install python3 ipython3 python3-flask
sudo apt-get -y install apache2
sudo apt-get -y install libapache2-mod-wsgi-py3
The conf file is: /etc/apach2/sites-available/arduinoweb.conf
:
<VirtualHost *>
ServerName 10.0.0.20
WSGIDaemonProcess arduinoweb user=pi group=pi threads=5
WSGIScriptAlias / /var/www/ArduinoWeb/arduinoweb.wsgi
<Directory /var/www/ArduinoWeb/ArduinoWeb>
WSGIProcessGroup arduinoweb
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Require all granted
</Directory>
Alias /static /var/www/ArduinoWeb/ArduinoWeb/static
<Directory /var/www/ArduinoWeb/ArduinoWeb/static/>
Require all granted
</Directory>
Alias /temp /var/www/ArduinoWeb/ArduinoWeb/temp
<Directory /var/www/ArduinoWeb/ArduinoWeb/temp/>
Require all granted
</Directory>
Alias /templates /var/www/ArduinoWeb/ArduinoWeb/templates
<Directory /var/www/ArduinoWeb/ArduinoWeb/templates/>
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
~
The WSGI script file in /var/www/Arduinoweb/arduinoweb.wsgi
:
import sys
if sys.version_info[0]<3: # require python3
raise Exception("Python3 required! Current (wrong) version: '%s'" % sys.version_info)
sys.path.insert(0, '/var/www/Arduinoweb/Arduinoweb')
from app import app as application
The error log of Apache:
[Wed Sep 21 21:46:22.669633 2016] [wsgi:error] [pid 17681:tid 1972667440] [client 10.0.0.3:64819] mod_wsgi (pid=17681): Target WSGI script '/var/www/ArduinoWeb/arduinoweb.wsgi' cannot be loaded as Python module.
[Wed Sep 21 21:46:22.669971 2016] [wsgi:error] [pid 17681:tid 1972667440] [client 10.0.0.3:64819] mod_wsgi (pid=17681): Exception occurred processing WSGI script '/var/www/ArduinoWeb/arduinoweb.wsgi'.
[Wed Sep 21 21:46:22.670196 2016] [wsgi:error] [pid 17681:tid 1972667440] [client 10.0.0.3:64819] Traceback (most recent call last):
[Wed Sep 21 21:46:22.671185 2016] [wsgi:error] [pid 17681:tid 1972667440] [client 10.0.0.3:64819] File "/var/www/ArduinoWeb/arduinoweb.wsgi", line 8, in <module>
[Wed Sep 21 21:46:22.671238 2016] [wsgi:error] [pid 17681:tid 1972667440] [client 10.0.0.3:64819] from app import app as application
[Wed Sep 21 21:46:22.671406 2016] [wsgi:error] [pid 17681:tid 1972667440] [client 10.0.0.3:64819] ImportError: No module named 'app'
I don't understand why it cant find the app.
This is the python file /var/www/Arduinoweb/Arduinoweb/app.py
:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask import request, redirect, url_for, render_template, jsonify
from socket import *
from time import time
from threading import Timer
from datetime import datetime
import fileinput
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:Qazwsx@localhost/arduinoweb'
app.debug = True
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<user %r>' % self.username
class Temp(db.Model):
__tablename__ = "Temp"
id = db.Column("id", db.Integer, primary_key=True)
Temp = db.Column("Temp", db.Integer)
Date = db.Column("Date", db.Date)
Time = db.Column("Time", db.Time)
DateTime = db.Column("DateTime", db.String)
def __init__(self, Temp, Date=None, Time=None, DateTime=None):
self.Temp = Temp
if Date is None:
Date = str(datetime.now()).split('.')[0]
self.Date = Date
if Time is None:
Time = str(datetime.now()).split('.')[0]
self.Time = Time
if DateTime is None:
DateTime = repr(datetime.now().replace(second=0, microsecond=0)).split('datetime.datetime',1)[1]
self.DateTime = DateTime
class EC(db.Model):
__tablename__ = "EC"
id = db.Column("id", db.Integer, primary_key=True)
EC = db.Column("EC", db.Float)
Date = db.Column("Date", db.Date)
Time = db.Column("Time", db.Time)
DateTime = db.Column("DateTime", db.String)
def __init__(self, EC, Date=None, Time=None, DateTime=None):
self.EC = EC
if Date is None:
Date = str(datetime.now()).split('.')[0]
self.Date = Date
if Time is None:
Time = str(datetime.now()).split('.')[0]
self.Time = Time
if DateTime is None:
DateTime = repr(datetime.now().replace(second=0, microsecond=0)).split('datetime.datetime',1)[1]
self.DateTime = DateTime
class PH(db.Model):
__tablename__ = "PH"
id = db.Column("id", db.Integer, primary_key=True)
PH = db.Column("PH", db.Float)
Date = db.Column("Date", db.Date)
Time = db.Column("Time", db.Time)
DateTime = db.Column("DateTime", db.String)
def __init__(self, PH, Date=None, Time=None, DateTime=None):
self.PH = PH
if Date is None:
Date = str(datetime.now()).split('.')[0]
self.Date = Date
if Time is None:
Time = str(datetime.now()).split('.')[0]
self.Time = Time
if DateTime is None:
DateTime = repr(datetime.now().replace(second=0, microsecond=0)).split('datetime.datetime',1)[1]
self.DateTime = DateTime
class Humidity(db.Model):
__tablename__ = "Humidity"
id = db.Column("id", db.Integer, primary_key=True)
Humidity = db.Column("Humidity", db.Integer)
Date = db.Column("Date", db.Date)
Time = db.Column("Time", db.Time)
DateTime = db.Column("DateTime", db.String)
def __init__(self, Humidity, Date=None, Time=None, DateTime=None):
self.Humidity = Humidity
if Date is None:
Date = str(datetime.now()).split('.')[0]
self.Date = Date
if Time is None:
Time = str(datetime.now()).split('.')[0]
self.Time = Time
if DateTime is None:
DateTime = repr(datetime.now().replace(second=0, microsecond=0)).split('datetime.datetime',1)[1]
self.DateTime = DateTime
class HumidityRoots(db.Model):
__tablename__ = "HumidityRoots"
id = db.Column("id", db.Integer, primary_key=True)
HumidityRoots = db.Column("HumidityRoots", db.Integer)
Date = db.Column("Date", db.Date)
Time = db.Column("Time", db.Time)
DateTime = db.Column("DateTime", db.String)
def __init__(self, HumidityRoots, Date=None, Time=None, DateTime=None):
self.HumidityRoots = HumidityRoots
if Date is None:
Date = str(datetime.now()).split('.')[0]
self.Date = Date
if Time is None:
Time = str(datetime.now()).split('.')[0]
self.Time = Time
if DateTime is None:
DateTime = repr(datetime.now().replace(second=0, microsecond=0)).split('datetime.datetime',1)[1]
self.DateTime = DateTime
@app.route('/Sensors')
def sensors_function():
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto("GETSENSORS".encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return rec_data
@app.route('/OutputsState')
def outputs_state_function():
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto("GETOUTPUTSSTATE".encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return rec_data
@app.route('/WebModeState')
def web_mode_state_function():
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto("GETWEBMODE".encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return rec_data
@app.route('/PLCState')
def plcstatefunction():
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto("GETPLCSTATE".encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return rec_data
@app.route('/IrrigateOnOff')
def irrigate_on_off_function():
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto("IRRIGATEOnOff".encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return rec_data
@app.route('/SprinklersOnOff')
def sprinklers_on_off_function():
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto("SprinklersOnOff".encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return rec_data
@app.route('/SetDateTime' , methods=['POST'])
def set_date_time_function():
completeAnswer = "%s:%s:%s:%s:%s:%s:%s:%s" % ("SETDATETIME", request.form.get('dOw'), request.form.get('SetDate'), request.form.get('SetMonth'), request.form.get('SetYear'), request.form.get('SetHour'), request.form.get('SetMinute'), request.form.get('SetSeconds'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/SetIrrigation' , methods=['POST'])
def set_irrigation_function():
completeAnswer = "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s" % ("SETIRRIGATION",request.form.get('SetIrrigationMode'), request.form.get('SetHumidityRangeMin'), request.form.get('SetHumidityRangeMax'), request.form.get('SetHour1'), request.form.get('SetHour1OnTime'), request.form.get('SetHour1OffTime'), request.form.get('SetHour2'), request.form.get('SetHour2OnTime'), request.form.get('SetHour2OffTime'), request.form.get('SetHour3'), request.form.get('SetHour3OnTime'), request.form.get('SetHour3OffTime'), request.form.get('SetHour4'), request.form.get('SetHour4OnTime'), request.form.get('SetHour4OffTime'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/SetEC' , methods=['POST'])
def set_EC_function():
completeAnswer = "%s:%s:%s:%s:%s" % ("SETEC", request.form.get('SetECRangeMin'), request.form.get('SetECRangeMax'), request.form.get('SetDoseEC'), request.form.get('SetECDelay'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/SetPH' , methods=['POST'])
def set_PH_function():
completeAnswer = "%s:%s:%s:%s:%s:%s" % ("SETPH", request.form.get('SetPHRangeMin'), request.form.get('SetPHRangeMax'), request.form.get('SetDosePHUp'), request.form.get('SetDosePHDown'), request.form.get('SetPHDelay'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/SetWaterTemp' , methods=['POST'])
def set_water_temp_function():
completeAnswer = "%s:%s:%s" % ("SETWATERTEMP", request.form.get('SetWaterTempRangeMin'), request.form.get('SetWaterTempRangeMax'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/SetSprinklers' , methods=['POST'])
def set_sprinklers_function():
completeAnswer = "%s:%s:%s:%s:%s" % ("SETSPRINKLERS", request.form.get('SetSprinklersBeginEndHoursBegin'), request.form.get('SetSprinklersBeginEndHoursEnd'), request.form.get('SetSprinklersOnTime'), request.form.get('SetSprinklersOffTime'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/SetAlerts' , methods=['POST'])
def set_alerts_function():
completeAnswer = "%s:%s:%s:%s:%s:%s" % ("SETALERTS", request.form.get('SetIrrigationThresholdAlert'), request.form.get('ECAlertOffset'), request.form.get('PHAlertOffset'), request.form.get('ResetCounterState'), request.form.get('AlertsState'))
address= ( '192.168.0.196', 5000) #define server IP and port
client_socket =socket(AF_INET, SOCK_DGRAM) #Set up the Socket
client_socket.settimeout(1) #Only wait 1 second for a response
client_socket.sendto(completeAnswer.encode(), address) #Send the data request
rec_data, addr = client_socket.recvfrom(2048) #Read response from arduino
return "ok"
@app.route('/')
def index():
return render_template('index.html')
@app.route('/Charts')
def charts():
return render_template('charts.html')
@app.route('/livechart')
def live_chart():
return render_template('livechart.html')
@app.route('/TempQuery' , methods=['POST'])
def temp_query():
answerDate = request.form.get('date')
answerSensor = request.form.get('sensor')
datafile = 'temp/TempByDateDbFile.txt'
if answerSensor == 'Temp':
DbTemp = Temp.query.filter_by(Date = answerDate).all()
## create the file from db
file = open(datafile, 'w')
for item in DbTemp:
file.write('{x: new Date' + str(item.DateTime) + ' , y: ' + str(item.Temp) + '},' + '\n')
file.close()
elif answerSensor == 'EC':
DbTemp = EC.query.filter_by(Date = answerDate).all()
## create the file from db
file = open(datafile, 'w')
for item in DbTemp:
file.write('{x: new Date' + str(item.DateTime) + ' , y: ' + str(item.EC) + '},' + '\n')
file.close()
elif answerSensor == 'PH':
DbTemp = PH.query.filter_by(Date = answerDate).all()
## create the file from db
file = open(datafile, 'w')
for item in DbTemp:
file.write('{x: new Date' + str(item.DateTime) + ' , y: ' + str(item.PH) + '},' + '\n')
file.close()
elif answerSensor == 'Humidity':
DbTemp = Humidity.query.filter_by(Date = answerDate).all()
## create the file from db
file = open(datafile, 'w')
for item in DbTemp:
file.write('{x: new Date' + str(item.DateTime) + ' , y: ' + str(item.Humidity) + '},' + '\n')
file.close()
elif answerSensor == 'HumidityRoots':
DbTemp = HumidityRoots.query.filter_by(Date = answerDate).all()
## create the file from db
file = open(datafile, 'w')
for item in DbTemp:
file.write('{x: new Date' + str(item.DateTime) + ' , y: ' + str(item.HumidityRoots) + '},' + '\n')
file.close()
##replace "-" in ","
f = open(datafile,'r')
filedata = f.read()
f.close()
newdata = filedata.replace("-",", ")
f = open(datafile,'w')
f.write(newdata)
f.close()
return 'OK'
@app.route('/RenderTempChart' , methods=['POST' , 'GET'])
def render_temp_chart():
datafile = 'temp/TempByDateDbFile.txt'
with open(datafile, 'r') as myfile:
file = myfile.read()
return render_template('DbTemp.html', file = file)
@app.route('/Control' , methods=['POST' , 'GET'])
def control():
return render_template('control.html')
"""
def update_data(interval): # store in DB all sensors real time data
Timer(interval, update_data, [interval]).start()
SensorsAnswer = sensors_function().split()
addTemp = Temp(int(SensorsAnswer[2]))
addEC = EC(float(SensorsAnswer[0]))
addPH = PH(float(SensorsAnswer[1]))
addHumidity = Humidity(int(SensorsAnswer[3]))
addHumidityRoots = HumidityRoots(int(SensorsAnswer[5]))
db.session.add(addTemp)
db.session.add(addEC)
db.session.add(addPH)
db.session.add(addHumidity)
db.session.add(addHumidityRoots)
db.session.commit()
update_data(300) # Store data in DB every x seconds
"""
if __name__ == "__main__":
app.run()
It's not working even with a simple code like this (same error):
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello world!"
if __name__ == "__main__":
app.run()
I'm using python 3.4.2. I'm not using it in a virtual environment.
The folder structure:
app.py
is at /var/www/Arduinoweb/Arduinoweb/app.py
arduinoweb.wsgi
is at /var/www/Arduinoweb/arduinoweb.wsgi
I do enable the VirtualHost arduinoweb.conf and restart apach2 service.
Upvotes: 1
Views: 407
Reputation: 21
thanks for the help .. eventually it was seems to be just a typing mistake in the wsgi script path: "/var/www/ArduinoWeb/ArduinoWeb" instead "/var/www/Arduinoweb/Arduinoweb" .
now its seems to work fine . thanks!!
Upvotes: 1
Reputation: 58523
For a start, this:
<Directory /var/www/ArduinoWeb/ArduinoWeb>
WSGIProcessGroup arduinoweb
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Require all granted
</Directory>
should be:
<Directory /var/www/ArduinoWeb>
WSGIProcessGroup arduinoweb
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
Technically this being wrong would cause two problems.
The first is that Apache shouldn't have even let you use that WSGI script as it wouldn't have permission to. Looks though like somewhere else in your Apache configuration is giving broad access to your file system when it shouldn't really.
I have also dropped the reloading option as that default to on anyway and isn't needed.
The second is that the WSGI script wouldn't be run in the context of the daemon process group. This would mean code would load in embedded mode instead and would run as Apache user. If the permissions on your files were such that only the pi
user could read them, then it wouldn't be able to access the app
module.
It is also generally wrong to have SeverName
be an IP address. If it is working then it is only doing so because this is the first VirtualHost
in the Apache configuration and so Apache is defaulting to using it when it can't properly do name base virtual host matching.
Anyway, see if that helps, otherwise provide output of running:
ls -las /var/www/ArduinoWeb /var/www/ArduinoWeb/ArduinoWeb
so can check what ownership/permissions of directories/files are.
Upvotes: 1