apacheflaskmod-wsgi

mod_wsgi: ModuleNotFoundError: No module named 'app'


I'm trying to deploy a very simple Flask app that appears in this tutorial for testing login capabilities in a flask app: https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login. I only changed a few things but it is mostly the same. The app structure is this one:

App structure

When I run it locally and externally through the flask server it works great but when I try to serve it through Apache it fails with a "Internal Server Error" message and the following errors in the error.log from Apache:

> [Tue May 09 19:48:18.108969 2023] [wsgi:error] [pid 31601] [client 185.216.73.35:9480] mod_wsgi (pid=31601): Failed to exec Python script file '/var/www/bdl/portal/app.wsgi'.
[Tue May 09 19:48:18.109123 2023] [wsgi:error] [pid 31601] [client 185.216.73.35:9480] mod_wsgi (pid=31601): Exception occurred processing WSGI script '/var/www/bdl/portal/app.wsgi'.
[Tue May 09 19:48:18.116248 2023] [wsgi:error] [pid 31601] [client 185.216.73.35:9480] Traceback (most recent call last):
[Tue May 09 19:48:18.116298 2023] [wsgi:error] [pid 31601] [client 185.216.73.35:9480]   File "/var/www/bdl/portal/app.wsgi", line 4, in <module>
[Tue May 09 19:48:18.116305 2023] [wsgi:error] [pid 31601] [client 185.216.73.35:9480]     from app import main as application
[Tue May 09 19:48:18.116322 2023] [wsgi:error] [pid 31601] [client 185.216.73.35:9480] ModuleNotFoundError: No module named 'app'

This is the content from the app.wsgi file:

import sys
sys.path.insert(0, "/var/www/bdl/portal")
from app import main as application

This is the __init__.py:

activate_this_file = "/var/www/bdl/auth/bin/activate_this.py"
with open(activate_this_file) as _file:
    exec(_file.read(), dict(__file__=activate_this_file))


    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_login import LoginManager

    # init SQLAlchemy so we can use it later in our models
    db = SQLAlchemy()

    def create_app():
        app = Flask(__name__)

        app.config['SECRET_KEY'] = 'xxxxxxxxxxxxxxxxx'
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'

        db.init_app(app)

        login_manager = LoginManager()
        login_manager.login_view = 'auth.login'
        login_manager.init_app(app)

        from .models import User

        @login_manager.user_loader
        def load_user(user_id):
            # since the user_id is just the primary key of our user table, use it in the query for the user
            return User.query.get(int(user_id))

        # blueprint for auth routes in our app
        from .auth import auth as auth_blueprint
        app.register_blueprint(auth_blueprint)

        # blueprint for non-auth parts of app
        from .main import main as main_blueprint
        app.register_blueprint(main_blueprint)

        from . import models
        with app.app_context():
            db.create_all()

        return app

This is the main.py file:

from flask import Blueprint, render_template
from flask_login import login_required, current_user
from . import db

main = Blueprint('main', __name__)

@main.route('/')
def index():
    return render_template('index.html')

@main.route('/profile')
@login_required
def profile():
    return render_template('profile.html', name=current_user.name)

And this is the Apache .conf file:

<VirtualHost *:80>
    ServerName balldatalab.com
    ServerAlias www.balldatalab.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/bdl/portal
                RewriteEngine on
                RewriteCond %{HTTPS} !=on
                RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
    WSGIScriptAlias / /var/www/bdl/portal/app.wsgi
    <Directory /var/www/bdl/portal>
      Order allow,deny
      Allow from all
    </Directory>

   ErrorLog /var/www/bdl/portal/logs/error.log    CustomLog /var/www/bdl/portal/logs/access.log combined </VirtualHost>

<VirtualHost *:443>
    ServerName balldatalab.com
    ServerAlias www.balldatalab.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/bdl/portal
                SSLEngine on
                SSLCertificateFile /etc/ssl/certs/bdl9.cer
                SSLCertificateKeyFile /etc/ssl/private/bdl9.key
                SSLCertificateChainFile /etc/ssl/certs/bdl9-inter.cer
    WSGIScriptAlias / /var/www/bdl/portal/app.wsgi
    <Directory /var/www/bdl/portal>
      Order allow,deny
      Allow from all
    </Directory>

   ErrorLog /var/www/bdl/portal/logs/error.log    CustomLog /var/www/bdl/portal/logs/access.log combined

</VirtualHost>

I really don't know what's wrong here, can you help me? Thanks in advance!


Solution

  • It's complaining because--as the error says--there's no Python module named app in the portal directory. app.wsgi isn't a Python module. You need to either have an app.py file or an /app/ directory which contains an __init__.py file in it. So the quickest way to fix the issue would be to rename /portal/__init__.py to app.py.

    However, beyond that:

    1. your __init__.py file doesn't actually create a Flask app object named main (which is what you're trying to import in your app.wsgi file). It has a create_app() function that returns a Flask app object, but no code that actually calls that function and assigns it to a variable named main.
    2. Your create_app() function also references an auth module that I don't see in your list of files/directories; I recommend you comment out that code until you get a 'hello world' app running.

    I would recommend you try to change __init__.py (which you should rename to app.py) to something like this for now:

    app.py
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_login import LoginManager
    
    # init SQLAlchemy so we can use it later in our models
    db = SQLAlchemy()
    
    app = Flask(__name__)
    
    app.config['SECRET_KEY'] = 'xxxxxxxxxxxxxxxxx'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
    
    db.init_app(app)
    
    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)
    
    from .models import User
    
    @login_manager.user_loader
    def load_user(user_id):
        # since the user_id is just the primary key of our user table, use it in the query for the user
        return User.query.get(int(user_id))
    
    # From Nathan: Comment this stuff out if you don't have an auth module set up yet.
    # blueprint for auth routes in our app
    # from .auth import auth as auth_blueprint
    # app.register_blueprint(auth_blueprint)
    
    # blueprint for non-auth parts of app
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    
    from . import models
    with app.app_context():
        db.create_all()