A powerful backend ready for your next app 🚀
MIT License
This is a starter template with a feature-rich ready-to-use backend that works out of the box for local development and can be easily deployed.
You get a fully functional backend so that you can focus on what matters most: your app!
Run the shell command:
docker-compose up
By default, the following will be served:
After production build:
When CMS is enabled:
Now you can edit/replace the app in the frontend
directory and start building your own app making use of the feature-rich backend.
Several configuration options can be set using environments variables exposed while running the docker-compose
command.
Please refer to docs on Environment variables in Compose for different ways to achieve that.
Variables in .env
file will be automatically used.
Note: DO NOT commit secrets to version control.
.env
file is not tracked by git (added to .gitignore
) to avoid accidentally committing secrets. A sample in provided in sample.env. You may rename it to .env
for local development. For deployment, use GitHub Secrets instead.
NODE_ENV:
If set to "development", running docker-compose up
starts frontend local development server with hot module replracement (HMR) on port 1234, and watches the backend source code and reloads on changes (e.g. in cloud code).
If set to "production", running docker-compose up
triggers frontend build generating static files that will be served on the default port (443), and the backend server runs on pm2
which restarts the server on crash.
valid values: development, production
default: development
HOST_NAME:
The DNS name for the server hosting the app. HTTPS is used automatically with TLS certificates issued and renewed from Let's Encrypt. If "localhost" or an IP address is used, self-signed (locally trusted) certificates will be used.
examples: mywebsite.com, blog.mywebsite.com
default: localhost
Required for remote deployment
BACKEND_PORT:
The port for backend server.
default: 1337
PARSE_SERVER_PATH:
Route to parse-server REST API
default: /api
PARSE_SERVER_GRAPHQL_PATH:
Route to parse-server graphql API
default: /graphql
PARSE_DASHBOARD_PATH:
Route to parse dashboard
default: /dashboard
PARSE_DASHBOARD_ENABLED:
Enables parse dashboard if set to "yes"
default: yes
CMS_ENABLED:
Enables CMS if set to "yes"
default: no
FRONTEND_DEV_SERVER_PORT:
The port for frontend development server
default: 1234
HMR_PORT:
The port for hot module replacement (HMR) for frontend development server
default: 1235
APP_ID:
Parse server app id
default: myappid
APP_NAME:
default: myappname
MASTER_KEY:
Parse server master key
default: mymasterkey
PARSE_SERVER_DATABASE_URI:
Parse server database URI.
By default it uses the included MongoDB container. You may change this if you wish to use another MongoDB instance.
default: mongodb://mongo:27017/dev
PARSE_DASHBOARD_USER_ID:
Parse dashboard user ID
PARSE_DASHBOARD_USER_PASSWORD:
Parse dashboard user password
CMS_USER_EMAIL:
Chisel CMS user email
CMS_USER_PASSWORD:
Chisel CMS user password
BACKEND_SRC_DIR:
The backend source code directory.
default: backend
FRONTEND_SRC_DIR:
The frontend source code directory.
default: frontend
FRONTEND_DIST_DIR:
The directory containing the frontend production build inside the frontend source code directory.
default: dist
DATA_DIR:
The directory for data persistence (see Data Persistance).
default: data
BACKEND_NPM_SCRIPT:
The npm script to run after starting the backend container.
default: start
FRONTEND_NPM_SCRIPT:
The npm script to run after starting the frontend container.
default: start
These settings are used to send mail from parse server (e.g. to verify user emails)
MAIL_SMTP_HOST:
SMTP host server
example: smtp.sendgrid.net
MAIL_SMTP_PORT:
SMTP server port
default: 587
MAIL_SMTP_USERNAME:
SMTP username
MAIL_SMTP_PASSWORD:
SMTP password
MAIL_FROM_ADDRESS:
The send-from email address
BACKEND_IMAGE:
The docker image for backend
default for local build: backend
default for CI/CD: docker.pkg.github.com/{owner}/{repo}/{repo}-backend
FRONTEND_IMAGE:
The docker image for frontend
default for local build: frontend
default for CI/CD: docker.pkg.github.com/{owner}/{repo}/{repo}-frontend
IMAGE_TAG:
The tag for docker images
default for local build: latest
default for CI/CD: git short SHA
Additional parse server configurations can be defined in ./backend/config.js
The data generated (e.g. MongoDB data, parse server logs and caddy certificates) are stored by default in the ./data
directory (can be configured by the DATA_DIR
environment variable).
Cloud code can be used to run custom server-side logic. It is built on Parse JavaScript SDK.
The main entry to cloud code is ./backend/cloud/main.js
Any npm package can be installed in the backend and used (see Installing Dependencies).
To run code on server start (e.g. creating default users and roles, enforcing security rules, ...etc.), add your code to ./backend/server/initialize-server.js
Files added to the directory ./backend/public will be served by the backend server under the route /public
.
Express middleware can be added to ./backend/server/index.js
The Parse dashboard is a powerful dashboard for managing the parse server. By default, it is enabled and accessible on the route /dashboard
of the backend server (e.g. https://localhost:1337/dashboard)
It can be configured by setting the environment variables similar to this example:
PARSE_DASHBOARD_ENABLED=yes
PARSE_DASHBOARD_PATH=/dashboard
PARSE_DASHBOARD_USER_ID=myuser
PARSE_DASHBOARD_USER_PASSWORD=mypassword
The API-first headless content management system, chisel-cms, is included. However, it is disabled by default.
To enable the CMS, set the environment variable:
CMS_ENABLED=yes
It is then accessible at the root of the backend server (by default: https://localhost:1337)
Parse server users can then login by their user credentials. Users can be added using the Parse SDK, REST API, Graphql API or Parse Dashboard.
Alternatively, a user can be added by setting the environment variables:
[email protected]
CMS_USER_PASSWORD=password
This creates a new user with these credentials in the parse server. If the user is already present, the password is reset to the supplied password.
The frontend and backend are served by Caddy server with automatic HTTPS.
Caddy serves all sites over HTTPS by default.
- Caddy serves IP addresses and local/internal hostnames over HTTPS with locally-trusted certificates. Examples: localhost, 127.0.0.1.
- Caddy serves public DNS names over HTTPS with certificates from Let's Encrypt. Examples: example.com, sub.example.com, *.example.com.
- Caddy keeps all certificates renewed, and redirects HTTP (default port 80) to HTTPS (default port 443) automatically.
The frontend web app can use vanilla javascript or any javascript/typescript framework or library (see Installing Dependencies). The app can interact with the backend using the Parse JS SDK, REST API or Graphql API.
A minimal vanilla javascript app is provided as a sample. It is a simple realtime todo app that uses the Parse JS SDK, Bootstrap and Parcel bundler.
Feel free to edit/replace the app with your own.
With the environment variable NODE_ENV
set to development
(default), running docker-compose up
starts the local development server on the front end with HMR. In addition, code in backend source directory is watched for changes which trigger backend server restart.
By default, the local development server runs on https://localhost:1234, mapping the port 1234 on the frontend container. The port can be configured by setting the environment variable FRONTEND_DEV_SERVER_PORT
.
Hot Module Replacement (HMR) uses the port 1235. It can be configured using the environment variable HMR_PORT
.
Example: if you have an angular CLI app, you may want to set the following environment variables:
FRONTEND_DEV_SERVER_PORT=4200
HMR_PORT=49153
When the environment variable NODE_ENV
is set to production
, npm run build
is called in the frontend container to generate the production build in the folder frontend/dist
(configurable by setting FRONTEND_DIST_DIR
variable). The generated static files are served directly by caddy server.
To trigger frontend production build while in development mode, run:
docker-compose exec frontend npm run build
See Running Shell Commands on Containers
With NODE_ENV=production
, the backend server process is managed by PM2 which restarts the server on crash.
Make sure the containers are running
docker-compose up -d
To start an interactive shell session on the frontend docker container run:
docker-compose exec frontend bash
and for the backend
docker-compose exec backend bash
Dependencies for the backend (including cloud code) are defined in ./backend/package.json. While dependencies for the frontend app are defined in ./frontend/package.json.
Installing npm packages can be done like that:
docker-compose up -d
docker-compose exec frontend npm install lodash
docker-compose exec backend npm install lodash
Please note that adding dependencies have to be followed by docker image build to persist the changes in the docker images, by running:
docker-compose build
For convenience, a package.json file was added to the root of the repo, so that common commands can be saved as npm scripts for repeated tasks like starting the containers, starting shell sessions, running tests, ...etc.
Examples:
npm start
Runs the docker containers
npm run docker-build
Builds the docker images
npm run frontend-shell
starts intercative shell session in the frontend container
npm run test
runs tests on the frontend and backend containers
NPM needs to be installed on the host machine to be able to run npm scripts.
Docker and Docker Compose significantly simplify deployment. All the setup and dependencies are already taken care of in the docker images.
So, in principle, the steps required for deployment are:
Although this can be done manually, it is greatly simplified using the included automated CI/CD setup that uses github actions.
Assuming you can connect using SSH to your server which has Docker and Docker Compose installed (see Server Setup), and that you have a personal github access token (see Container Registry), add the following Github Secrets:
PROD_DOCKER_REGISTRY_TOKEN: your personal github access token
PROD_SSH_HOST: your server IP address
PROD_SSH_KEY: your server SSH private key
PROD_ENV_VARS: edit the following example with your values
HOST_NAME=mywebsite.com
APP_ID=myappid
MASTER_KEY=mymasterkey
PARSE_DASHBOARD_USER_ID=user
PARSE_DASHBOARD_USER_PASSWORD=pass
Note: The environment variable HOST_NAME
is required for remote deployment.
Now pushing code to main/master branch should trigger build and deploy to your server. Note that you can follow the progress and read logs of CI/CD workflows on the "Actions" tab in the gihub repo.
Continue reading for details.
Pushing new code to the main branch (by default "main" or "master"), automatically triggers:
The same can be done for different deployment environments like staging (by default, the branch "staging") and development (by default, the branch "develop"). See Multiple Deployment Environments.
Pull requests and code push to other branches trigger only building and testing the code.
Pushing docker images to the container registry requires setting Github Secret {env}_DOCKER_REGISTRY_TOKEN
(e.g. PROD_DOCKER_REGISTRY_TOKEN
for production builds). Deployment requires setting Github Secrets {env}_SSH_HOST
and {env}_SSH_KEY
(e.g. PROD_SSH_HOST
and PROD_SSH_KEY
for production deployments). See Github Secrets for details.
Re-deploys can also be manually triggered (e.g. reverting to a previous build) by specifying the git SHA to revert to without having to re-build the images. See Manual Re-Deploys
Please note that github actions and github packages have limits for free accounts and are paid services. Check github pricing for details.
If you want to avoid running the CI/CD workflow on a commit (e.g. after updating a markdown file), include [skip ci]
or [ci skip]
to the commit message.
To limit usage of github packages storage in private repos, only the latest 10 versions of each docker image are kept, and older ones are deleted. This behaviour can be configured. Packages for public repos are free and cannot be deleted.
Any cloud hosting service can be used for deployment. The server needs to have docker and docker-compose installed and you should be able to connect to it by SSH.
I prefer Digital Ocean for the simplicity and ease of use. You can get your server up and running with minimal setup in a few minutes for as low as $5/month. If you do not have an account, this is a referral link to get started with $100 in credit over 60 days. I recommend using the Docker One-Click Droplet where you get docker and docker-compose pre-installed. Make sure to add SSH key to the created droplet.
Configure the DNS records, so that your domain points to the deployment server.
The CI/CD setup allows deployment to one or more of the following environments: Production, Staging and Development.
The selection of environment is based on the git branch that triggered the deploy. Each environment has a prefix for the Github Secrets used.
The following table summarizes the environments, the associated git branch and the prefix used for Github Secrets:
Environment | Git branch | Prefix | Example |
---|---|---|---|
Production | main, master | PROD | PROD_SSH_HOST |
Staging | staging | STAG | STAG_SSH_HOST |
Development | develop | DEV | DEV_SSH_HOST |
For example, pushing code to the git branch "develop" triggers "Development" build and deploy which use Github secrets prefixed by "DEV" (e.g. DEV_DOCKER_REGISTRY, DEV_DOCKER_REGISTRY_USER, DEV_DOCKER_REGISTRY_TOKEN, DEV_SSH_HOST, DEV_SSH_KEY, DEV_ENV_VARS). This causes pushing the docker images to the "Development" container registry and deploying the app to the "Development" server with the specified environment variables.
By default, the included CI/CD setup uses Github Packages as the container registry to host the built docker images, but it can be configured to use any other container registry.
A github personal access token is required to allow for pushing to and pulling from the container registry. Note that the token needs to have permissions for repo
, write:packages
and read:packages
(and delete:packages
if you want to allow for automatic deletion of old images). This token should be saved as a value for the Github Secret: {env}_DOCKER_REGISTRY_TOKEN (e.g. PROD_DOCKER_REGISTRY_TOKEN).
To use a different container registry (other than Github Packages), all the following Github Secrets have to be set:
For example, to use Docker Hub for production images set the following Github Secrets:
Deployment settings should be stored in GitHub Secrets.
For each deployment environment, the following set of secrets can be used (prefixed by the environment prefix - see Multiple Deployment Environments for details):
{env}_DOCKER_REGISTRY
(e.g. PROD_DOCKER_REGISTRY)
The docker container registry to host the built images.
default: docker.pkg.github.com
{env}_DOCKER_REGISTRY_USER
(e.g. PROD_DOCKER_REGISTRY_USER)
Container registry username.
default: github user.
{env}_DOCKER_REGISTRY_TOKEN
(e.g. PROD_DOCKER_REGISTRY_TOKEN)
Container registry password/token. When using Github Packages as registry, this should be the github personal access token (see above).
Required for pushing docker images.
{env}_SSH_HOST
(e.g. PROD_SSH_HOST)
Depolyment server address (used in SSH connection).
Required for deployment
{env}_SSH_PORT
(e.g. PROD_SSH_PORT)
Depolyment server port (used in SSH connection).
default: 22
{env}_SSH_USER
(e.g. PROD_SSH_USER)
User on deployment server (used in SSH connection)
default: root
{env}_SSH_KEY
(e.g. PROD_SSH_KEY)
SSH key for deployment server (used in SSH connection)
Required for deployment
{env}_SSH_PATH
(e.g. PROD_SSH_PATH)
Path on deployment server (used in SSH connection)
default: ./deploy/
{env}_ENV_VARS
(e.g. PROD_ENV_VARS)
These are environment variables that will be available when running docker-compose up
on deployment server. Add each variable in a separate line.
Example:
HOST_NAME=mywebsite.com
APP_ID=myappid
MASTER_KEY=mymasterkey
PARSE_DASHBOARD_USER_ID=user
PARSE_DASHBOARD_USER_PASSWORD=pass
{env}_DOCKER_COMPOSE_UP_ARGS
(e.g. PROD_DOCKER_COMPOSE_UP_ARGS)
When running docker-compose up
on deployment server the following arguments are passed
--no-build -d
You may add here more arguments.
This can be used to run specific services (see Using a Remote MongoDB Database), scaling, etc. See documentations for details.
During continuous integration, tests/checks are run by running npm run ci-test
both on the frontend and backend containers. You may add all your tests/checks to this script.
You can manually trigger a previous deploy, without having to re-build or test it (e.g. you find a bug in the current build and you want to revert to a previous deploy).
The CI/CD workflow can be triggered manually (from ‘Run workflow’ button on the Actions tab)
You need to supply the git short SHA for the commit you want to revert to. This is the same as the tag used for the docker images. Make sure that the docker images with that tag are available (check https://github.com/{owner}/{repo}/packages).
When manual re-deploys are triggered, Github Secrets used will be the ones present at the time of the new trigger not those that were present at the initial build.
By default, the backend server runs on the same host name provided (configured by HOST_NAME
environment variable) on a separate port (by default, 1337).
For example by setting HOST_NAME=mywebsite.com
, the backend is served on https://mywebsite.com:1337.
You may set the environment variable BACKEND_HOST_NAME
to a seperate host name. By default the backend port becomes 443 (unless the variable BACKEND_PORT
is set to a different port).
For example, to serve the backend on https://api.mywebsite.com, use this configuration:
HOST_NAME=mywebsite.com
BACKEND_HOST_NAME=api.mywebsite.com
Do not forget to configure the DNS records to point the backend host name to the same server.
Note that this can also be configured for localhost.
Example:
HOST_NAME=localhost
BACKEND_HOST_NAME=api.localhost
To use a remote MongoDB instance (e.g. managed database on MongoDB Atlas) instead of the included container, follow the following steps:
Set PARSE_SERVER_DATABASE_URI
environment variable to point to your database, for example:
PARSE_SERVER_DATABASE_URI=mongodb+srv://<user>:<pass>@cluster0.abcde.mongodb.net/dev?retryWrites=true&w=majority
Start the stack using the command:
docker-compose up --no-deps backend frontend caddy
To do the same for the CI/CD setup:
PARSE_SERVER_DATABASE_URI
environment variable to PROD_ENV_VARS
github secret.PROD_DOCKER_COMPOSE_UP_ARGS
and the value:--no-deps backend frontend caddy
Pull requests are welcome!