Local Development Environment Setup

This guide shows you how to setup your development machine for Frappe Cloud development. By the end of this guide, you will have a replica of the FC production environment.

“Patience is bitter, but its fruit is sweet.” – Aristotle


f servers: These host your benches (f is for Frappe Apps)

m servers: These host the database (m is for MariaDB)

n servers: These are proxy servers (n is Nginx, which does the proxying)



You should have the following software packages installed on your computer before proceeding:

  1. Docker: Latest, don't forget to give docker sudo access!

  2. Certbot: Latest

  3. dns-route53 plugin for certbot: pip3 install certbot-dns-route53

Credentials from Frappe Assets

You will need access to the following accounts. If you're working at Frappe, you can request them from Frappe Assets at frappe.io:

  1. Hetzner

  2. Digital Ocean

  3. AWS

Creating Servers on Hetzner

Hetzner is a cloud hosting provider that we will use to create our servers (n, f and m). In production, we use digital ocean but for development purposes, hetzner is a better value for money.

The naming convention used can be seen in the servers list:


For example, f1.g.fc.frappe.dev is the first f server and g is for Gavin.

Create a Network while creating the first server and choose that network for other two servers also. Don't forget to add your public SSH keys during server creation.

Now, create 3 servers in Helsinki region and with Ubuntu 20.04 OS:

  1. n1.<unique-name-initial>.fc.frappe.dev: CX11 type.

  2. f1.<unique-name-initial>.fc.frappe.dev: CX21 type.

  3. m1.<unique-name-initial>.fc.frappe.dev: CX21 type.

Note down the IP Address of all the three servers.

Creating DNS records in AWS Route53

Go to the AWS Console (again, credentials are in Frappe Assets), navigate to Route 53 > Hosted Zones. Click on fc.frappe.dev domain name. You have to create 4 DNS A records here. One record will be a wild-card sub-domain:

*.<name-initial>.fc.frappe.dev pointing to the IP address of the n server created in the previous section.

The other 3 records will be for f1, n1 and m1 respectively. Use the IP address from the previous step. You can have a look at other such records if you get confused at any point.

Now, make sure you can ssh (as root) into all the three servers using thier domain names. For example:

> ssh root@f1.h.fc.frappe.dev

Create your site

On your computer, run bench get-app https://github.com/frappe/press.

If you are on a M series Mac computer and you get an error related to "go" when installing press. Here's what you can try:

  1. Install go binary - brew install go

  2. go env -w GO111MODULE=off

After this, try running the get-app command again.

Now, create a new site and install press on this site.

Open the site and login as Administrator.

Press Settings

Create a Root Domain

Navigate to Root Domain List (AwesomeBar to rescue!) and create a new document. Fill up the details as below:

  • Name: <your-domain-name>, e.g. h.fc.frappe.dev

  • Default Cluster: Default

  • AWS Access Key ID: Get from AWS Console

  • AWS Secret Access Key: Get from AWS Console

Save it.

You can get your Access Keys by going to AWS Console > IAM > User > John Doe (create one if required) > Security credentials > Access Keys

Open Press Settings now. Now, set the Domain to the root domain you created in the previous step and cluster to Default.

Now, there is going to be a lot of back and forth between your terminal and Press Settings, so sit tight.

Let's Encrypt

Scroll down and expand the Let's Encrypt section. Before entering the details here, you have to create two directories on your local computer (it is better to place this at user level, e.g. /home/<user>/):

  1. .certbot -> directory

  2. webroot -> directory, inside the .certbot directory

Now, fill the Certbot Directory and Webroot Directory with the absolute path of the above two newly created directories respectively. Leave out other fields as it is. You can enter your email if you want.

Save the settings.


Now, Scroll down to Docker Registry section.

Fill in the fields as given below:

Docker Registry URL: registry.digitalocean.com/staging-frappe-cloud

Docker Registry Namespace: Any name you like, e.g. hussain-staging

Download Docker Credentials from https://cloud.digitalocean.com/registry/settings?i=abbd47 and then decode the auth string and use it for both Docker Registry Username and Docker Registry Password

The decoded string should be in the following format:


Use the string before colon (:) as Docker Registry Username and Docker Registry Password

Again, save the settings and scroll down to Docker Build section.

Go to your terminal and cd into your bench directory. Create two directories here:

  1. .clones

  2. .docker-builds

Go back to the Press Settingsand paste the absolute paths of the above two directories to the Clone Directory and Build Directory respectively. Leave the other field empty and save the settings.

Sometimes, there is an issue while uploading a docker image in the background and you have to manually push it to registry. For that case, you have to login to digital ocean registry through docker before pushing. You can do this by running this command:

> docker login -u <do-registry-user-id> -p <do-password> registry.digitalocean.com

Stripe Settings

In the Stripe Settings section, create a new Stripe Account from the link field.

You can signup for a new Stripe account from https://dashboard.stripe.com/. By default, Stripe gives you a test account which is enough for our development purposes.

Get the Publishable Key and Secret Key from Stripe dashboard and create your Stripe Account and set it in Press Settings. Set values for Credits on Signup fields. For e.g., INR 1800 and USD 25.

