Passenger WSGI setup with pyenv on Dreamhost for Web2Py

Update 2019.12.06: I have moved from DreamHost to Google Cloud VPS. If this post does not work for you, please see alternative method in a comment by Chris.

I have been using fastcgi+flup (link) to run my web2py apps on shared Dreamhost hosting. But the speed was really mediocre. Dreamhost recommends Passenger WSGI for python application.

After hours of research and testing, I would like to share my experience using pyenv + passenger wsgi + web2py on Dreamhost shared hosting as of 08.2017

What I did differently than most guides online is that I only have to edit .htaccess file (in domain root folder) with: (Credit: ASO)

PassengerEnabled on
PassengerAppRoot /home/%USER%/
PassengerPython /home/%USER%/.pyenv/shims/python

Most importantly and strangely, I didn’t need to modify passenger_wsgi.py (handlers/wsgihandler.py) at all. Most guides online (this; this; and many others) require adding two lines after import os, such as this one:

INTERP = "/home/%USER%/.pyenv/shims/python"
#INTERP is present twice so that the new Python interpreter knows the actual executable path
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)

But I couldn’t make it work if I modify passenger_wsgi.py. It seems .htaccess is sufficient to specify pyenv environment.

Some guides also suggest make a pyenv “virtualenv” within app folder, I found it is not required.

Assuming you already know:

  1. how to use web2py
  2. how to use pyenv on Dreamhost
  3. Read about Passenger on Dreamhost

This is what I did:

  1. Enable passenger on Dreamhost panel. A folder public will be created. Don’t worry.
  2. Put web2py files into your domain root folder, which is parent folder of public
  3. cp handlers/wsgihandler.py passenger_wsgi.py
  4. Create/modify .htaccess in domain root folder as described above.
  5. Created tmp/ folder under my web root folder, did a touch restart.txt to get passenger to reload

Your web2py site should now load in your browser. If you use free “Let’s Encrypt” SSL from Dreamhost panel, you should be able to verify your pyenv python environment from admin interface by accessing https. I did verify mine.

I am not sure ssh tunnel method could serve as verification, because you are serving admin from a separate web2py instance running from your shell.

Hope this will help fellow web2py users. Thank all the web2py team for providing web2py.

3 thoughts on “Passenger WSGI setup with pyenv on Dreamhost for Web2Py

  1. I have also hit this issue with DreamHost+Python3+Passenger… Does this solution still work for you? I tried setting PassengerPython in my .htaccess pointing to a Python3 in a virtualenv but that did not work; my Python program was always invoked with a Python2 interpreter.

    However I was able to get Passenger working with a Python3 virtualenv on DreamHost using the os.execl(INTERP…) method… With that in my passenger_wsgi.py, I saw this error in my ~/$DOMAIN/logs/http/error.log:

    App 28507 stderr: Traceback (most recent call last):
    App 28507 stderr: File “/usr/share/passenger/helper-scripts/wsgi-loader.py”, line 163, in main_loop
    App 28507 stderr: socket_hijacked = self.process_request(env, input_stream, client)
    App 28507 stderr: File “/usr/share/passenger/helper-scripts/wsgi-loader.py”, line 305, in process_request
    App 28507 stderr: write(data)
    App 28507 stderr: File “/usr/share/passenger/helper-scripts/wsgi-loader.py”, line 264, in write
    App 28507 stderr: output_stream.sendall(data)
    App 28507 stderr: TypeError: a bytes-like object is required, not ‘str’
    App 28507 stderr:

    And based on that I realised that in Python3 the WSGI handler is expecting a bytes type, not a str type. Calling .encode() on the WSGI handler made it work, i.e.:

    import sys, os
    INTERP = “/home/$USER/env/bin/python3”
    if sys.executable != INTERP:
    os.environ[‘LD_LIBRARY_PATH’] = ‘/home/$USER/env/lib/python3.6’
    os.execl(INTERP, INTERP, *sys.argv)

    def application(environ, start_response):
    start_response(‘200 OK’, [(‘Content-type’, ‘text/plain’)])
    return [“Hello, world! from {}: {}\n”.format(sys.version, sys.executable).encode()]

    1. Thanks, Chris. I have moved from DreamHost to google cloud VPS long time ago. So not sure whether what I wrote before still works or not. And it seems you made it work. Thanks for sharing! I will update the post so that people can see your method!

Leave a Reply

Your email address will not be published.