Dockerising Flutter Web app with dockerised Flutter build and Nginx
Flutter Web app build and host with Docker containers
Several examples of Dockerfiles for building and hosting Flutter web apps, Ubuntu-based Flutter Build image + Webapp image on Nginx.
All-in-one Dockerfile
Typical Dockerfile for building Flutter webapps might look like the one blow.
It uses ubuntu:latest
as a base build image, installs Flutter, builds the webapp, and copies it to the nginx:alpine
image.
The resulting image of the hosted on nginx webapp would be a bit more then 73 MB, thanks to nginx:alpine’s size of 48.2MB.
FROM ubuntu:latest AS builder
# Install dependencies
RUN apt-get update && apt-get install -y \
curl \
git \
unzip \
xz-utils \
zip \
libglu1-mesa
# Install Flutter
RUN git clone https://github.com/flutter/flutter.git /flutter
ENV PATH="/flutter/bin:${PATH}"
RUN flutter doctor
RUN flutter channel stable
RUN flutter upgrade
# Add build argument
ARG MY_MEGA_API_URL
ENV MY_MEGA_API_URL=${MY_MEGA_API_URL}
# Copy app source
WORKDIR /app
COPY . .
# Get app dependencies
RUN flutter pub get
# Clean any existing builds and build for web
RUN flutter clean
RUN flutter build web --release --verbose --dart-define=MY_MEGA_API_URL=${MY_MEGA_API_URL}
# Stage 2 - Create the final image with nginx to serve the static files
FROM nginx:alpine
# Copy the build from the builder stage
COPY --from=builder /app/build/web /usr/share/nginx/html
# Copy nginx configuration
RUN echo 'server { \
listen 80; \
server_name localhost; \
root /usr/share/nginx/html; \
index index.html; \
\
# Handle static assets with proper MIME types \
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|json)$ { \
expires 1y; \
add_header Cache-Control "public, immutable"; \
try_files $uri =404; \
} \
\
# Handle Flutter web routing \
location / { \
try_files $uri $uri/ @fallback; \
} \
\
location @fallback { \
rewrite ^.*$ /index.html last; \
} \
\
# Security headers \
add_header X-Frame-Options "SAMEORIGIN" always; \
add_header X-Content-Type-Options "nosniff" always; \
add_header X-XSS-Protection "1; mode=block" always; \
}' > /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Start Nginx
CMD ["nginx", "-g", "daemon off;"]
Dockerised Flutter
But if you have several Flutter web apps you are working on those temborary files for intermediate build image would eat up some of your disk space. It makes sense to create a single image for flutter build and reuse it across the projects. Here the one below takes 3.47GB on my PC only once.
Here is a simple Dockerfile for Flutter build image. Save it as a Dockerfile.flutter
.
FROM ubuntu:latest AS builder
# Install dependencies
RUN apt-get update && apt-get install -y \
curl \
git \
unzip \
xz-utils \
zip \
libglu1-mesa
# Install Flutter
RUN git clone https://github.com/flutter/flutter.git /flutter
ENV PATH="/flutter/bin:${PATH}"
RUN flutter doctor
RUN flutter channel stable
RUN flutter upgrade
Let’s build it with
docker build -f Dockerfile.flutter -t rg-flutter:1.0 .
Flutter Web App Simplified Dockerfile
FROM rg-flutter:1.0 AS builder
# Add build argument
ARG MY_MEGA_API_URL
ENV MY_MEGA_API_URL=${MY_MEGA_API_URL}
# Copy app source
WORKDIR /app
COPY . .
# Get app dependencies
RUN flutter pub get
# Clean any existing builds and build for web
RUN flutter clean
RUN flutter build web --release --verbose --dart-define=MY_MEGA_API_URL=${MY_MEGA_API_URL}
# Stage 2 - Create the final image with nginx to serve the static files
FROM nginx:alpine
# Copy the build from the builder stage
COPY --from=builder /app/build/web /usr/share/nginx/html
# Copy nginx configuration
RUN echo 'server { \
listen 80; \
server_name localhost; \
root /usr/share/nginx/html; \
index index.html; \
\
# Handle static assets with proper MIME types \
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|json)$ { \
expires 1y; \
add_header Cache-Control "public, immutable"; \
try_files $uri =404; \
} \
\
# Handle Flutter web routing \
location / { \
try_files $uri $uri/ @fallback; \
} \
\
location @fallback { \
rewrite ^.*$ /index.html last; \
} \
\
# Security headers \
add_header X-Frame-Options "SAMEORIGIN" always; \
add_header X-Content-Type-Options "nosniff" always; \
add_header X-XSS-Protection "1; mode=block" always; \
}' > /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Start Nginx
CMD ["nginx", "-g", "daemon off;"]