我正在尝试部署为在Apache服务器上提供服务而构建的Flask Web应用程序。
我在rasberry pi 3上使用rasbian(Jessie)操作系统。
该应用程序可以在flask内置的dev网络服务器上完美运行,但是无论如何我仍无法将其部署在apach上,这就是我所做的:
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
conf文件是:
/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>
~
/var/www/Arduinoweb/arduinoweb.wsgi中的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
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'
我不明白为什么找不到应用程序。
这是python文件
/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()
即使使用这样的简单代码(相同的错误),它也不起作用:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello world!"
if __name__ == "__main__":
app.run()
我正在使用python 3.4.2。我不在虚拟环境中使用它。
文件夹结构:
app.py
位于/var/www/Arduinoweb/Arduinoweb/app.py
arduinoweb.wsgi
位于/var/www/Arduinoweb/arduinoweb.wsgi
我确实启用了VirtualHost arduinoweb.conf并重新启动apach2服务。
最佳答案
首先,这是:
<Directory /var/www/ArduinoWeb/ArduinoWeb>
WSGIProcessGroup arduinoweb
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Require all granted
</Directory>
应该:
<Directory /var/www/ArduinoWeb>
WSGIProcessGroup arduinoweb
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
从技术上讲,这种错误会导致两个问题。
首先是Apache甚至不应该让您使用该WSGI脚本,因为它没有权限。看起来,虽然Apache配置中的其他地方确实提供了对文件系统的广泛访问,但实际上并非如此。
我也已经删除了重载选项,因为无论如何它都是默认值,并且不是必需的。
第二个是WSGI脚本不会在守护进程组的上下文中运行。这意味着代码将改为以嵌入式模式加载,并以Apache用户身份运行。如果您对文件的权限仅允许
pi
用户可以读取,则它将无法访问app
模块。将
SeverName
用作IP地址通常也是错误的。如果它在工作,那么它只是这样做,因为这是Apache配置中的第一个VirtualHost
,因此Apache在无法正确进行基于名称的虚拟主机匹配时默认使用它。无论如何,请查看是否有帮助,否则提供运行结果:
ls -las /var/www/ArduinoWeb /var/www/ArduinoWeb/ArduinoWeb
因此可以检查目录/文件的所有权/权限。