How to host lightweight apps for free
Tags: programming, heroku, cloudcomputing, coding
Published: 2017-09-23 22:01:07

---
title: "How to host lightweight apps for free"
published: true
tags: programming,heroku,cloud-computing,coding
canonical_url: https://medium.freecodecamp.com/how-to-host-lightweight-apps-for-free-a29773e5f39e
cover_image: https://cdn-images-1.medium.com/max/1024/1*m8zEyzBZkPlhZlNZ-w1gaw.jpeg
description: This article is a simple but meaningful “walk before you can run guide on how to get started with hosting your scripts on cloud servers.
---

When you look for web hosting services, there are many free options available. But there aren’t that many places where you can host full stack web apps that involve APIs, CGI, or AJAX backend queriesâ€Š–â€Šespecially if you want to use something other than PHP.

This article is a simple but meaningful “walk before you can run guide on how to get started with hosting your scripts on cloud servers.

### **When to use a Cloud Application Platform**

Cloud Application Platforms work well in scenarios where you need a bit of code to run on a server. Many of these platforms offer a series of Linux-based application containers (that appear like virtual machines) where you deploy the code you developed on your local computer with a set of command line keywords.

Heroku is one such service you could use to host your code (in various languages) relatively easily. It offers a freemium model where they let you use about 500 hours of computing for free (their full pricing is [here](https://www.heroku.com/pricing)).

![](https://cdn-images-1.medium.com/max/1024/1*5r9A_yT2n4zTeBVXAJRD_w.png)<figcaption>As of May 2017, the programming languages you can host underÂ Heroku</figcaption>

Once you’ve written your code on your local desktop, you can execute commands that deploy the code onto a workspace in Heroku. The code then executes depending on a trigger. Triggers can be a scheduled job, a web server which is triggered through a web page request, or something that is running constantly and processing dataâ€Š–â€Šwhich could get quite expensive.

What’s really nice is that you don’t have to worry about the operating system (memory, storage, CPU, security patches) as that is all managed for youâ€Š–â€Šbut at the same time it means that you do have limited flexibility since you cannot allocate resources directly.

Some specific examples where Heroku can work nicely for you:

- Hosting your own website where you want to write your own web server
- Periodically scraping data from a website and then storing it on a database for analysis
- Offering an API server for a specific task. Things like offering weather data, storing Internet of Things sensor data, or a web service call for a machine learning model
- A database service (although a service such as Firebase is possibly better suited)

### **Heroku Architecture**

Heroku provides a lightweight virtual machine (VM) for you to deploy your code. Note that under the free option, you can deploy up to 5 applications that are considered as 5 lightweight VMs. For your actual application, you are provided a separate URL subdomain under Heroku. So your project names need to be unique.

These workspaces have their own space for components such as: code and resource files (not dynamic data files), database (Postgres), and log files.

On your local desktop, Heroku uses your directory name to define your project, and also for Heroku to understand your context. So you can have multiple projects in different directories and when you run the Heroku commandsâ€Š–â€Šjust make sure you do so in the right folder.

The one key thing that you do need to be aware of (which I discovered the hard way through hours of debuggingâ€Š–â€ŠI wish I paid more attention to the documentation) is that everything is run from memory. There is no persistent storage. I’ll say it againâ€Š–â€Šyou cannot store any files on the file server! For persistence, Heroku offers a postgress SQL database where you can add records as required.

### **A simple exampleâ€Š–â€Šwebsite change detection**

Here’s a step-by-step guide to get a working example of a simple service that will email you if a website has changedâ€Š–â€Šbasically a clone of [www.changedetection.com.](http://www.changedetection.com.) There will be several key components of this:

1. A database that will store: (a) the email address to notify of a changed website; (b) the website to track; (c) the last â€˜copy’ of the website
2. A piece of code that will check a given website from the database in #1 (Python script)
3. A job scheduler that will run the program in #2 (equivalent of a cron job)
4. A web user interface where you can add/delete websites to monitor into the database mentioned in #1
5. A mechanism to send out emails

Understanding these components will arm you with the skills to do a lot of things already. I learned all of these things through multiple sources, so this acts as a consolidated post.

### **Assumptions**

The following guide makes the following assumptions:

- You have a GitHub accountâ€Š–â€Šif you don’t, please create one [here](https://github.com/). You should also read this simple [guide](http://readwrite.com/2013/09/30/understanding-github-a-journey-for-beginners-part-1/).
- You already have a Heroku accountâ€Š–â€Šif you don’t please create one [here](http://www.heroku.com).
- You are running a Windows machineâ€Š–â€Šif not, it is fine, the instructions are quite similar in other environments
- You already have Python installedâ€Š–â€Šif you don’t, please go [here](https://www.continuum.io/downloads) to install it
- You can already program in Pythonâ€Š–â€Šif not, then I’d suggest you learn some of the basics first. Some guides are [here](https://medium.mybridge.co/19-free-ebooks-to-learn-programming-with-python-8f6f0ad4a7f8).
- You know SQLâ€Š–â€Šif you don’t, please go [here](https://www.w3schools.com/sql/DEfaULT.asP).

### **Overview of the steps**

I find that going through a â€˜walk before you can run’ approach helps with the learning process. It also serves as documentation for yourself for how to solve each piece of the larger process. That way, if something breaks in your future endeavor, you have a better chance of figuring out where it went wrong.

**Step 1** : Develop the web user interfaceâ€Š–â€Šbuild Hello World first

**Step 2** : Persistenceâ€Š–â€Šcreate a database

**Step 3** : Check websites for changes

**Step 4:** Send an email notification on changes

**Step 5** : List the output on the web page

**Step 6: Deploy**

### **Step 1: Develop the web user interfaceâ€Š–â€Šbuild Hello World first**

First, let’s get a simple program deployed onto Heroku to get things started. This program will be a precursor to the web user interface (item #4) in the components list above. In order to serve up a page, we could simply have an HTML page, but then we would need to have a web server to server that file. In other words, when you type in the URL of the website, a program would need to interpret the request, then provide the contents of the HTML file. You can create your own mini web server with the Flask Python library, which is what we’ll do.

- Create a folder called webchecker and go into that directory (this directory name does not have to be the same as the Heroku application name)
- Install the Flask library. Enter the command: npm Flask
- Create the following Python program and name it showchecks.py:

```python
import os
from flask import Flask, request

app = Flask(__name__) #create an instance of the Flask library

@app.route('/hello') #whenever this webserver is called with <hostname:port>/hello then this section is called
def hello(): #The subroutine name that handles the call
	output = 'Hello World'
	return output #Whatever is returned from this subroutine is what is returned to the requester and is shown on the browser page

if __name__ == '__main__':
	port = int(os.environ.get('PORT', 5000)) #The port to be listening to – hence, the URL must be <hostname>:<port>/ inorder to send the request to this program
	app.run(host='0.0.0.0', port=port)  #Start listening
```

Before you deploy to Heroku, test that it works on your local PC. You can test it with the following steps:

- Run the program: python webchecker.com
- Open up your browser on your local pc and open up the page: [http://localhost:5000/hello](http://localhost:5000/hello)

![](https://cdn-images-1.medium.com/max/1024/1*GXR1TOFAk6wIUCm_mVTWLQ.png)<figcaption>Running the script will return a static page with â€˜hello world’Â output</figcaption>

Next, let’s deploy this to Heroku. Before you can deploy, there needs to be a few more files that need to be included to help Heroku know more about your application.

First, the requirements.txt

```
Flask==0.12
```

Second, the file to tell Heroku what to run when a webrequest is made:

```
web: python showchecks.py
```

Finally, the runtime version of Python to use (default is 2.7, but we want to specify the latest version of Python):

```
python-3.6.1
```

Hence, you should have four files:

1. showchecker.py which is the code
2. requirements.txt for the list of non-standard library dependencies. Whenever you have new libraries which are not part of the Python Standard Libraryâ€Š–â€Ši.e. you need to install them using a tool such as “pip”â€Š–â€Šthen add these here. You can find the version of an installed library such as Flask by running the command: pip show Flask in the command line
3. Procfile which is the actual Python script to run when the website is calledâ€Š–â€Šmake sure to update this if you change the Python file
4. runtime.txt which is the actual version of python to use

You can deploy with the following steps from the command line:

1. `heroku create webchecker01â€Š–â€Šbuildpack heroku/python`
2. `git add \*.\*\*`
3. `git status`
4. `git commit -m "all files"`
5. `git push heroku master`

![](https://cdn-images-1.medium.com/max/678/1*nLcnlwU1UocIvqbiHhviXQ.png)<figcaption>Once you run the “git push heroku master”, the deployment logs will be shown including the url where it isÂ deployed</figcaption>

For the command #1 (heroku create…), the “webechecker01 part is the unique name you’ll need to provide for the name of the app.

For command #3 (git status) this will tell you what files are ready to be deployed. Make sure all files are there, if not add them using git add \<filename\>.

Now you can check your website: \<application name\>.herokuapp.com/hello

![](https://cdn-images-1.medium.com/max/1024/1*tSMmTHoxgA2-xXQ0RaTrHg.png)<figcaption>The hello world program running on theÂ web</figcaption>

Let’s also make sure we can see the logs since this is a great way to see what’s going on with your app server. On your PC and in the webchecker directory, run the command: heroku logs

![](https://cdn-images-1.medium.com/max/1024/1*GQkthW50XPatw-J7fnrDlA.png)<figcaption>“heroku logs is a crucial command to run to see what’s going on within your appÂ server</figcaption>

You’ll see the last execution steps. If things aren’t working as expected, this is your first stop to find out more detail.

You can also go to the Heroku dashboard to see your consumption:

[https://dashboard.heroku.com](https://dashboard.heroku.com)

### **Step 2: Persistenceâ€Š–â€Šcreate a database**

In order to make more useful programs, you’ll need to have a data store of sorts. This is where the Postgres database service comes into play. You first need to deploy the Heroku database service, then create your tables, and finally be able to connect to the database from your code locally (for testing).

To deploy a database service, first create it using the following command:

heroku addons:create heroku-postgresql:hobby-dev

Next, access the database from the command line and create your tables. The database is created on the Heroku cloud service and not locally. However, you can access it through the command line. To log on to the database via the console, run the command heroku pg:psql. Remember, you have to do it in your webchecker folder so that Heroku knows that it is the database for the webchecker site.

To see the list of tables type the command \d

![](https://cdn-images-1.medium.com/max/1024/1*sctwYakzP69ePN-W50Rezw.png)

To create a table, you need to use normal SQL statements. For our webchecker program, let’s create a table with the following columns:

- IDâ€Š–â€Šautomatically generated ID for each entry (this will be the primary key). This is done by using the type “serial”
- websiteâ€Š–â€Šthe website to monitor
- emailaddressâ€Š–â€Šthe email address to send the notification that a change has occurred
- lasthashcodeâ€Š–â€Šwe won’t store a copy of the whole webpage, instead we will generate a hash based on the HTML of the page, and then compare this each time. This is more efficient storage-wise, but will not tell us what actually changed
- lastchangedateâ€Š–â€Šthe date that the web changed last time. Hence we will get the database to default this with the current date

To create this table, enter the following command in the Heroku Postgres database console:

```
CREATE TABLE webcheckerdb (id serial, website varchar(250), emailaddress varchar(250), lasthashcode varchar(32), lastchangedate timestamp DEFAULT current_date );
```

(Make sure you include the semicolon at the end!)

![](https://cdn-images-1.medium.com/max/1024/1*DJFH7kef_tDJhIse7sazWA.png)<figcaption>Creating the database, then using \d switch to see the list of tables and then “\d webecheckerdb to see theÂ columns</figcaption>

Next, let’s insert a single record in the database to ensure we have something to work with prior to getting our web UI up and running (you can use your own email address so it works in the future):

```
INSERT into webcheckerdb values(DEFAULT, 'news.google.com', 'email@me.com', '', DEFAULT);
```

(Make sure you include the semicolon at the end!)

![](https://cdn-images-1.medium.com/max/1024/1*lzafM9Y_USmlAaY-FPIjGw.png)<figcaption>You can then do a select statement (include the semicolon at the end!) to see theÂ data</figcaption>

You can quit with \q.

### **Step 3** : Check websites for changes

First, let’s get a piece of code to at least check if a hardcoded site can be retrieved (following on the concept of walking before running).

Hence, first step is to see if we can retrieve a webpage, hash it, and then compare it to a hardcoded hash. Create a new Python file called checkwebsite.py. Code here:

```python
import http.client
import hashlib
import pprint


def getCurrentWebsiteHash(weburl):
	httpConn = http.client.HTTPSConnection(weburl)
	httpConn.request('GET', weburl)

	resp = httpConn.getresponse()
	data = resp.read()

	hash_object = hashlib.md5( data )
	print(hash_object.hexdigest())

	return hash_object.hexdigest()

def getWebList():
	webRecordList = [ {'website':'www.google.com', 'lasthashcode':'xxx'} ]
	return webRecordList

def checkWebList(weblist):
	for webrecord in weblist:
		pprint.pprint(webrecord)
		currWebHash = getCurrentWebsiteHash( webrecord['website'])
		if currWebHash != webrecord['lasthashcode']:
			print( 'Website ' + webrecord['website'] + ' has changed ')

if __name__ == "__main__":
	weblist = getWebList()
	checkWebList( weblist )
```

Running this will output the following:

![](https://cdn-images-1.medium.com/max/1024/1*mnR-Yfax_dWTE3GeoffaaQ.png)

If you have any errors with missing libraries, you can add them via: pip install \<library\> from the command line.

Next, let’s connect to the database with the following code:

```python
import http.client
import hashlib
import psycopg2
from psycopg2.extras import RealDictCursor
import traceback
import urllib.parse
import pprint
import os

urllib.parse.uses_netloc.append("postgres")
url = urllib.parse.urlparse(os.environ["DATABASE_URL"])
dbConn = psycopg2.connect( database=url.path[1:], user=url.username, password=url.password, host=url.hostname, port=url.port)
dbCur = dbConn.cursor(cursor_factory=RealDictCursor)

def getCurrentWebsiteHash(weburl):
	print("getting url:"+ weburl)
	httpConn = http.client.HTTPSConnection(weburl)  #Create connection object
	httpConn.request('GET', weburl)	#Get the website

	resp = httpConn.getresponse()	
	data = resp.read()				#Get the webdata into a string object

	hash_object = hashlib.md5( data )	#Createa  hash code
	print(hash_object.hexdigest())		#print hash code

	return hash_object.hexdigest()

def getWebList():
	rows = []
	try:
		dbCur.execute("select * from webcheckerdb" )	#Get all records from database
		rows = dbCur.fetchall()
	except:
		print ("error during select: " + str(traceback.format_exc()) )
	return rows

def checkWebList(weblist):
	for webrecord in weblist:	#Loop through each record in database
		pprint.pprint(webrecord)
		currWebHash = getCurrentWebsiteHash( webrecord['website'])	#Get the current websites latest hash code
		if currWebHash != webrecord['lasthashcode']:				
			print( 'Website ' + webrecord['website'] + ' has changed ')
			try:
				#If there is a change, print out the change, but also update the database so that next time
				#the message wont get triggered again
				dbCur.execute("update webcheckerdb set lasthashcode ='" + str(currWebHash) + "' where id = '" + str(webrecord['id']) +"'" )
				dbConn.commit()
				print( 'Website hash updated for next time')
			except:
				print ("error during update: " + str(traceback.format_exc()) )

if __name__ == "__main__":
	weblist = getWebList()
	checkWebList( weblist )
```

When you try to run this code, you are likely going to get an error of the form KeyError: â€˜DATABASE\_URL’. This is because your Python code is trying to locate the web address of the Postgres database hosted on Heroku. This is automatically updated to the environment variable DATABASE\_URL in the Heroku server. However, on your local PC you will have to do this manually:

1. heroku config
2. set DATABASE\_URL=\<the database string listed from “heroku config”\>

![](https://cdn-images-1.medium.com/max/1024/1*Q4i73mFPaKPuDobdX9G_ZA.png)<figcaption>If you get the DATABASE_URL error, then set the environment variable</figcaption>

### Step 4: Send an email notification on changes

Final step is to send an email. To do this, you’ll need to install an Addon that has the ability to send emailsâ€Š–â€Šyou can find these via the Heroku marketplace: [https://elements.heroku.com/addons](https://elements.heroku.com/addons)

In here, there is an Addon called SendGrid: [https://elements.heroku.com/addons/sendgrid](https://elements.heroku.com/addons/sendgrid)

You can add SendGrid to your app in the command line by typing:

heroku addons:create sendgrid:starter

When you go to your dashboard you can see the new Addon in the Resources section:

![](https://cdn-images-1.medium.com/max/1024/1*c15ERSHkLS2tpByYFEJM1g.png)<figcaption>SendGrid addon that can enable sending emails will be at theÂ bottom</figcaption>

Before using it, you’ll need to create an API key. Double click the SendGrid component above and go into Settings-\>API Key-\>Create Key (blue button on top right).

![](https://cdn-images-1.medium.com/max/1024/1*DENX5_vY3u5ibFsMNW0Dug.png)<figcaption>Click on the Create Key button at topÂ right</figcaption>

Once you create the key, copy it and go back to the command prompt and enter:

heroku config:set SENDGRID\_API\_KEY=\<API key from above\>

This will only register it on the server, you need to add it locally to your desktop with:

set SENDGRID\_API\_KEY=\<API Key from above again\>

Once done, you can test your code in a new Python script called sendmail.py. Install the library via pip install sendgrid:

```python
import sendgrid
import os
from sendgrid.helpers.mail import *


def sendemail(recipient, emailSubject, body):
	sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY'))
	from_email = Email("heroku@myapp.com")
	to_email = Email(recipient)
	content = Content("text/plain", body)
	mail = Mail(from_email, emailSubject, to_email, content)
	response = sg.client.mail.send.post(request_body=mail.get())

	print("### Email sent to: "+ recipient + " ###")
	print(response.status_code)
	print(response.body)
	print(response.headers)

	

if __name__ == "__main__":
	sendemail('email@me.com', "hello world", "you have mail!")
```

To confirm the email was sent and delivered, you can go back to the SendGrid dashboard and checking the Statistics Overview screen:

![](https://cdn-images-1.medium.com/max/1024/1*i3v-OiFWlQhSEY_1y2VNoQ.png)

When checking your email, remember to check your spam.

Once it is working, there are only two lines of code you need to add to your main checkwebsite.py script. It is:

```
import sendmail #import the send email subroutine you wrote above

...

#call the subroutine after find the hashcode has changed
sendmail.sendemail(webrecord['emailaddress'], 'Website changed', webrecord['website'] + ' changed')
```

The full code is here:

```python
import http.client
import hashlib
import psycopg2
from psycopg2.extras import RealDictCursor
import traceback
import urllib.parse
import pprint
import os
import sendmail  #import the send email subroutine 

urllib.parse.uses_netloc.append("postgres")
url = urllib.parse.urlparse(os.environ["DATABASE_URL"])
dbConn = psycopg2.connect( database=url.path[1:], user=url.username, password=url.password, host=url.hostname, port=url.port)
dbCur = dbConn.cursor(cursor_factory=RealDictCursor)

def getCurrentWebsiteHash(weburl):
	print("getting url:"+ weburl)
	httpConn = http.client.HTTPSConnection(weburl)  #Create connection object
	httpConn.request('GET', weburl)	#Get the website

	resp = httpConn.getresponse()	
	data = resp.read()				#Get the webdata into a string object

	hash_object = hashlib.md5( data )	#Createa  hash code
	print(hash_object.hexdigest())		#print hash code

	return hash_object.hexdigest()

def getWebList():
	rows = []
	try:
		dbCur.execute("select * from webcheckerdb" )	#Get all records from database
		rows = dbCur.fetchall()
	except:
		print ("error during select: " + str(traceback.format_exc()) )
	return rows

def checkWebList(weblist):
	for webrecord in weblist:	#Loop through each record in database
		pprint.pprint(webrecord)
		currWebHash = getCurrentWebsiteHash( webrecord['website'])	#Get the current websites latest hash code
		if currWebHash != webrecord['lasthashcode']:		
			print( 'Website ' + webrecord['website'] + ' has changed email to ' + webrecord['emailaddress'])
			#call the subroutine after find the hashcode has changed
			sendmail.sendemail(webrecord['emailaddress'], 'Website changed',  webrecord['website'] + ' changed')
			try:
				#If there is a change, print out the change, but also update the database so that next time
				#the message wont get triggered again
				dbCur.execute("update webcheckerdb set lasthashcode ='" + str(currWebHash) + "' where id = '" + str(webrecord['id']) +"'" )
				dbConn.commit()
				print( 'Website hash updated for next time')
			except:
				print ("error during update: " + str(traceback.format_exc()) )

if __name__ == "__main__":
	weblist = getWebList()
	checkWebList( weblist )
```

### **Step 5** : List the output on the web page and schedule the job

The next step is to list the output on the webpage.

This involves querying the database, and then cycling through and showing the data on your screen. Hence, it takes the â€˜Hello World’ code above, and makes the modification. I also created a different path for this, so to test this out you’ll need to go to the URL: http://localhost:5000/list

```python
import os
from flask import Flask, request
import hashlib
import psycopg2
from psycopg2.extras import RealDictCursor
import traceback
import urllib.parse
import pprint 

app = Flask(__name__) #create an instance of the Flask library
urllib.parse.uses_netloc.append("postgres")
url = urllib.parse.urlparse(os.environ["DATABASE_URL"])
dbConn = psycopg2.connect( database=url.path[1:], user=url.username, password=url.password, host=url.hostname, port=url.port)
dbCur = dbConn.cursor(cursor_factory=RealDictCursor)


@app.route('/list') #whenever this webserver is called with <hostname:port>/hello then this section is called
def list(): #The subroutine name that handles the call
	output = 'Check status:'
	rows = []
	try:
		dbCur.execute("select * from webcheckerdb" )	#Get all records from database
		rows = dbCur.fetchall()
		for webrecord in rows:	#Loop through each record in database
			output = output + '<BR> ' + pprint.pformat(webrecord)
	except:
		output = "error during select: " + str(traceback.format_exc())

	return output #Whatever is returned from this subroutine is what is returned to the requester and is shown on the browser page


@app.route('/hello') #whenever this webserver is called with <hostname:port>/hello then this section is called
def hello(): #The subroutine name that handles the call
	output = 'Hello World'
	return output #Whatever is returned from this subroutine is what is returned to the requester and is shown on the browser page

if __name__ == '__main__':
	port = int(os.environ.get('PORT', 5000)) #The port to be listening to – hence, the URL must be <hostname>:<port>/ inorder to send the request to this program
	app.run(host='0.0.0.0', port=port)  #Start listening
```

And here’s the output:

![](https://cdn-images-1.medium.com/max/1024/1*Cr3hYo0DKRwBiXhfgVLE0g.png)

### Step 6: Deploy

The final step is to deploy everything to Heroku and then schedule the job so that it checks email.

You should have the following files:

1. Procfileâ€Š–â€Šthe file which points to showchecker.py
2. requirements.txtâ€Š–â€Šthe file which contains the library dependencies
3. runtime.txtâ€Š–â€Šthe version of python
4. showchecker.pyâ€Š–â€Šthe python code which shows the database output on the web via \<your appname\>.herokuapp.com/list
5. checkwebsite.pyâ€Š–â€Šthe python code that checks for any changes on the websites

For the requirements.txt, you will need to make amendments to add the latest libraries:

```
Flask==0.12
psycopg2==2.6.2
sendgrid==3.6.3
```

Deploy these all to Heroku:

1. `git add \*.\*\*`
2. `git commit -m "deployment"`
3. `git push heroku master`

Test each component:

1. Go to \<your app name\>.herokuapp.com/hello
2. Go to \<your app name\>.herokuapp.com/list

If there are any errors, then run heroku logs in the command line to see what is going on.

Next, run the checkwebsite.py directly on Heroku to make sure there are no issues. To do this, you can type:

heroku run python checkwebsite.py

![](https://cdn-images-1.medium.com/max/1024/1*eTeK6EvsZjWvMw-IYnDGuA.png)<figcaption>This is a great way to ensure your code is running as well on the heroku cloud asÂ locally</figcaption>

Finally, you can now schedule your job. Again, you need to include an Addon to do this.

heroku addons:create scheduler:standard

![](https://cdn-images-1.medium.com/max/1024/1*6O4ealFi6wtJ2OuE-wXa8w.png)

And you should be able to see the scheduler in your resources page:

![](https://cdn-images-1.medium.com/max/1024/1*RG3zOR_MfVjM2fjHStyZmg.png)<figcaption>The scheduler addon has been included as well which you can doubleÂ click</figcaption>

You can simply use the command line to run the program, in our case it is: python checkwebsite.py (this is the same as what we tested above with the heroku run command).

![](https://cdn-images-1.medium.com/max/1024/1*zfwYHHgSwOl4WHIcY1DJTw.png)<figcaption>You can schedule this with a fewÂ options.</figcaption>

### Summary

And that’s it… the first time it is a little complex, but hopefully the above incremental steps will help you understand what’s going on under the hood. There are a lot more resources on [Heroku](http://www.heroku.com) as well as a wealth of information on [Stack Overflow](http://stackoverflow.com/). These resources should make a lot more sense after going through the above.

Good Luck!

_Thanks for reading! If you like what you read, share it so that others may find this (you can also find me on[Twitter](http://www.twitter.com/pubs12))_

* * *


_This post was originally published on [medium.com](https://medium.freecodecamp.com/how-to-host-lightweight-apps-for-free-a29773e5f39e)_