{"action":"created","issue":{"url":"https://api.github.com/repos/Charlotteis/guestbook/issues/1","labels_url":"https://api.github.com/repos/Charlotteis/guestbook/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/Charlotteis/guestbook/issues/1/comments","events_url":"https://api.github.com/repos/Charlotteis/guestbook/issues/1/events","html_url":"https://github.com/Charlotteis/guestbook/issues/1","id":53518940,"number":1,"title":"Can I actually deploy a cgi script to something like Heroku?","user":{"login":"Charlotteis","id":542140,"avatar_url":"https://avatars.githubusercontent.com/u/542140?v=3","gravatar_id":"","url":"https://api.github.com/users/Charlotteis","html_url":"https://github.com/Charlotteis","followers_url":"https://api.github.com/users/Charlotteis/followers","following_url":"https://api.github.com/users/Charlotteis/following{/other_user}","gists_url":"https://api.github.com/users/Charlotteis/gists{/gist_id}","starred_url":"https://api.github.com/users/Charlotteis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Charlotteis/subscriptions","organizations_url":"https://api.github.com/users/Charlotteis/orgs","repos_url":"https://api.github.com/users/Charlotteis/repos","events_url":"https://api.github.com/users/Charlotteis/events{/privacy}","received_events_url":"https://api.github.com/users/Charlotteis/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Charlotteis/guestbook/labels/help+wanted","name":"help wanted","color":"159818"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2015-01-06T14:21:31Z","updated_at":"2015-01-13T13:44:35Z","closed_at":null,"body":"~"},"comment":{"url":"https://api.github.com/repos/Charlotteis/guestbook/issues/comments/69745436","html_url":"https://github.com/Charlotteis/guestbook/issues/1#issuecomment-69745436","issue_url":"https://api.github.com/repos/Charlotteis/guestbook/issues/1","id":69745436,"user":{"login":"pkqk","id":5235,"avatar_url":"https://avatars.githubusercontent.com/u/5235?v=3","gravatar_id":"","url":"https://api.github.com/users/pkqk","html_url":"https://github.com/pkqk","followers_url":"https://api.github.com/users/pkqk/followers","following_url":"https://api.github.com/users/pkqk/following{/other_user}","gists_url":"https://api.github.com/users/pkqk/gists{/gist_id}","starred_url":"https://api.github.com/users/pkqk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pkqk/subscriptions","organizations_url":"https://api.github.com/users/pkqk/orgs","repos_url":"https://api.github.com/users/pkqk/repos","events_url":"https://api.github.com/users/pkqk/events{/privacy}","received_events_url":"https://api.github.com/users/pkqk/received_events","type":"User","site_admin":false},"created_at":"2015-01-13T13:44:35Z","updated_at":"2015-01-13T13:44:35Z","body":"You shouldn't have to play around with buildpacks, you have a `requirements.txt` file so Heroku should work out that it needs python.\r\n\r\nI've not tested all this but hopefully it should give you enough of a start and clue for what to google\r\n\r\n# Get the server running\r\n\r\nFirst though since you're not using a framework which has a default way to run it you need to tell Heroku to do the `python server.py`, this is done with a file called `Procfile`, this is what Foreman uses but you don't need to care, it just needs to be a file with the line:\r\n\r\n    web: python server.py\r\n\r\nin it, which tells Heroku for the `web` task you want to run this command.\r\n\r\nBy this point you should be able to deploy and it might not crash but it probably won't work.\r\n\r\nTo get the web server bit to work you will need to make it listen on the right port and to not just listen on `127.0.0.1`\r\n\r\nSo first change line 4 in server.py to \r\n```python\r\nHOST = \"0.0.0.0\"\r\n```\r\nThe difference here is that `127.0.0.1` is a special address that is only available from the computer the program is running on, so when you're running it on your machine you can get to it by `localhost` but someone else even on the same network couldn't. `0.0.0.0` means that port will be available on all the networks the computer is connected to (see security issue below).\r\n\r\nNext we need to get the the server to listen on a port that Heroku has exposed to the internet. Before running the command in `Procfile` Heroku will set up some environment variables so they are available to your program. One of them is `PORT` which is the port exposed to the internet via Heroku's routing layer.\r\n\r\nSo we need to get access to that variable from inside the python process. In the `os` module there is a function called [getenv](https://docs.python.org/3/library/os.html#os.getenv) that does this for us.\r\n\r\nSo in server.py add\r\n```python\r\nimport os\r\n```\r\nat the top and change line 3 to\r\n```python\r\nPORT = os.getenv(\"PORT\", 8000)\r\n```\r\nIt will then set `PORT` to the value Heroku gives it or default to 8000 if you're running it locally.\r\n\r\n## Security issue\r\nThere is a slight security issue here, in that if you are developing on your machine someone else on the network can now get to your app, you might want this but if you don't you could change the code too:\r\n```python\r\nPORT = os.getenv(\"PORT\")\r\n# We are not running on Heroku\r\nif PORT is None:\r\n  PORT = 8000\r\n  HOST = \"127.0.0.1\"\r\nelse:\r\n  HOST = \"0.0.0.0\"\r\n```\r\n\r\n# Get the database working\r\n\r\nThe image of the code that Heroku uses is readonly so line 7 in database.py needs to use a different location. If we are lucky you might be able to change it to:\r\n```python\r\nDATABASE = \"/tmp/guestbook.db\"\r\n```\r\nTo get it working temporarily, the only issue here is that the computer running your code in Heroku is temporary, so after you haven't requested it in a while Heroku will stop the code and throw away the virtual machine which means next time it starts up `/tmp/guestbook.db` won't exist anymore. This is why you will need to make it use postgres.\r\n\r\nIf you don't already have a database attached to the project you can [provision one following this guide](https://devcenter.heroku.com/articles/heroku-postgresql#provisioning-the-add-on) and you'll then have an environment variable called `DATABASE_URL` with the connection string in it.\r\n\r\nSo to access the database when running on Heroku you can change the database setup lines to:\r\n```python\r\nimport os\r\nimport urlparse\r\n\r\nDATABASE_URL = os.getenv('DATABASE_URL')\r\n# use sqlite\r\nif DATABASE_URL is None:\r\n  database = SqliteDatabase(\"guestbook.db\")\r\nelse:\r\n  # extract all the database connection parameters from DATABASE_URL\r\n  database_url = urlparse.urlparse(DATABASE_URL)\r\n  # get rid of the \"/\" from the path to get the database name\r\n  database_name = database_url.path[1:]\r\n  # connection arguments are documented here:\r\n  # http://initd.org/psycopg/docs/module.html#psycopg2.connect\r\n  database = PostgresqlDatabase(\r\n    database_name,\r\n    user=database_url.username,\r\n    password=database_url.password,\r\n    host=database_url.hostname,\r\n    port=database_url.port\r\n  )\r\n```\r\n\r\n## We're really close now\r\nIt should all work now, fingers crossed, except that the postgres database won't have the tables created in it. This is what frameworks usually call migrations but for the moment you can just cheat and get a python shell on a Heroku node and run `database.create_tables()` by doing this on your machine\r\n```bash\r\nheroku run python\r\n```\r\nOnce you get the python shell\r\n```python\r\nimport database\r\ndatabase.create_tables()\r\nquit()\r\n```\r\n\r\nThen if everything has worked you should be able to access it in the web browser. 😬"}}