I love ZSH. I love my colorful terminal prompts, I love my indicators, I love my icons. That's all very well on my computer, but what about inside Docker containers?
Well, turns out it's actually really easy to set up ZSH in Docker, it just requires a bit of doing. This post will explain how to do just that! I'll use a non-root user because that's safer, but if you want to use
root to do everything, just ignore the user switching and permissions changing, it should all work fine.
I've set this up as a multi-stage build layer, but you can get rid of the
AS setup in the first line if you want to do something else.
TL;DR: Here's the Gist! (If you're using NodeJS, there's a special one for you here!)
Let's break that down. We start off by using the Alpine Linux image, but this should work for any Linux image, you might just need to modify
apk add to be
apt install or something else. If you're using NodeJS in Docker, use
FROM alpine:latest AS setup
Then we set the environment variable
RUNNING_IN_DOCKER to true. I do this with all my Dockerfiles just because it's sometimes really useful to be able to tell easily if a script is running in Docker or on the host (e.g. testing automatically before a commit made in the container vs through VS Code on the host).
ENV RUNNING_IN_DOCKER true
Next, we create a new unprivileged user called
main for security (using
-D to not give a password). Then we just create a a folder to put our app in, and give ownership of it to that user.
RUN adduser -D main RUN mkdir -p /app \ && chown -R main:main /app
if you're using NodeJS, don't bother creating a new user, you already have the
node user created for you by the NodeJS base image. That user also already has the setup to install packages without any extra config. Just get rid of the first line and change
After that, we install the dependencies for ZSH and then download Antigen (used for managing ZSH plugins) from GitHub.
RUN apk --no-cache add zsh curl git RUN mkdir -p /home/main/.antigen RUN curl -L git.io/antigen > /home/main/.antigen/antigen.zsh
With Antigen installed, we copy over our ZSH configuration, which I like to store in
.dockershell.sh, but it will be copied to
.zshrc in the container. I have an example configuration in this Gist if you need inspiration!
COPY .dockershell.sh /home/main/.zshrc
Then we just give the
main user ownership of both the Antigen config and
RUN chown -R main:main /home/main/.antigen /home/main/.zshrc
Now, we can actually run ZSH, which will automatically pull everything we need to fulfill our configuration! This may take some time depending on how complex your config is, but after you've done it once, it's the same for every other container that ever uses it! Also note that you will have to rebuild whenever you change your ZSH config of course. Anyway, we run ZSH as the
main user so it sets it up with the right permissions (that's the user we'll interact with the container with). After that, we switch back to
root for any remaining stages.
USER main RUN /bin/zsh /home/main/.zshrc USER root
And that'll give you ZSH in Docker! Just remember to add this when you want a prompt:
ENTRYPOINT [ "/bin/zsh" ]
Here are three Gists that might help in getting everything operational:
Thanks for reading! Happy ZSHing! 👋