Now click on Create Stripe Webhook. It should create webhook endpoints on Stripe and set the field Stripe Webhook Endpoint ID.

That's it for Stripe Settings.

Setting up Proxy server (n server)

Go to the Proxy Server list and click + Add Proxy Server. Fill in the details as given below:

Hostname: n1 (n2, n3, if you want to create more Proxy servers)

IP: IP Address of the n server. Private IP: Private (internal) IP Address of the n server. Can be found in Hetzner console.

Click on save.

Note: The agent password will be set automatically for you.

Now, click on the Actions dropdown button, which is located next to the Save button and click on Setup Server. The server should go in Installing state.

This will setup the server. We use Ansible to automate the infrastructure, so, once you click on the Setup Server button, Ansible Plays will be created and run in the background to setup the server (install necessary software, perform essential configuration changes and more). Each Ansible Play document creates a number of Ansible Task, which is an individual task that will be carried out to setup the server.

Navigate to Ansible Task List and you should see some tasks which will have a particular status. For example, success means the task completed successfully and running means the task is currently running. You should confirm that all the tasks are eventually successful.

After some time, when the tasks have completed to run, the Proxy Server will go to Active state.

If there is any error (for example, if the Proxy Server goes into Broken state) or a task keeps running forever, go to the Error Log List and you will most probably find a log that corresponds to the task and more information on why it failed.

If the Ansible Task "Clone Agent Repository" fails, you might want to generate a personal access token and edit the git clone URL in press/playbooks/roles/agent/tasks/main.yml at the agent github URL line. It should be in the format: "https://<github-username>:<personal-access-token>@github.com:/frappe/agent"

Setting up DB server (m server)

In this section, we will move on to create a Database Server. Go to the Database Server List and create a new document. Fill in the fields as given below:

Hostname: m1 IP: External IP address of the m server Private IP: Internal IP address of the m server

MariaDB Root Password: Create a password, this will be the root password of the MariaDB database that will be installed on this server.

Now, you have to follow the same steps as for the proxy server. Save the document and do setup server. Once this server is setup, you can move on to setting up the f server.

Setting up App server (f server)

In the proxy server section, we created and set up the Proxy Server which sits in the front and forwards traffic to various f servers. Now, f servers are where the benches (along with the sites) are present. The databases are on different m servers and the sites hosted in the f servers use those databases.

Go to the Server List and add a new server document. Fill in the details as given below:

Hostname: f1 Cluster: Default

IP: External IP address of f server Private IP: Internal IP address of f server

Proxy Server: Select the Proxy Server which we created in a previous section. Database Server: Select the Database Server which we created in the previous section.

Leave other fields as they are. Save the document.

Now, click on Actions > Setup Server and wait for it to complete. After that, click on Actions > Add to Proxy.

That's it for the f server.

Setting up Builds

Under Press Settings > Docker > Docker Build set Build Server to the app server you have created in the previous set.

Now, when you run a Build and Deploy, the image that is created for the deploy will be built on the Build Server.

Creating Your First Site

Creating an App

The first step is to create an App that will ultimately be installed on our site. The first app in any release group must be frappe (Frappe Framework), the name is case sensitive. Navigate to App List page and click on '+ Add new App' button on the top-right corner. Fill in the details as below:

New App

Create App Source

Now, we need to create an App source for this app. Navigate to App Source list page, create a new document and fill in the details as below:

Creating a Release Group

If you are on a Mac add export NO_PROXY=* OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES to your shell configuration file (like .zshrc) to avoid having Agent Jobs stuck at Undelivered status.

Navigate to the Release Group list and create a new release group. The details to be filled are shown in the screenshot below.

New App

Select the app source that you created in the previous step. Click save.

Once you save the release group document, a Deploy Candidate is automatically created for this release group. In fact, a deploy candidate is created any time you make changes to the Release Group.

New App

Click on the Deploy Candidate chip and this will take you to the Deploy Candidate page which is filtered for the current Release Group. Select the Deploy Candidate (are named like bench-xxx) that was created latest. You should only have one if you never created a release group before. Now, click on Actions and then Schedule Build and Deploy.

New App

This will build the docker image for this bench, upload it to the digital ocean image registry and also deploy it to your f server.

You can click on Visit Dashboard link on the top-left corner to view the progress of the build and deploy step.

Once the image is deployed, you can go the benches list and you will find a new bench there. This was created using the Deploy Candidate. Now, you can go ahead and create as many sites you want. You can do this either via the dashboad or the desk.

Resolving issues

One of the issues that you may get into is not being able to obtain a TLS Certificate for the root domain. If that is the case, you have to manually call (via console) the _obtain_certificate method on the TLS Certificate document that was created for the Root Domain document that we created in the initial part of this guide.


  • Set scheduler_tick_interval to a smaller value (like 5) for faster Agent Job updates, since most of them don't take much time.


If you made till here, well done and be proud of yourself. Now, its time to build awesome things. Good Luck with your journey on Frappe Cloud.

On this page