Using FusionAuth on Docker
FusionAuth Docker containers can be used with Docker Compose, Kubernetes, Helm or OpenShift.
The following example is using Docker Compose. Here are kubernetes installation instructions, which use Helm. Find links for OpenShift and other community supported environments in the FusionAuth Contrib GitHub repo.
Docker Compose
All of the FusionAuth Docker images may be found on Docker Hub.
The FusionAuth Docker Compose YAML files may be found on FusionAuth containers repository and more examples in the FusionAuth Docker Compose example repository described in more detail below.
If you’re looking for a complete configuration to get up and running quickly, use our Docker Compose example. docker-compose.yml
will install FusionAuth with OpenSearch, but you can switch between the different search engines.
Installing FusionAuth
To use FusionAuth download the docker-compose.yml
and the .env
files and then start up the configured containers.
Download the FusionAuth docker files
curl -o docker-compose.yml https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/main/docker/fusionauth/docker-compose.yml
curl -o .env https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/main/docker/fusionauth/.env
Edit these files as needed. The stock .env
file will contain the following values, you will want to modify the DATABASE_PASSWORD
and ensure the POSTGRES_USER
and POSTGRES_PASSWORD
values are correct. You may also override any of these values using environment variables.
The .env file
DATABASE_USERNAME=fusionauth
DATABASE_PASSWORD=hkaLBM3RVnyYeYeqE3WI1w2e4Avpy0Wd5O3s3
FUSIONAUTH_APP_MEMORY=512M
FUSIONAUTH_APP_RUNTIME_MODE=development
OPENSEARCH_JAVA_OPTS="-Xms512m -Xmx512m"
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
Starting FusionAuth
docker compose up -d
docker compose logs -f
The Docker Compose Files
The following is the default docker-compose.yml
file, which installs FusionAuth.
docker-compose.yml
version: '3'
services:
db:
image: postgres:16.0-bookworm
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
networks:
- db_net
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
search:
image: opensearchproject/opensearch:2.11.0
environment:
cluster.name: fusionauth
discovery.type: single-node
node.name: search
plugins.security.disabled: true
bootstrap.memory_lock: true
OPENSEARCH_JAVA_OPTS: ${OPENSEARCH_JAVA_OPTS}
healthcheck:
interval: 10s
retries: 80
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:9200/
restart: unless-stopped
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- 9200:9200 # REST API
- 9600:9600 # Performance Analyzer
volumes:
- search_data:/usr/share/opensearch/data
networks:
- search_net
fusionauth:
image: fusionauth/fusionauth-app:latest
depends_on:
db:
condition: service_healthy
search:
condition: service_healthy
environment:
DATABASE_URL: jdbc:postgresql://db:5432/fusionauth
DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_USERNAME: ${DATABASE_USERNAME}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY}
FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE}
FUSIONAUTH_APP_URL: http://fusionauth:9011
SEARCH_SERVERS: http://search:9200
SEARCH_TYPE: elasticsearch
healthcheck:
test: curl --silent --fail http://localhost:9011/api/status -o /dev/null -w "%{http_code}"
interval: 5s
timeout: 5s
retries: 5
networks:
- db_net
- search_net
restart: unless-stopped
ports:
- 9011:9011
volumes:
- fusionauth_config:/usr/local/fusionauth/config
networks:
db_net:
driver: bridge
search_net:
driver: bridge
volumes:
db_data:
fusionauth_config:
search_data:
Docker Services
In the above example configurations there are three services:
database
search
fusionauth
Let’s look at each of these.
Database Service
The database service provides a PostgreSQL database for use by FusionAuth.
You will need to either set the POSTGRES_PASSWORD
environment variable in the db
service section, or, more ideally, set the value in the host environment and only reference it in the docker-compose.yml
file.
By default this database is not accessible outside of the Docker Compose containers, but you may expose the port if you want to examine the database by adding the ports mapping in the service definition.
Review the other properties to ensure they meet your requirements.
Note: If you plan to use MySQL please review the Limitations for the FusionAuth docker images.
Search Service
Elasticsearch Versions >=
7.6.1 and <=
7.17.x are currently supported. Later versions may work as well but may not have been tested for compatibility.
OpenSearch version 2.x should also function properly with FusionAuth version >= 1.42.0
.
The RAM required by Elasticsearch or OpenSearch depends on your login volume and user/entity counts. If you expect to have a few logins per minute and only a few thousand users/entities, 1GB-2GB
of RAM will be sufficient. If you have more users/entities as well as logins, please size up accordingly. We recommend running load tests of FusionAuth to help determine the amount of RAM that is required for your needs.
The FusionAuth Service
This is the service that runs the FusionAuth application.
Review the Configuration documentation to customize your deployment. The best way to configure FusionAuth when using Docker is to use environment variables as documented in that link.
In addition, the port 9011
is mapped between the container and your host machine. This may be modified if you want to run more than one FusionAuth instance or for any other reason.
Other Services
You may add other services to the Docker Compose files if needed.
For example, in development environments it can be helpful to run MailCatcher which provides a local SMTP server. This allows FusionAuth to send transactional emails for account verification, password reset, and others.
Example docker-compose.yml with mailcatcher
version: '3'
services:
db:
image: postgres:16.0-bookworm
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
networks:
- db_net
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
search:
image: opensearchproject/opensearch:2.11.0
environment:
cluster.name: fusionauth
discovery.type: single-node
node.name: search
plugins.security.disabled: true
bootstrap.memory_lock: true
OPENSEARCH_JAVA_OPTS: ${OPENSEARCH_JAVA_OPTS}
healthcheck:
interval: 10s
retries: 80
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:9200/
restart: unless-stopped
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- 9200:9200 # REST API
- 9600:9600 # Performance Analyzer
volumes:
- search_data:/usr/share/opensearch/data
networks:
- search_net
mailcatcher:
image: sj26/mailcatcher
ports:
- "1025:1025"
- "1080:1080"
healthcheck:
interval: 10s
retries: 80
test: wget -q -O /dev/null http://mailcatcher:1080/
networks:
- mailcatcher_net
fusionauth:
image: fusionauth/fusionauth-app:latest
depends_on:
db:
condition: service_healthy
search:
condition: service_healthy
mailcatcher:
condition: service_healthy
environment:
DATABASE_URL: jdbc:postgresql://db:5432/fusionauth
DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_USERNAME: ${DATABASE_USERNAME}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY}
FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE}
FUSIONAUTH_APP_URL: http://fusionauth:9011
SEARCH_SERVERS: http://search:9200
SEARCH_TYPE: elasticsearch
FUSIONAUTH_APP_KICKSTART_FILE: ${FUSIONAUTH_APP_KICKSTART_FILE}
networks:
- db_net
- search_net
- mailcatcher_net
restart: unless-stopped
ports:
- 9011:9011
volumes:
- fusionauth_config:/usr/local/fusionauth/config
- ./kickstart:/usr/local/fusionauth/kickstart
networks:
db_net:
driver: bridge
search_net:
driver: bridge
mailcatcher_net:
driver: bridge
volumes:
db_data:
fusionauth_config:
search_data:
Below is a functional configuration on the tenant email tab based on the above configuration file:
This a view of the Mailcatcher client.
Upgrading
To upgrade FusionAuth when running with docker compose
:
- Stop the instance:
docker compose down
. - Modify the
docker-compose.yml
file to point to the version of FusionAuth you want. You can see available tags. - Start it up:
docker compose up -d
. - Log in to the administrative UI.
Migrations
If there were database migrations required, what happens on an upgrade depends on two settings: the runtime mode and the silent mode.
Prior to version 1.19.0
, migration behavior was different. See below for more.
If silent mode is set to true
, then database migrations will automatically be performed.
If silent mode is false
and the runtime mode is set to development
, then the maintenance mode screen will pop up and you will be prompted to complete the migrations there.
In all other cases the migrations will not be applied, and you’ll have to perform them yourself. If you want to manage your own database upgrades, performing the SQL migrations out of band with another tool or process is a good option.
When Are Database Migrations Applied
Runtime Mode | Silent Mode | Migration Behavior |
---|---|---|
development | true | Migration applied automatically |
development | false | Maintenance mode UI displayed, user prompted to run migrations |
production | true | Migration applied automatically |
production | false | Migration never applied by FusionAuth, must be applied out of band |
See the configuration reference or the silent mode guide for more information. To apply the database migrations out of band see the database upgrade documentation.
Prior to 1.19
If the installation is in production
mode, apply the migrations out of band.
When running in development runtime mode, silent mode was enabled based upon the presence of environment variables, such as the database user, and could not explicitly be enabled or disabled.
Docker Tags
The Docker Compose file references the latest
tag, but that tag is not dynamic. It is only the latest at a point in time. To get the most recently released image, you have a couple of options.
- Pull the latest image with this command:
docker pull fusionauth/fusionauth-app:latest
ordocker compose pull
and recreate your deployment withdocker compose up -d
which will recreate every container where a new image is available. - Edit the Docker Compose file and specify a specific version. This is a good idea for a production deployment. With
docker compose pull
you can only pull the specified image, or just rundocker compose up -d
which will pull the image and recreate the container at the same time. - Remove all images with
docker rmi <IMAGE ID>
selected from the list of IMAGE IDs which you can show withdocker images
. This requires that the image isn’t used and therefore may prompt you to remove containers using it. Since all state of FusionAuth is stored in the database, and for docker you use volumes to persist data, you can safely remove the containers. After that you can usedocker compose pull
,docker compose build
anddocker compose up -d
accordingly to get images specified the in thedocker-compose.yml
.
To generally clean up your images on your system ,docker image prune
will remove all unused, dangling images.
Custom Docker Images
If you want to build your own image starting with our base image, start with the fusionauth/fusionauth-app
image. Just as the FusionAuth Docker image is based on an Ubuntu container image, you can build a Docker file which is based on the fusionauth/fusionauth-app:latest
image. This can be useful if you want to permanently add a password hashing plugin, configuration file, or other customization to the image.
Here’s a Dockerfile which extends the latest FusionAuth image:
Example Dockerfile for building fusionauth-app including a plugin
FROM maven AS build
WORKDIR /app
RUN git init . &&\
git remote add -t \* -f origin https://github.com/FusionAuth/fusionauth-example-password-encryptor.git &&\
git checkout master &&\
mvn compile package
FROM fusionauth/fusionauth-app:latest
COPY --chown=fusionauth:fusionauth --from=build /app/target/fusionauth-example-password-encryptor*.jar /usr/local/fusionauth/plugins/
Here’s an example docker compose YAML file which uses this new image:
Example docker-compose.yml for building fusionauth-app including a plugin
version: '3'
services:
db:
image: postgres:16.0-bookworm
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
networks:
- db_net
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
search:
image: opensearchproject/opensearch:2.11.0
environment:
cluster.name: fusionauth
discovery.type: single-node
node.name: search
plugins.security.disabled: true
bootstrap.memory_lock: true
OPENSEARCH_JAVA_OPTS: ${OPENSEARCH_JAVA_OPTS}
healthcheck:
interval: 10s
retries: 80
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:9200/
restart: unless-stopped
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- 9200:9200 # REST API
- 9600:9600 # Performance Analyzer
volumes:
- search_data:/usr/share/opensearch/data
networks:
- search_net
fusionauth:
#image: fusionauth/fusionauth-app:latest
build: ./fusionauth-app
depends_on:
db:
condition: service_healthy
search:
condition: service_healthy
environment:
DATABASE_URL: jdbc:postgresql://db:5432/fusionauth
DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_USERNAME: ${DATABASE_USERNAME}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY}
FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE}
FUSIONAUTH_APP_URL: http://fusionauth:9011
SEARCH_SERVERS: http://search:9200
SEARCH_TYPE: elasticsearch
FUSIONAUTH_APP_KICKSTART_FILE: ${FUSIONAUTH_APP_KICKSTART_FILE}
networks:
- db_net
- search_net
restart: unless-stopped
ports:
- 9011:9011
volumes:
- fusionauth_config:/usr/local/fusionauth/config
- ./kickstart:/usr/local/fusionauth/kickstart
networks:
db_net:
driver: bridge
search_net:
driver: bridge
volumes:
db_data:
fusionauth_config:
search_data:
With this example, you can use docker compose build
to only run the build steps in the referenced Dockerfile. This will create you a custom Docker image which is consequentially used in the creation of the container in Docker Compose when running docker compose up -d
. Alternatively you can run only docker compose up -d
which will automatically take care of the build as well if not present.
By default the build process will cache a lot of the steps, to force a fresh build you can run docker compose build --pull --no-cache
instead.
Here’s the FusionAuth application Dockerfile as a reference which builds the fusionauth/fusionauth-app
base image.
The FusionAuth Docker file
#
# FusionAuth App Dockerfile
#
# Build:
# > docker pull ubuntu:noble
# > docker buildx build --platform=linux/arm64 -t fusionauth/fusionauth-app:1.54.0 .
# > docker buildx build --platform=linux/arm64 -t fusionauth/fusionauth-app:latest .
#
# Note: Substitute your target platform architecture. The above example is targetting a 64-bit ARM platform.
# To target an Intel based platform use --platform=linux/amd64.
#
# Run:
# > docker run -p 9011:9011 -it fusionauth/fusionauth-app
#
# Publish:
# > docker push fusionauth/fusionauth-app:1.54.0
# > docker push fusionauth/fusionauth-app:latest
#
###### Setup the java and fusionauth-app base #####################################################
FROM --platform=$BUILDPLATFORM ubuntu:noble AS build
ARG BUILDPLATFORM
ARG FUSIONAUTH_VERSION=1.54.0
ARG JDK_MODULES=java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.net.http,java.rmi,java.security.jgss,java.security.sasl,java.sql,java.xml.crypto,jdk.attach,jdk.crypto.ec,jdk.dynalink,jdk.jcmd,jdk.jdi,jdk.localedata,jdk.jpackage,jdk.unsupported,jdk.zipfs
ARG TARGETPLATFORM
ARG TARGETARCH
RUN printf "Building on ${BUILDPLATFORM} for ${TARGETPLATFORM} (${TARGETARCH})."
RUN case "${BUILDPLATFORM}" in \
linux/arm64)\
BUILD_JAVA_SUM="d768eecddd7a515711659e02caef8516b7b7177fa34880a56398fd9822593a79";\
BUILD_JAVA_URL="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.4_7.tar.gz";\
;;\
linux/amd64)\
BUILD_JAVA_SUM="51fb4d03a4429c39d397d3a03a779077159317616550e4e71624c9843083e7b9";\
BUILD_JAVA_URL="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz";\
;;\
*)\
printf "Unsupported build platform arch: ${BUILDPLATFORM}";\
exit 1;\
;;\
esac \
&& case "${TARGETARCH}" in \
arm64)\
JAVA_SUM="d768eecddd7a515711659e02caef8516b7b7177fa34880a56398fd9822593a79";\
JAVA_URL="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.4_7.tar.gz";\
;;\
ppc64le)\
JAVA_SUM="c208cd0fb90560644a90f928667d2f53bfe408c957a5e36206585ad874427761";\
JAVA_URL="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_ppc64le_linux_hotspot_21.0.4_7.tar.gz";\
;;\
s390x)\
JAVA_SUM="c900c8d64fab1e53274974fa4a4c736a5a3754485a5c56f4947281480773658a";\
JAVA_URL="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_s390x_linux_hotspot_21.0.4_7.tar.gz";\
;;\
amd64)\
JAVA_SUM="51fb4d03a4429c39d397d3a03a779077159317616550e4e71624c9843083e7b9";\
JAVA_URL="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz";\
;;\
*)\
printf "Unsupported arch: ${TARGETARCH}";\
exit 1;\
;;\
esac \
&& apt-get update \
&& apt-get install -y curl unzip \
&& mkdir -p /tmp/openjdk \
&& mkdir -p /tmp/build/openjdk \
&& curl -LfsSo /tmp/build/openjdk.tar.gz "${BUILD_JAVA_URL}" \
&& echo "${BUILD_JAVA_SUM} */tmp/build/openjdk.tar.gz" | sha256sum -c - \
&& curl -LfsSo /tmp/openjdk.tar.gz "${JAVA_URL}" \
&& echo "${JAVA_SUM} */tmp/openjdk.tar.gz" | sha256sum -c - \
&& cd /tmp/build/openjdk \
&& tar -xf /tmp/build/openjdk.tar.gz --strip-components=1 \
&& cd /tmp/openjdk \
&& tar -xf /tmp/openjdk.tar.gz --strip-components=1 \
&& /tmp/build/openjdk/bin/jlink --compress=2 \
--module-path /tmp/openjdk/jmods/ \
--add-modules ${JDK_MODULES} \
--output /opt/openjdk \
&& curl -LfsSo /tmp/fusionauth-app.zip https://files.fusionauth.io/products/fusionauth/${FUSIONAUTH_VERSION}/fusionauth-app-${FUSIONAUTH_VERSION}.zip \
&& mkdir -p /usr/local/fusionauth/fusionauth-app \
&& unzip -nq /tmp/fusionauth-app.zip -d /usr/local/fusionauth
###### Use Ubuntu latest and only copy in what we need to reduce the layer size ###################
FROM ubuntu:noble
RUN apt-get update \
&& apt-get -y install --no-install-recommends curl \
&& apt-get -y upgrade \
&& apt-get -y clean \
&& rm -rf /var/lib/apt/lists \
&& useradd -d /usr/local/fusionauth -U fusionauth
COPY --chown=fusionauth:fusionauth --from=build /opt/openjdk /opt/openjdk
COPY --chown=fusionauth:fusionauth --from=build /usr/local/fusionauth /usr/local/fusionauth
###### Connect the log file to stdout #############################################################
RUN mkdir -p /usr/local/fusionauth/logs \
&& touch /usr/local/fusionauth/logs/fusionauth-app.log \
&& ln -sf /dev/stdout /usr/local/fusionauth/logs/fusionauth-app.log
###### Start FusionAuth App #######################################################################
LABEL description="Create an image running FusionAuth App. Installs FusionAuth App"
LABEL maintainer="FusionAuth <dev@fusionauth.io>"
EXPOSE 9011
USER fusionauth
ENV FUSIONAUTH_USE_GLOBAL_JAVA=1
ENV JAVA_HOME=/opt/openjdk
ENV PATH=$PATH:$JAVA_HOME/bin
CMD ["/usr/local/fusionauth/fusionauth-app/bin/start.sh"]
Here is additional Docker documentation.
Kickstart
Using Docker with Kickstart is a powerful combination. Using these technologies together lets you:
- Configure and share development environments
- Create replicable bug reports
- Spin up auth instances with a well known, versioned set of data for continuous integration and testing
All the normal limitations of Kickstart apply (the Kickstart will not run if the database has already been set up with an API key, for example).
It’s easy to get started with Kickstart, but you’ll need to tweak your Docker Compose files a bit. Before you begin, you’ll need a valid kickstart.json
file. Note that this file could be called anything, kickstart.json
is simply a convention. Check out the Kickstart documentation for more information on writing one.
Once you have a valid kickstart.json
file, create a subdirectory in the location of your docker-compose.yml
file. It can be named anything; this documentation will use a directory called kickstart
. Next, you’ll mount this directory and set the FUSIONAUTH_APP_KICKSTART_FILE
variable in the docker-compose.yml
file.
Here are the steps to do so:
- In the
volumes:
section of thefusionauth
service, add- ./kickstart:/usr/local/fusionauth/kickstart
. - Modify
.env
and add the Kickstart configuration variable:FUSIONAUTH_APP_KICKSTART_FILE=/usr/local/fusionauth/kickstart/kickstart.json
. This path should be what the Docker container expects, not the path on the host. - Configure
docker-compose.yml
to pass the environment variable set by.env
to the container. Do this by addingFUSIONAUTH_APP_KICKSTART_FILE: ${FUSIONAUTH_APP_KICKSTART_FILE}
to theenvironment
section of thefusionauth
service. docker compose up -d
The following is an example docker-compose.yml
file configuring FusionAuth to run the commands in a kickstart.json
at startup.
Example docker-compose.yml for running Kickstart
version: '3'
services:
db:
image: postgres:16.0-bookworm
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
networks:
- db_net
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
search:
image: opensearchproject/opensearch:2.11.0
environment:
cluster.name: fusionauth
discovery.type: single-node
node.name: search
plugins.security.disabled: true
bootstrap.memory_lock: true
OPENSEARCH_JAVA_OPTS: ${OPENSEARCH_JAVA_OPTS}
healthcheck:
interval: 10s
retries: 80
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:9200/
restart: unless-stopped
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- 9200:9200 # REST API
- 9600:9600 # Performance Analyzer
volumes:
- search_data:/usr/share/opensearch/data
networks:
- search_net
fusionauth:
image: fusionauth/fusionauth-app:latest
depends_on:
db:
condition: service_healthy
search:
condition: service_healthy
environment:
DATABASE_URL: jdbc:postgresql://db:5432/fusionauth
DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_USERNAME: ${DATABASE_USERNAME}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY}
FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE}
FUSIONAUTH_APP_URL: http://fusionauth:9011
SEARCH_SERVERS: http://search:9200
SEARCH_TYPE: elasticsearch
FUSIONAUTH_APP_KICKSTART_FILE: ${FUSIONAUTH_APP_KICKSTART_FILE}
networks:
- db_net
- search_net
restart: unless-stopped
ports:
- 9011:9011
volumes:
- fusionauth_config:/usr/local/fusionauth/config
- ./kickstart:/usr/local/fusionauth/kickstart
networks:
db_net:
driver: bridge
search_net:
driver: bridge
volumes:
db_data:
fusionauth_config:
search_data:
After running docker compose up -d
you should see a line similar to the one below in the logs. These logs can be accessed using this command: docker compose logs -f fusionauth
:
FusionAuth log messages indicating Kickstart has succeeded
io.fusionauth.api.service.system.kickstart.KickstartRunner - Summary
This indicates that Kickstart completed and provides a summary of the configuration changes made by it.
You may also want to check out the Isolated Docker Setups if you want the ability to rapidly stand up different versions and configurations of FusionAuth.
If you want to test changes to your Kickstart file, you’ll need to delete your volumes each time. Kickstart won’t run except on a brand new install. If there is any data in the database, it won’t proceed.
This will delete all data in your docker instance.
Deleting the volumes
docker compose down -v
Plugins
Instead of building a custom docker image, you can directly mount a directory containing a plugin to your Docker container.
Here are the steps to do so:
- In the
volumes:
section of thefusionauth
service, add- ./plugins:/usr/local/fusionauth/plugins
. - Copy your plugin jar file, created by following the instructions, to your
plugins
directory on the host. docker compose up -d
The following is an example docker-compose.yml
file configuring FusionAuth to scan for plugins at startup.
Example docker-compose.yml for installing a plugin
version: '3'
services:
db:
image: postgres:16.0-bookworm
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
networks:
- db_net
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
search:
image: opensearchproject/opensearch:2.11.0
environment:
cluster.name: fusionauth
discovery.type: single-node
node.name: search
plugins.security.disabled: true
bootstrap.memory_lock: true
OPENSEARCH_JAVA_OPTS: ${OPENSEARCH_JAVA_OPTS}
healthcheck:
interval: 10s
retries: 80
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:9200/
restart: unless-stopped
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- 9200:9200 # REST API
- 9600:9600 # Performance Analyzer
volumes:
- search_data:/usr/share/opensearch/data
networks:
- search_net
fusionauth:
image: fusionauth/fusionauth-app:latest
depends_on:
db:
condition: service_healthy
search:
condition: service_healthy
maven:
condition: service_completed_successfully
environment:
DATABASE_URL: jdbc:postgresql://db:5432/fusionauth
DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
DATABASE_USERNAME: ${DATABASE_USERNAME}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY}
FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE}
FUSIONAUTH_APP_URL: http://fusionauth:9011
SEARCH_SERVERS: http://search:9200
SEARCH_TYPE: elasticsearch
FUSIONAUTH_APP_KICKSTART_FILE: ${FUSIONAUTH_APP_KICKSTART_FILE}
networks:
- db_net
- search_net
restart: unless-stopped
ports:
- 9011:9011
volumes:
- fusionauth_config:/usr/local/fusionauth/config
- ./kickstart:/usr/local/fusionauth/kickstart
- ./plugins:/usr/local/fusionauth/plugins
maven:
image: maven
command:
- /bin/sh
- -c
- |
git init .
git remote add -t \* -f origin https://github.com/FusionAuth/fusionauth-example-password-encryptor.git
git checkout master
mvn compile package
cp target/fusionauth-example-password-encryptor*.jar output/
chown 1000:1000 output/*
volumes:
- maven_cache:/root/.m2
- plugin_source:/app
- ./plugins:/app/output
working_dir: /app
networks:
db_net:
driver: bridge
search_net:
driver: bridge
volumes:
db_data:
fusionauth_config:
search_data:
maven_cache:
plugin_source:
After running docker compose up -d
you should see a line like this in the logs, which you can access using the command docker compose logs -f fusionauth
:
FusionAuth log messages indicating a plugin has been successfully installed
INFO io.fusionauth.api.plugin.guice.PluginModule - Installing plugin [com.mycompany.fusionauth.plugins.guice.MyExampleFusionAuthPluginModule]
INFO io.fusionauth.api.plugin.guice.PluginModule - Plugin successfully installed
Such output indicates that the plugin has been installed and can be used.
Accessing the Host Machine
The default FusionAuth Docker configuration sets up the network using the bridge
configuration. This means that all the hosts defined by docker-compose.yml
can access each other. However, it means that any applications running on your host machine cannot be accessed by FusionAuth using localhost
.
This is typically only an issue when FusionAuth is accessing resources outside of the Docker network to, for example, send email or request a webhook. For example, if an application is running locally and you want FusionAuth, running in Docker, to send a webhook payload to it, configuring FusionAuth to send the webhook to localhost
won’t work. localhost
in the Docker container refers to the Docker container itself, not the host machine.
In this situation, do one of the following:
- Run a container with your application in Docker, and use the appropriate network domain name.
- Install FusionAuth on the host machine and use
localhost
. - Use an alias address,
host.docker.internal
, as the hostname instead oflocalhost
.- For macOS and Windows hosts, you can use
host.docker.internal
without any additional configuration. - For Linux hosts, add the following lines to your
docker-compose.yml
.
- For macOS and Windows hosts, you can use
extra_hosts:
- "host.docker.internal:host-gateway"
Modifying the FusionAuth service in docker-compose.yml
to use other Docker networking schemes such as host
may work, but isn’t fully tested or supported.
OpenSearch Production Deployment Configuration
Production runtime requirements and configuration for OpenSearch will drastically differ from the Docker Compose examples as the examples are configured without any security or redundancy.
Please review the Installing OpenSearch documentation for further details around production deployment.
Elasticsearch Production Deployment Configuration
Elasticsearch has a few runtime requirements that may not be met by default on your host platform. Please review the Elasticsearch Docker production mode guide for more information.
For example if startup is failing and you see the following in the logs, you will need to increase vm.max_map_count
on your host VM.
The log message when max_map_count is too low
2018-11-22T12:32:06.779828954Z Nov 22, 2018 12:32:06.779 PM ERROR c.inversoft.maintenance.search.ElasticsearchSilentConfigurationWorkflowTask
- Silent configuration was unable to complete search configuration. Entering maintenance mode. State [SERVER_DOWN]
2018-11-22T13:00:05.346558595Z ERROR: [2] bootstrap checks failed
2018-11-22T13:00:05.346600195Z [1]: memory locking requested for elasticsearch process but memory is not locked
2018-11-22T13:00:05.346606495Z [2]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
Limitations
Due to Oracle licensing restrictions, the docker images published on Docker Hub do not contain the necessary software to connect to a MySQL database.
If you wish to use MySQL, you’ll need to build a custom container that includes the MySQL Connector JAR file. Here is an example container definition that uses the FusionAuth image as a base layer and adds the MySQL connector.
Example Dockerfile which downloads the MySQL connector
#
# FusionAuth App Dockerfile including the MySQL connector
#
# Note:
# -----------------------------------------------------------------------------
# The MySQL JDBC connector is not bundled with FusionAuth due to the GPL
# license terms under which Oracle publishes this software.
#
# Because of this restriction, you will need to build a docker image for your
# use that contains the MySQL JDBC connector in order to connect to a MySQL
# database at runtime.
# Source: https://github.com/mysql/mysql-connector-j
# License: https://github.com/mysql/mysql-connector-j/blob/release/8.0/LICENSE
# Homepage: https://dev.mysql.com/doc/connector-j/8.0/en/
#
# If you choose to build a Docker image containing this connector, ensure you
# are aware and in compliance with the license under which the MySQL JDBC connector
# is provided.
#
# This file is provided as an example only.
# -----------------------------------------------------------------------------
#
# Build:
# > docker build -t fusionauth/fusionauth-app-mysql:1.54.0 .
# > docker build -t fusionauth/fusionauth-app-mysql:latest .
#
# Run:
# > docker run -p 9011:9011 -it fusionauth/fusionauth-app-mysql
#
FROM fusionauth/fusionauth-app:1.54.0
ADD --chown=fusionauth:fusionauth https://search.maven.org/remotecontent?filepath=com/mysql/mysql-connector-j/9.0.0/mysql-connector-j-9.0.0.jar /usr/local/fusionauth/fusionauth-app/lib