This is a two-container web application consisting of React frontend served with Nginx and an API served with Express from a Node container. This is merely intended to serve as a jumping-off point for building such an application, and it comes ready with a test endpoint being used to pull information into the frontend.
we'll assume Docker is already installed.
These steps were pulled right from the Docker documentation.
- Install Docker Compose.
First, you may want to check the current release and replace the 1.23.2
in the command below if necessary.
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
- Make it executable.
Next, set the permissions to make the binary executable:
$ sudo chmod +x /usr/local/bin/docker-compose
- Verify it's working as expected.
Then, verify that the installation was successful by checking the version:
$ docker-compose --version
This will print out the version you installed:
docker-compose version 1.23.2, build 1110ad01
Fork and clone this repo.
$ git clone https://github.com/mbwatson/docker-nginx-react-node-api.git
Make an environment variables file named .env
. There's a sample one--.env.sample
--in place that will work for development out of the box, so just copy that.
$ cp .env.sample .env
This file contains a couple environment variables: NODE_ENV
and API_PORT
. The NODE_ENV
is set to development by default and can be (and is) overridden in the production Compose file. The API_PORT
specifies the port to esrve the API on.
There are two services to run--they are named frontend
and api
.
Start both services:
$ docker-compose up
The above command starts and attaches to the three containers and results in output like the following.
Recreating node ...
Recreating react ...
Recreating react
Recreating react ... done
Attaching to project-api, project-frontend
project-api |
project-api | > api@1.0.0 start /usr/src/app
project-api | > nodemon app
project-api |
project-api | [nodemon] 1.18.9
project-api | [nodemon] to restart at any time, enter `rs`
project-api | [nodemon] watching: *.*
project-api | [nodemon] starting `node app.js`
project-api |
project-api | Shhh... I'm listening on port 3030.
project-api |
project-frontend |
project-frontend | > app@0.1.0 start /usr/src/app
project-frontend | > react-scripts start
project-frontend |
project-frontend | Starting the development server...
project-frontend |
project-frontend | Compiled successfully!
project-frontend |
project-frontend | You can now view app in the browser.
project-frontend |
project-frontend | Local: http://localhost:3000/
project-frontend | On Your Network: http://192.168.240.3:3000/
project-frontend |
project-frontend | Note that the development build is not optimized.
project-frontend | To create a production build, use npm run build.
project-frontend |
.
.
.
If necessary, it will build the images first.
It's nice to leave your session attached to keep an eye on errors, but of course you want to rebuild and/or detach at times:
$ docker-compose up --build -d
Or only start a single services, specify it explicitly:
$ docker-compose up api
The above command starts only the api
. This is nice if you want to test the API with a tool like Postman.
You can also just build a specific image.
$ docker-compose up --build frontend
Anyway, after starting both containers. Point your browser to http://localhost:3000
to see the React application. To mess with the API directly (in the browser or with something like Postman, say), that is served to http://localhost:3030
, replacing the 3030
with another port if you made a change to .env
above.
Notice now if everything is working correctly. You should a rotating React logo, much like the out-of-the-box result from running Create React App. You should also see a "Response from API" block with "You hit the API test endpoint!" displayed.
That text is being served from the api
container, and you can trace the entire interaction to make sense of the communication between the containers.
On the frontend, you see that /frontend/src/App.js
uses the ApiTestCard
component, which receives the test endpoint as a prop, which in turn makes the call (with Axios) to the test endpoint, and then shows the response on the page.
On the backend you can trace the call to the test endpoint through /api/app.js
to /api/routes/test.js
to /api/controllers/test.js
.
Note the development frontend
and api
services start with React's development server and Nodemon, respectively, allowing hot reloading. This is great for speeding up the development process, which can take place entirely within the containers. The source files are mapped to the host machine, however, so you can also develop outside the containers. It is, however, necessary to rebuild the images during development if new modules are installed.
If, for example, you execute npm install some-tool
to install a module (which would of course be done from within the frontend/
directory), the next time docker-compose up
is run, the --build
flag will need to be used so that some-tool
is installed on the image before the container spins up.
Alternatively, you could circumvent this by logging into the running react
container and npm install
it there in (the default location) /usr/src/app
.
Start both services by specifying the production-specific Docker Compose file, docker-compose.prod.yml
:
$ docker-compose -f docker-compose.prod.yml up --build -d
This serves the frontend to port 80
on the host, and is thus reachable simply at http://localhost
. The API is publicly accessible via http://localhost/api
because the Nginx reverse proxies requests to /api/
to port 3030
in the api
container.
If you started without the detach flag, -d
, you can stop the containers running with CTRL+C
, and Docker will clean up after itself. If you ran things in detched mode (with the -d
flag), then bring everything down with the following command.
$ docker-compose down
Links to some tools used in this project are below.
- Docker
- Docker: https://docs.docker.com
- Docker Compose: https://docs.docker.com/compose/
- Docker Multi-Stage Builds https://docs.docker.com/develop/develop-images/multistage-build/
- React
- React JS: https://reactjs.org/
- Nodemon https://nodemon.io/
- Express https://expressjs.com/
- Nginx: https://nginx.org/en/docs/