Multi apps
Introduction
With the multi apps principle, you can create multiple apps in a single project. This is useful if you want to create a single project that contains multiple apps related to each other.
Multi apps pros and cons
When it comes to multi application projects, you have two options:
- Create a single project that contains multiple apps
- Create multiple projects that contain their own app
Each options has its pros and cons, but in general, the first option is more suitable for small to medium sized projects, while the second option is more suitable for medium to large sized projects.
Pros
- You only need to maintain a single project configuration, which makes it easier to manage.
- You don't need to run a proxy to serve multiple apps on the same domain.
- You keep a lightweight and readable configuration file.
Cons
- You need to install all dependencies for every apps, even if you only want to work on a single one.
- You don't have a real network separation between apps, which may be different than the production environment.
The project
As we want to make the things as simple as possible, we will create a project that contains two apps:
- Strapi: A headless CMS that will be used to manage the content of our website and provide an API for our frontend.
- NextJS: A frontend application that will be used to display the content of our website.
Structure
First of all, we need to create the structure of our project. To do so, we will create a folder that will contain our project, and then we will create two folders inside of it, one for each app.
strapi # Contains the Strapi app
nextjs # Contains the NextJS app
The next steps assume that we already have installed Strapi app and a NextJS in our folders, we can now create the configuration file of our project.
Configuration
Default template
Now we can create the configuration file of our project. To do so, we will install the default template by running the following command in the root of our project:
dcmd template get default
Environment configuration
As any other project, we need to configure the environment variables of our project.
To do so, copy the .env.example
file to .env
and edit it to match your needs.
Also do not forget to change the project name in the docker-compose file.
More information about project configuration can be found here.
Assume that the rest of this example will use my_multi_apps_project as project name.
Understanding
As you can see, the docker-compose.yml
is very simple and contains only a few services:
dns
: A DNS server that will be used to resolve the domain names of our apps inside the docker project network.apache
: A web server that will be used to serve our apps.db
: A database that will be used by our apps.
What we want to do is to add our apps to the project, so we will add the following services to the docker-compose.yml
file:
strapi_node
: The Strapi node container.strapi_db
: The Strapi database container. (Renaming the db service)nextjs_node
: The NextJS node container.
As you can see, we have renamed the db
service to strapi_db
because we don't need 2 databases in our project, we only need one database for Strapi.
If we had multiple databases to manage, we would copy the db
service and rename it to {app}_db
where {app}
is the name of the app that will use the database.
The names of the services doesn't really matter, but it's a good practice to name them after the app that will use them.
Also the nextjs app and the strapi app could use the same node image, but this is not a good practice, how could you change the node image for each app if you share the same one ?
Adding our services
First of all, we need to create the Dockerfile of our services.
Strapi Dockerfile
FROM node:20.10.0-bullseye
NextJS Dockerfile
FROM node:20.10.0-bullseye
Docker-compose
We are now able to define the configuration in our docker-compose file.
# ...
strapi_db:
hostname: strapi_db
container_name: ${PROJECT_NAME}_strapi_db
image: mariadb:10.6.16
dns:
- ${SUBNET_BASE}.20
- 8.8.8.8
expose:
- 3306
ports:
- 52000:3306
volumes:
- db_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_USER=user
- MYSQL_PASSWORD=user
- MYSQL_DATABASE=default
networks:
- mainnet
strapi_node:
hostname: node
container_name: ${PROJECT_NAME}_node
build: services/strapi/node
working_dir: /var/www
command: tail -f /dev/null
dns:
- ${SUBNET_BASE}.20
- 8.8.8.8
volumes:
- type: bind
source: ${PROJECT_ROOT}
target: /var/www
ports:
- 3000:3000
networks:
- mainnet
nextjs_node:
hostname: nextjs_node
container_name: ${PROJECT_NAME}_nextjs_node
build: services/nextjs/node
working_dir: /var/www
command: tail -f /dev/null
dns:
- ${SUBNET_BASE}.20
- 8.8.8.8
volumes:
- type: bind
source: ${PROJECT_ROOT}
target: /var/www
ports:
- 3400:3000
networks:
- mainnet
Note that strapi will listen on port 3000 and nextjs will listen on port 3400 from our host.
Configuring apache
To serve our apps, we will use apache, so we need to configure it to serve our apps.
The configuration file is located in .docker/etc/apache/http-vhosts.conf
, we will add the following configuration to it:
<VirtualHost *:80>
ServerName strapi.my_multi_apps_project.dev.local
ProxyPass / http://strapi_node:3000/
ProxyPassReverse / http://strapi_node:3000/
</VirtualHost>
<VirtualHost *:80>
ServerName nextjs.my_multi_apps_project.dev.local
ProxyPass / http://next_node:3000/
ProxyPassReverse / http://next_node:3000/
</VirtualHost>
Creating custom commands
We will now create some custom commands to make our life easier.
Strapi
#!/usr/bin/env /bin/bash
# @description: Run Strapi CLI in the node container
set -e
DEFAULT_TASK="develop --polling"
if [[ -z $@ ]]
then
echo -e "empty task param, run default ${DEFAULT_TASK} task"
TASK=$DEFAULT_TASK
else
TASK=$@
fi
echo -e "running $TASK task"
docker exec -it ${PROJECT_NAME}_strapi_node /bin/bash -c "\
umask g=rwx,u=rwx,o=rwx &&\
cd /var/www &&\
npx strapi $TASK"
NextJS
#!/usr/bin/env /bin/bash
# @description: Run Next CLI in the node container
set -e
DEFAULT_TASK="dev"
if [[ -z $@ ]]
then
echo -e "empty task param, run default ${DEFAULT_TASK} task"
TASK=$DEFAULT_TASK
else
TASK=$@
fi
echo -e "running $TASK task"
docker exec -it ${PROJECT_NAME}_nextjs_node /bin/bash -c "\
umask g=rwx,u=rwx,o=rwx &&\
cd /var/www &&\
npx next $TASK"
Starting the project
We are now ready to start our project, so let's do it !
dcmd up
In the first terminal instance run the following command:
dcmd strapi strapi
In the second terminal instance run the following command:
dcmd nextjs next
The NextJS app can now reach the Strapi app at http://strapi.my_multi_apps_project.dev.local
.
Note that you still have to connect strapi to the database etc.