-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🔐 Reduce Docker size by half + improve security #465
base: master
Are you sure you want to change the base?
Conversation
Docker Compose mount the volumes as root by default and the node user can't access the SQLite DB (read-only)
cc: @rrfaria: I closed the previous PR to provide a cleaner branch. |
…nstallation/NETWORKING.md` file
You mentioned that you fixed issue with NEXT_PUBLIC_ENV vars. It cannot be fixed, since I now provide prebuild images, the public env vars are hardcoded in the code generated by nextjs. Its not feasible to change them and changing them via a script is not a practical approach. Your PR seems good for users who want to build images locally, but in other terms even if I link the env variable, the vars would still be hardcoded. |
There is a lot of projects that are using the My last Helm chart was for the project TypeBot (PR in progress), a NextJS app with a backend and frontend. |
Details
This PR optimized the Dockerfiles (frontend + backend), significantly reducing the image size and improving security by running as a non-root user (node).
Here are the fundamental changes and explanations:
Multi-stage build: I used a two-stage build process. The first stage (builder) installs dependencies and builds the application. The second stage only copies the necessary files for running the application.
Removed ARG variables on the backend image: Since Docker Compose or Kubernetes will provide the environment variables, I removed them from the Dockerfile. We can set these variables in your Docker Compose file or Kubernetes deployment configuration.
Optimized copying and building: I first copy only the package.json and yarn.lock files, then install dependencies. This allows better caching of the dependency installation step.
Minimal production image: The final stage only copies the built assets, node_modules, and necessary files from the builder stage, resulting in a much smaller Docker image.
Use a more standard folder for the app: I replaced the
/home/perplexica
with/app
and updated thedocker-compose.yaml
file to this new path.Use a non-root user (node): Instead of using the root user by default, I changed the container user to
node
(the default user for official Node Docker images). I had to set this user's permissions on the Dockerfiles and thedocker-compose.yaml
to avoid permission issues on the SQLite DB file.Use an ARG variable for the backend image to use by default the
node
user when running on Kubernetes and theroot
user if running with Docker Compose. The Docker Compose volumes are created with theroot
user, and the SQLite DB is accessible only as read-only if running the node user.Update the Node version to Node v22 for the
frontend
andbackend
.I tried to move all the ENV vars to a shared
.env
in the root folder by providing the right syntax to the Docker Compose file, but I haven't figured out why the Frontend app still looking for its./ui/.env
file. If you have any insights, I will be happy to fix it. For now, it uses the same.env
file for the backend and frontend (I have updated the README with additional instructions).Important
The downside to running the backend Docker image as a non-root user is that Docker Compose will mount the volume as root, and the
node
user will have access to the DB only in read-only mode.Docker Compose must run only with the
--build
flag to force rebuild the Docker image with theroot
user.By default, the Docker images will be published to Docker Hub with the
node
user.We will not have this issue with the SQLite DB permissions on Kubernetes because the volumes are managed differently.
Moving to a Postgres DB will fix this issue and help scale the project later. The Docker Compose will be able to launch a Postgres image, and it will be the same for Kubernetes with a dedicated pod or managed database like AWS RDS.
You can keep the root user for the backend image if you think that is too much for simple use with the Docker Compose file, but using the non-root user (
node
) will be more secure.