我正在尝试部署为在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


因此可以检查目录/文件的所有权/权限。

09-25 18:06