4

Latest update: The problem had indeed to do with permission and user groups, today I learned why we do not simply use root for everything. Thanks to Jakub P. for reminding me to look into the apache error logs and thanks to domoarrigato for providing helpful insight and solutions.


What's up StackOverflow.

I followed the How To Deploy a Flask Application on an Ubuntu VPS tutorial provided by DigitalOcean, and got my application to successfully print out Hello, I love Digital Ocean! when being reached externally by making a GET request to my public server IP.

All good right? Not really.

After that, I edit the tutorial script and write a custom flask application, I test the script in my personal development environment and it runs without issue, I also test it on the DigitalOcean server by having it deploy on localhost and making another GET request.

All works as expected until I try to access it from my public DigitalOcean IP, now suddenly I am presented with a 500 Internal Server Error.

What is causing this issue, and what is the correct way to debug in this case?

What have I tried?

  • Setting app.debug = True gives the same 500 Internal Server Error without a debug report.

  • Running the application on the localhost of my desktop pc and DigitalOcean server gives no error, the script executes as expected.

  • The tutorial code runs and executed fine, and making a GET request to the Digital Ocean public IP returns the expected response.

  • I can switch between the tutorial application and my own application and clearly see that I am only getting the error wit my custom application. However the custom application still presents no issues running on localhost.

My code

from flask import Flask, request, redirect
from netaddr import IPNetwork
import os
import time

app         = Flask(__name__)
APP_ROOT    = os.path.dirname(os.path.abspath(__file__))

# Custom directories
MODULES     = os.path.join(APP_ROOT, 'modules')
LOG         = os.path.join(APP_ROOT, 'log')


def check_blacklist(ip_adress):
    ipv4 = [item.strip() for item in open(MODULES + '//ipv4.txt').readlines()]
    ipv6 = [item.strip() for item in open(MODULES + '//ipv6.txt').readlines()]

    for item in ipv4 + ipv6:
        if ip_adress in IPNetwork(item):
            return True

        else:
            pass

    return False


@app.route('/')
def hello():
    ip_adress   = request.environ['REMOTE_ADDR']
    log_file    = open(LOG + '//captains_log.txt', 'a')

    with log_file as f:

        if check_blacklist(ip_adress):
            f.write('[ {}: {} ][ FaceBook ] - {} .\n'
                    .format(time.strftime("%d/%m/%Y"), time.strftime("%H:%M:%S"), request.environ))
            return 'Facebook'

        else:
            f.write('[ {}: {} ][ Normal User ] - {} .\n'
                    .format(time.strftime("%d/%m/%Y"), time.strftime("%H:%M:%S"), request.environ))
            return 'Normal Users'


if __name__ == '__main__':
    app.debug = True
    app.run()

The tutorial code:

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello, I love Digital Ocean!"
if __name__ == "__main__":
    app.run()
Community
  • 1
  • 1
Olav A
  • 301
  • 3
  • 10
  • can you ssh into the server and run the application manually from the command line? then you can inspect the stacktrace in the shell - should be enlightening. – domoarigato May 27 '16 at 12:23
  • I did this, no errors and it runs like expected. – Olav A May 27 '16 at 12:24
  • wait, so it works now? the 500 error is gone? If you receive a 500 error in the browser, and you dont see a corresponding stack trace in the shell where you are running the application, then your browser is not pointed at the same application. – domoarigato May 27 '16 at 12:27
  • Sorry, I should have eloborated, your questions is kinda answered in my post though: `Running the application on the localhost of my desktop pc and DigitalOcean server gives no error, the script executes as expected.` what I mean is, when I run it manually from command line `python __init__.py` the flask application starts and when making a `GET` to the localhost address `requests.get('http://127.0.0.1:5000/').content` it returns `Normal Users` like expected. The `500 Internal Server Error` only appears when trying to reach the server by public IP address, – Olav A May 27 '16 at 12:31
  • However, updating the `__init__.py` to the tutorial code, the `500 Internal Server Error` dissapears. – Olav A May 27 '16 at 12:32
  • This is normal, as you run app with app.run(0.0.0.0) cf: http://stackoverflow.com/questions/7023052/flask-configure-dev-server-to-be-visible-across-the-network – Paul May 27 '16 at 12:34
  • 1
    You should inspect the error log and access log of Apache (I'm assuming virtualhost config similar to the one in the DigitalOcean article). It could be as trivial as something in your code becoming None (null) when accessed from outside of localhost, breaking your code. What does the 500 stack trace show? Is access log as expected? – Jakub P. May 27 '16 at 12:34
  • 1
    @PaulHOCHON he is getting a response from the server, so it seems to be listening on the right address/hostname anyway. Still, I never tried with Apache so who knows :) – Jakub P. May 27 '16 at 12:35
  • @JakubP. the apache error.log is showing a permission denied error: `IOError: [Errno 13] Permission denied: '/var/www/flaskapp/flaskapp/log//captains_log.txt'` – Olav A May 27 '16 at 12:39
  • remove one of the `/` in `//captains_log.txt` – domoarigato May 27 '16 at 12:40
  • I'm thinking the error is caused by root and www not being part of the same group, therefore unable to access the files outside of the root of the flaskapp directory, will update once I checked this out. – Olav A May 27 '16 at 12:42
  • 1
    Good. You'll solve it now. :) – Jakub P. May 27 '16 at 12:48

1 Answers1

1

Seems like the following line could be a problem:

log_file    = open(LOG + '//captains_log.txt', 'a')

if the path its looking for is: '/var/www/flaskapp/flaskapp/log//captains_log.txt'

that would make sense that an exception is thrown there. Possible that the file is in a different place, on the server, or a / needs to be removed - make sure the open command will find the correct file.

If captains_log.txt is outside the flask app directory, you can copy it in and chown it. if the txt file needs to be outside the directory then you'll have to add the user to the appropriate group, or open up permissions on the actual directory.

chown command should be:

sudo chown www:www /var/www/flaskapp/flaskapp/log/captains_log.txt

and it might be smart to run:

sudo chown -r www:www /var/www
domoarigato
  • 2,802
  • 4
  • 24
  • 41
  • good thought, however it is finding the file. It's throwing a permission denied, I screwed up with user groups somewhere along the line. – Olav A May 27 '16 at 12:50
  • what is the actual path and permissions for it? paste in results of ls -l – domoarigato May 27 '16 at 12:52
  • How do you know that APP_ROOT points at `var/www/flaskapp`? It looks like it is wherever the file is started from – OneCricketeer May 27 '16 at 12:53
  • that's exactly why. It's the starting directory. And I know because I checked the apache error log. As mentioned in one of the comments to the OP: `IOError: [Errno 13] Permission denied: '/var/www/flaskapp/flaskapp/log//captains_log.txt'` the `//` are not the cause of any trouble here. The files and dir that the `captains_log.txt` are in are owned by `root`, apache runs under `www` which is a different group, which means that the `www` group is getting a permission denied on the files and dir owned by `root`. – Olav A May 27 '16 at 12:56
  • 1
    try to chown it - something like in my updated answer – domoarigato May 27 '16 at 12:58
  • I fixed the issue, and it was indeed permissions and user groups, thanks for the help, I tagged you in the OP, hope you don't mind :) – Olav A May 27 '16 at 13:19