├── favicon.ico ├── .well-known └── acme-challenge │ ├── BPgVqxFMZAg29d7KfHwS2xGvRa79EKblxgWDn_44_N0 │ ├── FJ76sYmjUGa6JLc5s2J_QeQzqcBnmO2AAV6wr4sWe5E │ ├── T4XE4bNn2nrblyobGQyqEsLY2GvcDUYeMPYfKl5neWw │ ├── WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0 │ ├── _-SyF07cuWWE6OgqWRRq-QCWDfG2NOxqm_U5gT-7L8A │ ├── iTMP1u9ugjJG3m7xHpd7JNxF6EPREu--7jzK5qjVmxU │ └── qN0VkWVSSAqFmDkV90s_gZKkFYXbmbXG53nbfVeeXqE ├── .gitignore ├── package.json ├── index.html ├── update_stack.py ├── README.md ├── elixir-phoenix-app-deployment.md └── SSL-certificate-step-by-step-setup-instructions.md /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwyl/learn-heroku/HEAD/favicon.ico -------------------------------------------------------------------------------- /.well-known/acme-challenge/BPgVqxFMZAg29d7KfHwS2xGvRa79EKblxgWDn_44_N0: -------------------------------------------------------------------------------- 1 | BPgVqxFMZAg29d7KfHwS2xGvRa79EKblxgWDn_44_N0.NqTSciiSqnBus5ylE1wdT7QOgICWBgpA_OHhYIuyCxI -------------------------------------------------------------------------------- /.well-known/acme-challenge/FJ76sYmjUGa6JLc5s2J_QeQzqcBnmO2AAV6wr4sWe5E: -------------------------------------------------------------------------------- 1 | FJ76sYmjUGa6JLc5s2J_QeQzqcBnmO2AAV6wr4sWe5E.NqTSciiSqnBus5ylE1wdT7QOgICWBgpA_OHhYIuyCxI -------------------------------------------------------------------------------- /.well-known/acme-challenge/T4XE4bNn2nrblyobGQyqEsLY2GvcDUYeMPYfKl5neWw: -------------------------------------------------------------------------------- 1 | T4XE4bNn2nrblyobGQyqEsLY2GvcDUYeMPYfKl5neWw.NqTSciiSqnBus5ylE1wdT7QOgICWBgpA_OHhYIuyCxI -------------------------------------------------------------------------------- /.well-known/acme-challenge/WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0: -------------------------------------------------------------------------------- 1 | WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0.kURQ5HbILtRXEwJA2QI4W5TdBkjnZNqH2_RHORvmN6w -------------------------------------------------------------------------------- /.well-known/acme-challenge/_-SyF07cuWWE6OgqWRRq-QCWDfG2NOxqm_U5gT-7L8A: -------------------------------------------------------------------------------- 1 | _-SyF07cuWWE6OgqWRRq-QCWDfG2NOxqm_U5gT-7L8A.NqTSciiSqnBus5ylE1wdT7QOgICWBgpA_OHhYIuyCxI -------------------------------------------------------------------------------- /.well-known/acme-challenge/iTMP1u9ugjJG3m7xHpd7JNxF6EPREu--7jzK5qjVmxU: -------------------------------------------------------------------------------- 1 | iTMP1u9ugjJG3m7xHpd7JNxF6EPREu--7jzK5qjVmxU.NqTSciiSqnBus5ylE1wdT7QOgICWBgpA_OHhYIuyCxI -------------------------------------------------------------------------------- /.well-known/acme-challenge/qN0VkWVSSAqFmDkV90s_gZKkFYXbmbXG53nbfVeeXqE: -------------------------------------------------------------------------------- 1 | qN0VkWVSSAqFmDkV90s_gZKkFYXbmbXG53nbfVeeXqE.NqTSciiSqnBus5ylE1wdT7QOgICWBgpA_OHhYIuyCxI -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | .DS_Store 17 | apps.txt 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "learn-heroku", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "http-server": "^0.9.0", 6 | "live-server": "^1.2.0" 7 | }, 8 | "engines": { 9 | "node": "6.10.x" 10 | }, 11 | "scripts": { 12 | "start": "node node_modules/.bin/http-server", 13 | "local": "node_modules/.bin/live-server --port=8080" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Learn Heroku - Hello World! 6 | 7 | 8 |

Hello World!

9 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /update_stack.py: -------------------------------------------------------------------------------- 1 | # update the stack of your heroku apps. github.com/dwyl/learn-heroku/issues/43 2 | import os 3 | 4 | os.system("echo Fetching List of Apps from Heroku") 5 | os.system('heroku apps:table --filter="STACK=cedar-14" >> apps.txt') 6 | file = open('apps.txt', 'r') 7 | Lines = file.readlines() 8 | 9 | # Strips the newline character 10 | for line in Lines: 11 | parts = line.split(" ") 12 | app = parts[0].strip() 13 | print("updating: " + app) 14 | os.system("heroku stack:set heroku-18 -a " + app) 15 | 16 | import sys 17 | sys.exit() 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn (How to Deploy a Web Application on) Heroku 2 | 3 | ![heroku logo](https://cdn.worldvectorlogo.com/logos/heroku-1.svg) 4 | 5 | ## Why? 6 | 7 | You know how to _create_ a web application, 8 | but that knowledge is only _useful_ 9 | if you know how to _show_ the app to people! 10 | 11 | ## What? 12 | 13 | Easily deploy your node.js web application to Heroku 14 | so you can start testing it with end-users as soon as possible! 15 | 16 | You'll have a _public_ URL for your app in 5 minutes which you can share 17 | with real people and get feedback/validation for your idea! 18 | 19 | ### "Top 7" Key Benefits: 20 | 21 | + Basic apps are ***Free***!! (_e.g. Demo, Hackathon or "Low Traffic" 22 | Personal "Blog" or Portfolio site_) 23 | 24 | + _***Quick and Easy Deployment***_ from your development machine or GitHub! 25 | A couple of clicks or a single command is all it takes! 26 | 27 | + Excellent **knowledge base** / documentation for 28 | both simple and advanced topics! 29 | (_if you get stuck, 30 | [**ask a question**](https://github.com/dwyl/learn-heroku/issues) 31 | we can/will help!_) 32 | 33 | + ***Continuous Deployment*** is easy from a GitHub repository using "Hooks". 34 | (_see step-by-step tutorial below!_) 35 | 36 | + Great Range of "**Addon Services**" you can use with your app 37 | in a couple of clicks (_e.g: PostgreSQL, ElasticSearch, Monitoring etc._)
38 | and most have a "free tier" 39 | so you can get started without spending a penny! 40 | See: https://elements.heroku.com/addons 41 | 42 | + "_Industry Standard_" ***Service Quality*** is _really_ good 43 | (_under the hood Heroku uses Amazon Web Services 44 | but they do all the "plumbing" so you don't have to waste time on "DevOps" 45 | until you're ready to scale, at which point just pay for a pro!_) 46 | 47 | + **Cost-effective** for your ***first 10k users*** 48 | (_don't waste your time on "DevOps" till you have validated your App Idea 49 | with real people!_) 50 | 51 | 52 | ## Who? 53 | 54 | _Anyone_ building for the web who values their _time_ and wants/needs 55 | a _painless_ way to ***deploy, monitor and automatically scale*** 56 | an app! 57 | 58 | 59 | ## How? 60 | 61 | ### Beginner: Basic Heroku Deployment of Node.JS App in 5 Minutes 62 | 63 | #### Pre-requisites: 64 | + **Computer** with a ***Web Browser*** 65 | + **Internet Connection** 66 | + ***GitHub Account*** ... if you don't have one see: 67 | [github.com/dwyl/github-reference#how-to-**sign-up**](https://github.com/dwyl/github-reference#how-to-sign-up) 68 | + Heroku account ... if you don't have one, sign up now: https://signup.heroku.com (_it's free! and **no credit card required**!_) 69 | 70 | #### No Experience/Knoweldge Required 71 | + No Node.js or other knowledge required 72 | + All web-based (_no command line, we can learn that "CLI" later!_) 73 | 74 | #### 1. Fork this repository on GitHub! 75 | 76 | In your web browser navigate to: 77 | [github.com/dwyl/**learn-heroku**](https://github.com/dwyl/learn-heroku) 78 | (_if you aren't already on the page_) 79 | 80 | After you have starred the repository, 81 | click the "fork" button:
82 | ![learn-heroku-fork-button](https://cloud.githubusercontent.com/assets/194400/23248016/267e77b2-f995-11e6-9748-0ef7dc69c22a.png) 83 | 84 | You should now see something similar to this: 85 | ![image](https://cloud.githubusercontent.com/assets/194400/23248074/6e0b7404-f995-11e6-9261-7b8a21f44ab5.png) 86 |
(_with your GitHub username in place of mine_) 87 | 88 | 89 | #### 2. Log into your Heroku Account and Create a New App 90 | 91 | > **Note**: if you don't already have a Heroku account set one up now! 92 | 93 | Visit: https://dashboard.heroku.com/new and create your new app.
94 | _example_:
95 | ![create-new-app](https://cloud.githubusercontent.com/assets/194400/23212611/6881bd72-f8ff-11e6-8c00-6ddf4c97c3ef.png)
96 | (_you will need to give your app a **different name**; 97 | all heroku apps are **unique**._) 98 | 99 | 100 | #### 3. Use Heroku (Web) UI to Deploy the Application 101 | 102 | Once you create your app in Heroku you will be shown the "***Deploy***" screen: 103 | 104 | ![learn-heroku-deployment](https://cloud.githubusercontent.com/assets/194400/23248304/97afbf26-f996-11e6-9858-a7c5aea594ef.png) 105 | 106 | Connect your Heroku app to the GitHub Repository you created (_by forking_) 107 | in step 1 (_above_). 108 | 109 | ##### Steps: 110 | 111 | + Click on the "Connect to GitHub" button 112 | + Search for the repository `learn-heroku` in our case 113 | + Click on "Connect" button. 114 | 115 | Now click "**Enable Automatic Deploys**" to ensure that 116 | any changes made on GitHub are automatically deployed on Heroku: 117 | 118 | ![enable-automatic-deploys](https://cloud.githubusercontent.com/assets/194400/23248376/fcb091ac-f996-11e6-8b84-8433d6915d4d.png) 119 | 120 | #### 4. Test The Deployment Works by Updating a File in the Forked Repo 121 | 122 | Back in GitHub, use the Web user interface (UI) to edit one of the files 123 | in your fork of `learn-heroku`. 124 | 125 | My suggestion is update (_increment_) the version number 126 | in the `package.json` file: 127 | 128 | Click the edit icon:
129 | ![edit-package-json-button](https://cloud.githubusercontent.com/assets/194400/23248743/e4e94cd8-f998-11e6-98ba-eb6d78ec634f.png) 130 | 131 | In the edit view, increment the version number: 132 | ![edit-version-number](https://cloud.githubusercontent.com/assets/194400/23248804/3f63f76c-f999-11e6-92bc-02ea7c2863ad.png) 133 | 134 | Now scroll down to the **Commit changes** section of the edit view: 135 | 136 | ![learn-heroku-commit-changes](https://cloud.githubusercontent.com/assets/194400/23248896/9afcfdee-f999-11e6-96ad-9a53aa0d8e2d.png) 137 | 138 | write a descriptive commit message and click the "**Commit changes**" button. 139 | 140 | > Note: we typically don't encourage people to `commit` directly to `master` 141 | but given that this is your personal fork you can do it this one time. 142 | 143 | You should see something like this: 144 | ![learn-heroku-changes-committed](https://cloud.githubusercontent.com/assets/194400/23248968/e9788bd2-f999-11e6-9c14-205c9ad00ee7.png) 145 | 146 | That will trigger the Heroku deployment of the Hello World Application! 147 | 148 | #### 5. Visit the Heroku App in your Web Browser 149 | 150 | > In my case the URL for my app is: https://hello-world-heroku-node.herokuapp.com 151 | 152 | You should expect to see:
153 | ![learn-heroku-hello-world](https://cloud.githubusercontent.com/assets/194400/23319783/edd7954c-facf-11e6-9059-0862a69e1fd3.png) 154 | 155 | ### Congratulations! You just _deployed_ your first app on Heroku! 156 | 157 | 158 |


159 | 160 | ### Intermediate: Detailed Step-by-Step Instructions a "Real" App 161 | 162 | See: [elixir-phoenix-app-deployment.md](https://github.com/dwyl/learn-heroku/blob/master/elixir-phoenix-app-deployment.md) 163 | 164 | ### Intermediate: Environment Variables on Heroku 165 | 166 | See: [github.com/dwyl/learn-environment-variables#**environment-variables-on-heroku**](https://github.com/dwyl/learn-environment-variables#environment-variables-on-heroku) 167 | 168 | ### Intermediate: Using a Custom Domain Name on Heroku 169 | 170 | To use a custom domain name on your heroku app, the first thing to do is to purchase your domain name. There are a number of services you can use for this (we like [iwantmyname.com](https://iwantmyname.com)). 171 | 172 | The next step is to add this domain to your heroku app. You can do this using the command line interface, or the settings dashboard on heroku.com. 173 | 174 | heroku dashboard - domains and certificates 175 | 176 | Once you've added your domain, you should see a DNS target: 177 | 178 | heroku - dns target 179 | 180 | This is what you need to give to your DNS provider (which is most likely the site you purchased your domain from). 181 | 182 | If your domain starts with `www.`, you will need to add the DNS target as a `CNAME` record with a name of `www` 183 | 184 | If your domain just consists of the domain name and the top level domain (eg. `github.com` instead of `www.github.com`; This is known as the root domain), you might be able to add it as a `CNAME`, but will most likely need to add it as an `ANAME` or an `ALIAS` record. In this case, either leave the name blank, or use `@` 185 | 186 | Some services will not allow you to add the root domain as a `CNAME`, and will not have `ANAME` or `ALIAS` as an option, instead requiring you to give an IP address as the `A` record. This is not possible with heroku, as they use dynamic IP addresses, meaning they will change regularly and your DNS record will no longer be correct. 187 | 188 | However, if you still want people to be able to access your site using the root domain, there are still a few things you can do. 189 | 190 | Some services (iwantmyname.com included) have a feature where they will automatically configure DNS records for popular web services (tumblr, squarespace, heroku etc.). 191 | 192 | Another alternative is to just add the `www` DNS record, and to add a redirect (it may also be known as forwarding) from your root domain to that. This does mean that the `www` will show in the browser address bar, but both addresses will lead to your site. 193 | 194 | See the [heroku docs](https://devcenter.heroku.com/articles/custom-domains) or your DNS providers help page for specific instructions. 195 | 196 | 210 | 211 | ## Background Reading 212 | 213 | - https://devcenter.heroku.com/articles/getting-started-with-nodejs 214 | - http://build-podcast.com/heroku 215 | 216 | ## Frequently Asked/Ansered Questions (FAQ) 217 | 218 | ### Isn't Heroku "_Expensive_" for the CPU/RAM You're Getting? 219 | 220 | Heroku costs more per unit of computing resource than the equivalent 221 | _infrastructure_ provider 222 | (_e.g: AWS / DigitalOcean / GoogleCloud / Azure / etc._) 223 | but it's _cheap_ if you factor ***developer's time*** 224 | as your **biggest cost/constraint**!
225 | Setting up deployment to AWS with all the benefits/features Heroku has 226 | out-of-the-box will take _hours_. So unless your developer's time is _free_ 227 | _or_ you _are_ the developer and want to spend a day on deployment 228 | instead of building features to solve the end-user's problem, 229 | use Heroku and focus on _building_ the product!
230 | See: https://github.com/dwyl/learn-heroku/issues/3 231 | -------------------------------------------------------------------------------- /elixir-phoenix-app-deployment.md: -------------------------------------------------------------------------------- 1 | # Deploying an Elixir/Phoenix App to Heroku 2 | 3 | ![heroku-phoenix-logo](https://user-images.githubusercontent.com/194400/36444274-ecc44e10-1672-11e8-818d-e638e9ff459e.png) 4 | 5 | 6 | ## Why? 7 | 8 | You want to deploy your Web Application with Database to Heroku 9 | as _fast_ as possible while still _understanding_ all the steps! 10 | 11 | 12 | ## What? 13 | 14 | A _step-by-step_ guide to deploying a (Phoenix) Web App on Heroku. 15 | 16 | We _created_ this walkthrough/tutorial while _deploying_ our 17 | "beginner phoenix example": 18 | https://github.com/dwyl/phoenix-chat-example
19 | So we _know_ it works! Try it: https://phxchat.herokuapp.com 20 | 21 | > _**Note**: most of this is applicable to **any** App_ 22 | (_Node.js, Python, Ruby, etc._)
23 | > Even if you are deploying a totally different Language/Framework, 24 | it's still worth "_skimming_". 25 | 26 | ## Who? 27 | 28 | _Anyone_ who wants a _quick, easy and "**free**"_ 29 | way to _deploy_ a demo app! 30 | 31 | 32 | ## _How_? 33 | 34 | _First_, let's do the setup on Heroku: 35 | 36 | ### 1. _Create_ a New App 37 | 38 | Once you have logged into your Heroku account 39 | and are viewing your "dashboard": https://dashboard.heroku.com 40 | 41 | 1.1 Click on the `New` button, then
42 | 1.2 Click on `Create new app`: 43 | 44 | ![heroku-create-app](https://user-images.githubusercontent.com/194400/36428249-575cf816-1647-11e8-9005-0ea5219a039c.png) 45 | 46 | ### 2. Give Your New App a _Name_ 47 | 48 | Input your desired name 49 | (_if it's available; otherwise get **creative**!_):
50 | ![heroku-new-app-name-defaults](https://user-images.githubusercontent.com/194400/36433381-44f30258-1654-11e8-8af8-a3e262a28573.png)
51 | In this case we are creating an App called `phxchat`. 52 | (_short for `Phoenix Chat`, 53 | because **obviously** `phoenixchat` is "taken"..._) 54 | 55 | Leave the rest of the options to the "default" options 56 | (_unless you have specific needs_). 57 | 58 | > _**Note**: don't worry about the "Add to pipeline" option for now, 59 | we will come back to it later_. 60 | 61 | Click on the `Create app` button. 62 | 63 | You will be directed to the "Deploy" tab for your app:
64 | ![heroku-phx-chat-dwploy-tab](https://user-images.githubusercontent.com/194400/36435297-31653eb8-1659-11e8-9ce7-2c47ad38471c.png) 65 | 66 | ### 3. Create "Deployment Pipeline" 67 | 68 | On the "Deploy" tab of your app, scroll down 69 | till you see the "Deployment Method" section: 70 | 71 | ![heroku-deploy-connect-to-github-connect](https://user-images.githubusercontent.com/194400/36437399-c76b9664-165e-11e8-99a6-4e72756705ae.png) 72 | 73 | 1. Click on "GitHub" 74 | 2. Select the "Owner" of the App you want to deploy 75 | (_usually your own GitHub username_) 76 | 3. Type (_or copy-paste_) the name of your App. 77 | 4. Click `Search` to find the repo. 78 | 5. Click "Connect" button. 79 | 80 | You should see:
81 | ![heroku-app-connected](https://user-images.githubusercontent.com/194400/36438050-97d7c132-1660-11e8-979b-0846fcacc9bc.png) 82 | 83 | 84 | ### 4. Add the PostgreSQL Database "Add-on" 85 | 86 | Given that our Phoenix App uses a Postgres database to store it's data, 87 | let's add it as an "Add-on". 88 | 89 | Scroll to the top of the dashboard and click on the "Resources" tab: 90 | 91 | ![click-on-resources-tab](https://user-images.githubusercontent.com/194400/36438338-83dc0b06-1661-11e8-89a0-3268638a4c34.png) 92 | 93 | On the "Resources" page, scroll down till you See "Add-ons" 94 | 95 | ![heroku-addons-select-postgres](https://user-images.githubusercontent.com/194400/36438438-d6bcd350-1661-11e8-89fe-b0b5889c8f93.png) 96 | 97 | 1. Type: "post" (_in the add-on search input box_) 98 | 2. Select "Heroku Postgres" from the list. 99 | 100 | This will open a "Modal" for you to _confirm_:
101 | ![heroku-postgres-select-default](https://user-images.githubusercontent.com/194400/36438710-9ae7b2ea-1662-11e8-829b-c1ee854b54d5.png) 102 | 103 | Leave the _default_ "Hobby Dev - Free" 104 | and _click_ the "**Provision**" button. 105 | 106 | You should now see (_something similar to_) the following:
107 | ![heroku-addon-installed](https://user-images.githubusercontent.com/194400/36438893-21945f00-1663-11e8-87a4-62baa1f56e95.png) 108 | 109 | 110 | ### 5. Create a `elixir_buildpack.config` File 111 | 112 | In the root directory of the App you are trying to deploy, 113 | create a file called `elixir_buildpack.config` 114 | 115 | _Paste_ the following lines into the file: 116 | 117 | ```yml 118 | # Latest version of Erlang/OTP see: https://git.io/Je5k6 119 | erlang_version=22.2 120 | 121 | # Latest Elixir Version see: https://github.com/elixir-lang/elixir/releases 122 | elixir_version=1.9.4 123 | 124 | # Always rebuild from scratch on every deploy? 125 | always_rebuild=false 126 | 127 | # Set the path the app is run from 128 | runtime_path=/app 129 | ``` 130 | 131 | This file overrides the default options defined 132 | by adding the buildpack in **Step 9** (_below_). 133 | For more detail on the configuration options 134 | for your `elixir_buildpack.config` file 135 | see: 136 | https://github.com/HashNuke/heroku-buildpack-elixir#configuration 137 | 138 | 139 | ### 6. Create a `Procfile` File 140 | 141 | Also in the root directory of your App, 142 | create a file called `Procfile` 143 | 144 | _Paste_ this line in the file: 145 | 146 | ```sh 147 | web: MIX_ENV=prod mix ecto.migrate && mix phx.server 148 | ``` 149 | That will ensure that your database tables/schema is up-to-date 150 | _before_ trying to launch the app. 151 | 152 | 153 | ### 7. Update Your `prod.exs` File 154 | 155 | This section "_borrows liberally_" from: 156 | https://hexdocs.pm/phoenix/heroku.html#making-our-project-ready-for-heroku 157 | 158 | #### 7.1 Configure the `Endpoint` Section 159 | 160 | The default looks something like this: 161 | ```elixir 162 | config :chat, ChatWeb.Endpoint, 163 | load_from_system_env: true, 164 | url: [host: "example.com", port: 80], 165 | cache_static_manifest: "priv/static/cache_manifest.json" 166 | ``` 167 | 168 | Update the following params: `url`, `force_ssl` and `secret_key_base`: 169 | ```elixir 170 | config :chat, ChatWeb.Endpoint, 171 | load_from_system_env: true, 172 | url: [scheme: "https", host: "phxchat.herokuapp.com", port: 443], 173 | force_ssl: [rewrite_on: [:x_forwarded_proto]], 174 | cache_static_manifest: "priv/static/cache_manifest.json", 175 | secret_key_base: Map.fetch!(System.get_env(), "SECRET_KEY_BASE") 176 | ``` 177 | Where: 178 | + The first line remains the same (_dependent on the name of your app_) 179 | + The `url` should be your heroku app name (_in our case `phxchat`_) 180 | 181 | 182 | #### 7.2 Create a `Repo` Section 183 | 184 | By default `prod.exs` does _not_ have a `Repo` section, 185 | so we need to _create_ one. Here's a "template" 186 | 187 | ```elixir 188 | # Configure your database 189 | config :hello, Hello.Repo, 190 | adapter: Ecto.Adapters.Postgres, 191 | url: System.get_env("DATABASE_URL"), 192 | pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), 193 | ssl: true 194 | ``` 195 | 196 | The one for our "chat" application is:
197 | ```elixir 198 | # Configure your database 199 | config :chat, Chat.Repo, 200 | adapter: Ecto.Adapters.Postgres, 201 | url: System.get_env("DATABASE_URL"), 202 | pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), 203 | ssl: true 204 | ``` 205 | All that changes is the _first_ line which is the name of your app. 206 | 207 | 208 | #### 7.3 Comment out Last Line in `prod.exs` 209 | 210 | Given that we are storing our "secrets" as Environment Variables on Heroku. 211 | We can _safely_ comment out the line in `prod.exs`: 212 | 213 | ```elixir 214 | import_config "prod.secret.exs" 215 | ``` 216 | becomes: 217 | 218 | ```elixir 219 | # import_config "prod.secret.exs" 220 | ``` 221 | 222 | ### 8. Generate the `SECRET_KEY_BASE` String 223 | 224 | The `SECRET_KEY_BASE` is the key that your app will use to 225 | digitally sign request tokens. It's vital to keep it a _secret_ 226 | to avoid "_compromising_" your app. 227 | Therefore we will store it in an Environment Variable on Heroku. 228 | 229 | #### 8.1 Run the `mix phx.gen.secret` Command 230 | 231 | On your `localhost` (_terminal_), run the following command: 232 | ```sh 233 | mix phx.gen.secret 234 | ``` 235 | That will output a **64 character** String such as: 236 | ``` 237 | khaO4IJvSa+AFJHGFzlsgVlOuNNLgrUg9D4PCD943tKqersy3YNtABh/zmqd/v7y 238 | ``` 239 | _Copy_ that string to your clipboard. 240 | (_we will use it in the next step_) 241 | 242 | #### 8.2 Define the `SECRET_KEY_BASE` Environment Variable on Heroku 243 | 244 | > _**Note**: if you are `new` to Environment Variables, 245 | we recommend you read our "**complete beginner**" **tutorial**_: 246 | [github.com/dwyl/**learn-environment-variables**](https://github.com/dwyl/learn-environment-variables) 247 | 248 | Open the "Settings" Tab of your App's Heroku Dashboard: 249 | ![heroku-settings-tab](https://user-images.githubusercontent.com/194400/36446677-fe75289e-1679-11e8-9ec0-d5fe28cca26a.png) 250 | 251 | Now _scroll_ down to the "Config Variables" 252 | and click on the "***Reveal Config Vars***" button: 253 | 254 | ![heroku-reveal-config-variables](https://user-images.githubusercontent.com/194400/36446776-48e847bc-167a-11e8-9118-43c06b65dde8.png) 255 | 256 | This will display your _existing_ variable `DATABASE_URL` 257 | and allow the creation of new Environment Variables. 258 | 259 | ![heroku-add-secret_key_base-config-var](https://user-images.githubusercontent.com/194400/36446972-dfc41e4a-167a-11e8-82cf-509f9fc53632.png) 260 | 261 | 1. **Set** the "key" for the variable: `SECRET_KEY_BASE` 262 | 2. **Paste** the value generated in step 8.1 (_above_) 263 | 3. **Click** the "Add" button 264 | 265 | 266 | ### 9. Add the Elixir "Buildpack" 267 | 268 | Still in the "Settings" Tab of the Heroku Dashboard for the App, 269 | Scroll down to the "**Buildpacks**" section: 270 | 271 | ![heroku-add-buildpacks](https://user-images.githubusercontent.com/194400/36447145-63574cc8-167b-11e8-8671-db1b6f208669.png) 272 | 273 | Click on the "Add buildpack" button. 274 | 275 | > A "Buildpack" tells Heroku _how_ to run your app. 276 | > In the case of an elixir app it defines how to get the dependencies 277 | and what the app expects/requires.
278 | For more detail, see: https://devcenter.heroku.com/articles/buildpacks 279 | 280 | When the "Modal" opens: 281 | 282 | ![heroku-add-elixir-buildpack](https://user-images.githubusercontent.com/194400/36447345-098f6fb2-167c-11e8-8413-61c7b1164fc5.png) 283 | 284 | 1. Paste the value: 285 | https://github.com/HashNuke/heroku-buildpack-elixir.git 286 | into the field. 287 | 2. Click on "Save change" button 288 | 289 | You should now see the following: 290 | 291 | ![heroku-buildpack-added](https://user-images.githubusercontent.com/194400/36447410-41416f78-167c-11e8-86c3-57f7f7c86195.png) 292 | 293 | #### 9.1 _Repeat_ 294 | 295 | In order to compile any "_static assets_" (JS/etc.) 296 | we need to add a _second_ buildpack: 297 | https://github.com/gjaldon/heroku-buildpack-phoenix-static.git 298 | 299 | Repeat the process you just went through but this time 300 | add the `heroku-buildpack-phoenix-static` buildpack. 301 | 302 | Great! Now onto the _final_ step! 303 | 304 | ### 10. (_Manually_) Deploy 305 | 306 | > _Don't worry_, you only have to do this _once_.
307 | All _subsequent_ deploys are automatic! 308 | 309 | Back on the "Deploy" tap of your App's Dashboard, 310 | Scroll down to the "Manual deploy" section: 311 | 312 | ![heroku-manual-deploy](https://user-images.githubusercontent.com/194400/36447781-5229282a-167d-11e8-956b-aed5acc9c15f.png) 313 | 314 | Click on the "**Deploy Branch**" button. 315 | 316 | This will _start_ the build process. 317 | Heroku will show you the "build log": 318 | 319 | ![heroku-build-log](https://user-images.githubusercontent.com/194400/36447871-9b051252-167d-11e8-8c18-c04e6deac7d4.png) 320 | 321 | Once the build is complete, 322 | click on the "Open App" button in the top-right of your Heroku dashboard: 323 | ![open-app](https://user-images.githubusercontent.com/194400/36480033-bb4bbff4-1702-11e8-8b78-76c97518702a.png) 324 | 325 | You should see _your_ app running in the browser! 326 | 327 | In _our_ case the app is: https://phxchat.herokuapp.com 328 | ![phxchat](https://user-images.githubusercontent.com/194400/36480000-9c6fe768-1702-11e8-86d6-c8703883096c.png) 329 | 330 | `done()` 331 | 332 |

333 | 334 | 335 | ### Why _Not_ use the "Official" Deployment Guide? 336 | 337 | We are **aware** of (and have read) the 338 | "Deploying on Heroku" guide: 339 | https://hexdocs.pm/phoenix/heroku.html
340 | It's a _good_ guide for people with "intermediate" Heroku skills, 341 | however it's **longer** (more steps) than this tutorial, 342 | uses the Heroku "Toolbelt" (Command Line Interface "CLI"), 343 | which _most_ "beginners" _don't have_ installed 344 | and does not setup a "deployment pipeline" so it's a "manual" job 345 | (_running the deploy command each time_). 346 | 347 | With that said, it is a _good_ reference, so if you are stuck, 348 | that is a good place to look for "trouble-shooting". 349 | 350 | 351 | ## References & Background Reading 352 | 353 | + "Official" Heroku Deployment guide: https://hexdocs.pm/phoenix/heroku.html 354 | + Basic deployment: https://medium.com/@yasserhussain1110/how-to-deploy-phoenix-app-to-heroku-95d4bef32322 also uses Heroku CLI and doesn't setup a deployment pipeline. But good section on `config/prod.exs` changes. 355 | + Migrating a Phoenix App on Heroku: https://blog.learnphoenix.io/strategies-for-migrating-a-phoenix-app-on-heroku-ed0ea3aee4e5 _confirmed_ that `mix ecto.migrate` works in `Procfile`. (_Thanks @SamCorcos_) 356 | -------------------------------------------------------------------------------- /SSL-certificate-step-by-step-setup-instructions.md: -------------------------------------------------------------------------------- 1 | ![letsencrypt-760x320](https://cloud.githubusercontent.com/assets/194400/23311312/8c4cc85a-faad-11e6-912c-9cc96ec21da6.png) 2 | 3 | # Step-by-Step Setup Instructions for Let's Encrypt _Free_ SSL 4 | 5 | > _Note: These instructions are only applicable to web apps 6 | with a **custom domain** name_. 7 | 8 | 9 | ## Why? 10 | 11 | You have a custom domain for your Heroku app 12 | and now you want an SSL Certificate 13 | to Secure/Encrypt all communications between users and your app. 14 | 15 | ## What? 16 | 17 | Let's Encrypt offers a ***Free*** _Automated_ SSL Certificate Service 18 | brought to you by the **_non-profit_ 19 | Internet Security Research Group** (ISRG). 20 | see: https://letsencrypt.org/about/ 21 | 22 | ### Instructions Valid for Apps Written in _Any_ Language/Framework! 23 | 24 | The instructions in this tutorial/guide are applicable 25 | to an app written in ***any language or framework***. 26 | You will _temporarily_ deploy a Node.js `http-server` to your Heroku app 27 | which will allow Let's Encrypt to _verify_ that you "_own_" the app/domain. 28 | 29 | > _**Note**: No Node.js knowledge is assumed or required. You won't be 30 | writing a single line of JS code._ 31 | 32 | Once you have set up SSL you can deploy what ever kind of app you like. 33 | (_in our case the app is written in [Elixir/Phoenix!](https://github.com/dwyl/technology-stack/#the-pete-stack) ... 34 | node.js is just an easy way to get this working in a **generic** way._) 35 | 36 | ## How? 37 | 38 | "**certbot**" is the script that _automates_ the certificate creation process. 39 | 40 | ### Step 1: Clone this Repository to get the Setup Code 41 | 42 | ``` 43 | git clone https://github.com/dwyl/learn-heroku.git 44 | cd learn-heroku 45 | ``` 46 | 47 | ### Step 2: Set Git Remote 48 | 49 | Check what your _current_ `origin` remote is: 50 | ```sh 51 | git remote -v 52 | ``` 53 | ![git-remote](https://cloud.githubusercontent.com/assets/194400/23321003/400c1fa4-fad5-11e6-8e9b-0caf85963dd1.png) 54 | 55 | Set it to what ever the git url is for the app you are setting up SSL for. e.g: 56 | ```sh 57 | git remote set-url origin git@github.com:healthlocker/healthlocker.git 58 | ``` 59 | 60 | Push your current branch to the GitHub repo: 61 | ```sh 62 | git push --set-upstream origin letsencrypt-temporary-server 63 | ``` 64 | 65 | ### Step 3: _Temporarily_ Change the Branch Heroku Deploys from 66 | 67 | ![ssl1](https://cloud.githubusercontent.com/assets/194400/23256626/22f87da4-f9b8-11e6-96d1-72e50ebeffa4.png) 68 | 69 | Change it to the name of your branch e.g: 70 | 71 | ![ssl2](https://cloud.githubusercontent.com/assets/194400/23256625/22f75cee-f9b8-11e6-896f-296e353429be.png) 72 | 73 | It should look something like this: 74 | 75 | ![ssl-deploy-from-diff-branch-disable-ci-check](https://cloud.githubusercontent.com/assets/194400/23256955/7e62225c-f9b9-11e6-9ba0-74e5d2644f8a.png) 76 | remember to (_temporarily_) _dissable_ the checkbox `Wait for CI to 77 | pass before deploy`
78 | (_we have no tests for this temporary server!_). 79 | 80 | 81 | ### Step 4: Install `certbot` 82 | 83 | > `certbot` installation instructions for various platforms: 84 | https://letsencrypt.org/getting-started 85 | 86 | ```sh 87 | brew install certbot 88 | ``` 89 | ![bew-install-certbot](https://cloud.githubusercontent.com/assets/194400/23254553/59f014a0-f9b0-11e6-9667-4e5e9b8014bc.png) 90 | 91 | (_it might take a few minutes to install on a slower internet connection... 92 | be patient..._) 93 | 94 | ### Step 4: Run `certbot` Command (_Manual Setup_) 95 | 96 | Once you've installed `certbot` run the following command: 97 | ```sh 98 | sudo certbot certonly --manual 99 | ``` 100 | 101 | Remember to use both the domain a `www` subdomain. (_separated by a space_) e.g: 102 | 103 | ``` 104 | example.com www.example.com 105 | ``` 106 | 107 | Our app was: 108 | ``` 109 | healthlocker.uk www.healthlocker.uk 110 | ``` 111 | 112 | Follow the steps and **pay _close_ attention**! 113 | 114 | When you reach the screen that looks like this: 115 | 116 | ![certbot-instructions](https://cloud.githubusercontent.com/assets/194400/23255249/c7d2b250-f9b2-11e6-9d45-d2cdb965defa.png) 117 | 118 | _**DON'T** `continue` until you have completed **Step 5**_. 119 | 120 | Instructions printed by `certbot`: 121 | (_for reference ONLY see below for sub-set of instructions_) 122 | ``` 123 | mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge 124 | cd /tmp/certbot/public_html 125 | printf "%s" WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0.kURQ5HbILtRXEwJA2QI4W5TdBkjnZNqH2_RHORvmN6w > .well-known/acme-challenge/WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0 126 | 127 | # run only once per server: 128 | $(command -v python2 || command -v python2.7 || command -v python2.6) -c \ 129 | "import BaseHTTPServer, SimpleHTTPServer; \ 130 | s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \ 131 | s.serve_forever()" 132 | ``` 133 | 134 | You _wont_ be _able_ to run shell commands on a Heroku instance 135 | so we need to use a _temporary_ node.js server to achieve our objective. 136 | 137 | In your `current working directory` (_on your localhost_) 138 | run the following command to create the `.well-known/acme-challenge` directory: 139 | 140 | #### Step 4.1 Create the `.well-known/acme-challenge` Directory (_if it doesn't exist_) 141 | 142 | ``` 143 | mkdir -p .well-known/acme-challenge 144 | ``` 145 | 146 | #### Step 4.2 Create a File for the Token Verification 147 | 148 | Now ***copy-paste*** the `printf` command from the `certbot` instructions: 149 | they should look _something_ like this: 150 | 151 | ``` 152 | printf "%s" WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0.kURQ5HbILtRXEwJA2QI4W5TdBkjnZNqH2_RHORvmN6w > .well-known/acme-challenge/WgFpodyij_PDzkU0MZ3CzKCI05hjLOcq2tP-1rs6ko0 153 | ``` 154 | The tokens will be _specific_ to you so make sure you get the correct tokens. 155 | (_there is one token per domain_) 156 | 157 | #### Step 4.3: Commit Your Changes (_the token file_) and Push to GitHub 158 | 159 | Make a commit on your local branch so you can push to github 160 | (_and trigger the heroku build_) 161 | 162 | ``` 163 | git add . 164 | git commit -m 'add letsencrypt verification file' 165 | git push 166 | ``` 167 | That will deploy the file you created in Step 4.2 to Heroku. 168 | 169 | ### Step 5: Visit the Endpoint in your Browser to _Confirm_ it _Worked_: 170 | 171 | Visit your app in a web browser to confirm the deploy worked. 172 | e.g: http://example.com/.well-known/acme-challenge 173 | 174 | The url for _our_ app was: http://healthlocker.uk/.well-known/acme-challenge 175 | 176 | ![click-on-filename-to-test](https://cloud.githubusercontent.com/assets/194400/23293421/eda79e68-fa5d-11e6-95d4-a8c57fe4a8fd.png) 177 | 178 | It should _download_ a text file to your computer 179 | when you visit the endpoint in the browser. 180 | 181 | ### Step 6: Continue with the Certbot process 182 | 183 | Hit the enter key in the terminal window to `continue` the `certbot` process: 184 | 185 | ![certificate-success](https://cloud.githubusercontent.com/assets/194400/23293159/81c0b6d6-fa5c-11e6-96bb-68b5c18f0098.png) 186 | 187 | If if it worked, you should see something like that output in your terminal. 188 | If not scroll down to Trouble-Shooting section below 189 | 190 | ### Step 7: Conclude the process on Heroku 191 | 192 | You're _amost_ there, this is the _easy_ part! 193 | 194 | #### Step 7.1: `GOTO` Heroku "Settings" Tab and Click "***Configure SSL***" 195 | 196 | Navigate to the settings section of _your_ app on Heroku Dashboard e.g: 197 | 198 | ![navigate-to-the-settings-on-heroku](https://cloud.githubusercontent.com/assets/194400/23293535/880d2b1c-fa5e-11e6-8c56-106336bd899c.png) 199 | 200 | Scroll down to the "**Domains and certificates**" section 201 | and click on "***Configure SSL***" button: 202 | 203 | ![scroll-down-to-domains-and-certificates-section](https://cloud.githubusercontent.com/assets/194400/23293564/bcf94b94-fa5e-11e6-84a1-ad756cf46c62.png) 204 | 205 | #### Step 7.2: Click the link to _Paste_ the File Contntes 206 | 207 | Click on the link to paste the certificate:
208 | ![click-to-paste-the-contens](https://cloud.githubusercontent.com/assets/194400/23293840/6771a142-fa60-11e6-96b4-fded45e79550.png) 209 | 210 | #### Step 7.3: Copy the _Pulbic_ Certificate from your Machine 211 | 212 | Recall from above that the certificate generated by `certbot` 213 | was saved to `/etc/letsencrypt/live/healthlocker.uk/` (_your domain will be different_) 214 | 215 | You can _copy_ the contents of the file (_without "leaking" it_) 216 | by running the following command in your terminal: 217 | 218 | ``` 219 | sudo cat /etc/letsencrypt/live/healthlocker.uk/fullchain.pem | pbcopy 220 | ``` 221 | > Note: `sudo` is required because the `certbot` runs as admin
222 | for explanation of the `pbcopy` command see:
http://superuser.com/questions/113529/how-can-i-load-a-files-contents-into-the-clipboard 223 | 224 | #### Step 7.4: _Paste_ the _Pulbic_ Certificate 225 | 226 | Paste the `Public` Key (`cert.pem` _you copied above_) 227 | into the `