> On 10 May 2020, at 11:39 pm, 'OwlHoot' via modwsgi <[email protected]> > wrote: > > > I have used mod_wsgi-express to whump up an Apache config. But I found a > problem whereby when run by user "apache" it can't find a python module which > I know is present when running under "root" : > > # whoami > root > > # python -c "import django;" > # > > # su apache > > $ python -c "import django;" > File "<string>", line 1, in <module> > ModuleNotFoundError: No module named 'django'
Most likely because you installed packages as root with some strange restrictive umask or something which resulted in files installed not being accessible to non root user. That or you installed stuff under /root home directory as per user site-packages, which since /root is not accessible to other users will not be able to be read by Apache user. > I recall reading that mod_wsgi and mod_wsgi-express is installed with python > running in some virtual environment. But as I am running this in a Docker > container, I am really not interested in and know little about outdated old > stuff like venv, virtualenv, and suchlike (and I wish there was a > mod_wsgi-express option to use the system-wide python, and not bother with > spinning a virtual cocoon round the python it uses, as doing this simply > complicates things when using Docker! ) Using the system Python installation area rather than a Python virtual environment is still best practice in a container image, because Python packages installed by and required by the operating system can interfere with your ability to install packages you need of specific versions. For a big explanation of the problem see the post I made about this at: * http://blog.dscpl.com.au/2016/01/python-virtual-environments-and-docker.html <http://blog.dscpl.com.au/2016/01/python-virtual-environments-and-docker.html> > So my question is how can I "devirtualise" this python that runs under user > "apache", so it runs the system-wide python3 and its libraries, and thus pick > up the django module among others, the same as "root"? I really recommend against that. I also recommend against running your container as root to begin with as that is a security issue in itself. You also should drop capabilities when running the container so that su/sudo don't work. There is no need for you to start Apache as root and then switch to Apache user. A series of best practices is: * Add a new user account (use pid 1001). * Create a home directory for that user and ensure that the user owns it so it can write to it. * Switch user in Dockerfile to 1001 (don't use the username, use the uid so platforms can verify the container doesn't run as root). The container will later be run as 1001 and not as root. * Create a virtual environment in the home directory. * With virtual environment activated pip install mod_wsgi and all your application packages. * Set up command to run mod_wsgi-express, use port 8080. Do not use port 80 as there is no need to. Map port 80 to port 8080 outside using docker runtime if that is what you really need exposed. There are a bunch of other things you can do to improve this but too much to detail here. A lot of it is perhaps out of date and doesn't reflect what I would regard as best practice now, but have a bunch of other blog posts pin related topic of running Python with Docker at: * http://blog.dscpl.com.au/p/using-python-with-docker.html <http://blog.dscpl.com.au/p/using-python-with-docker.html> I have other workshops as well which cover most up to date stuff. Graham > Thanks in anticipation > > Regards > > John R Ramsden > > P.S. The annoying thing is I had the perishing thing working on Friday, and > carefully preserved my changes, or thought I had. But upon rebuilding the > Docker container, something is not quite the same as before and the Apache > error log has reverted to containing the "Not found 'django'" error as above. > I'd be happy to set the access right to every file in the container to 777 if > that is what it takes, as this app will be running inside an intranet. But I > have a feeling that won't fix the problem, and probably isn't entirely sound > from a security standpoint. > > P.S. As a service to this mailing list, which I hope others may find useful, > I append a python script I wrote to strip out all the extra "ifs and buts" > cruft from the generated httpd.conf file, so one can see more clearly what is > going on. (IMHO it would be a good idea to have a mod_wsgi-express option > that generates the httpd.conf file without them to start with.) The script > may not win any prizes for elegance, but it did the job for me. (But use it > with care, as some version numbers are hard-coded! ) > > #!/usr/bin/python > > import re > > env_vars = dict() > > # Fetch '-D' tokens from httpd command arguments > # > # HTTPD_ARGS="-f /application/apache/httpd.conf -E > /application/apache/startup.log -DMOD_WSGI_VIRTUAL_HOST -DMOD_WSGI_WITH_HTTPS > .." > # > funit = open('apachectl', 'r') > > lines = funit.read().splitlines() > > httpd_args = 'HTTPD_ARGS=' > > for line in lines: > > if len(httpd_args) < len(line) and httpd_args == line[0:len(httpd_args)]: > > matches = re.finditer(' -D[A-Z_]+', line) > > for match in matches: > env_vars[match.group()[3:]] = 1 > > break > > funit.close() > > > # Output httpd.conf file with Ifs and Buts removed > # > n_blank_line = 0 > > old_version = False > > skip_level = 0 > > skip_flags = [] > > defined_no = '<IfDefine !' > defined_yes = '<IfDefine ' > > funit = open('httpd.conf', 'r') > > lines = funit.read().splitlines() > > for line in lines: > > skip = None > > if '<IfVersion >= 2.2.15>' == line or '<IfVersion >= 2.4>' == line: > continue > > elif '<IfVersion < 2.4>' == line: > old_version = True > continue > > elif '</IfVersion>' == line: > if old_version: > old_version = False > > continue > > elif old_version: > continue > > elif '</IfDefine>' == line: > > skip = skip_flags.pop() > > if skip: > > skip_level -= 1 > > continue > > elif defined_no == line[0:len(defined_no)]: > > key = line[len(defined_no) : -1] > > skip = True if key in env_vars else False > > elif defined_yes == line[0:len(defined_yes)]: > > key = line[len(defined_yes) : -1] > > skip = True if key not in env_vars else False > > if skip is not None: > > skip_flags.append(skip) > > if skip: > skip_level += 1 > > continue > > if skip_level == 0: > > # Compress multiple output blank lines to single blank line > # > if re.match(r'^\s*$', line): > n_blank_line += 1 > else: > n_blank_line = 0 > > if n_blank_line > 1: > continue > > print(line) > > funit.close() > > -- > You received this message because you are subscribed to the Google Groups > "modwsgi" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected] > <mailto:[email protected]>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/modwsgi/92ed75db-0c73-462f-8eee-f1e563b42d3f%40googlegroups.com > > <https://groups.google.com/d/msgid/modwsgi/92ed75db-0c73-462f-8eee-f1e563b42d3f%40googlegroups.com?utm_medium=email&utm_source=footer>. -- You received this message because you are subscribed to the Google Groups "modwsgi" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/modwsgi/BB1D70D7-DAB1-451D-963B-D576FAB7911D%40gmail.com.
