Managing containers may not be easy for you, especially if you run Kubernetes or minikube. This is where Portainer can come in handy.
Portainer is the most popular container management platform in the world with over 1 million users.
For homelab and self-hosting enthusiasts like myself, Portainer is a must-have app and a key service in my Docker media server.
It makes managing docker containers, setting up stacks, or even destroying them a breeze. You can even use Docker Compose inside Portainer. It allows you to write YAML files and add manifests for Docker applications. You can deploy, configure, troubleshoot, and secure Docker images with Portainer more easily within a user interface.
Portainer is the top app in our list of best Docker containers.
In this guide, I will present a Portainer Docker-Compose file that I use in all of my stacks.
First, a few frequently asked questions before we setup Portainer using Docker-Compose.
Can I use Docker Compose in Portainer?
Yes, Portainer allows users to manage Docker Compose files directly from the user interface. Users can easily deploy and manage Docker Compose services using Portainer’s web-based interface.
What version of Docker Compose does Portainer use?
The version of Docker Compose used by Portainer depends on the version of Docker installed on the host machine. Portainer is compatible with all versions of Docker Compose, from version 1 to the latest version.
What is the difference between Docker Compose and Portainer?
Docker Compose is a tool for defining, deploying, and running multi-container Docker applications. Portainer, on the other hand, is a management tool for Docker environments. It provides a user-friendly interface for managing Docker containers, images, volumes, and networks.
Should I use Portainer with Docker?
Yes, using Portainer with Docker can make it easier to manage your Docker environments (even multiple), particularly if you have multiple Docker environments to manage. Portainer provides a user-friendly interface that simplifies the management of Docker containers, images, volumes, and networks.
Portainer Docker Compose Setup
Whether you run a network using Swarm or Nomad or have a lot of containers from experimentation, Portainer is the most popular container manager for Docker images. It can run on any cluster. It can run as Linux container or Windows native container.
In this Portainer docker install guide, we will use the free Community Edition. Even though it is free, it still is a very powerful way to manage containers, images, volumes, networks, and more.
We have previously shown how to install Portainer using the docker run accommand. But, having used Docker for over 5 years (and being a person of non-IT background), I strongly suggest you take the time to learn Docker compose and build your stack using it.
Docker Compose gives you portability between systems. I can use the docker-compose files from my GitHub repo in my Ubuntu Server on Proxmox, my Ubuntu Server VPS on Digital Ocean, or even my Synology NAS and they will work the same.
1. Prepare to Setup Portainer Using Docker
First, let us start with some requirements. I won’t go into a lot of details as these have been covered in detail in my Docker Media Server guide. Here is a summary of the requirements before Proceeding.
Setting Up The Docker Environment
This is also explained in detail in my Docker Guide. We are going to customize a few things with Docker before building the Portainer Docker Compose file.
First, is the folder structure. I like to house all of the docker-related files and folders in one location. I call it the Docker Root Folder. Our docker-compose.yml, .env files, etc. will be located in this folder, as shown below.
In addition, all of Portainer’s data will go into the appdata/portianer folder. For this guide, you do not need to worry about the remaining folders in the above screenshot.
Create the .env file
First, the dot in front of env is not a typo.
It is a hidden file that will store some of the key information we may use (environmental variables) repeatedly. In the docker root folder (explained above), create the .env file and add the following contents to it.
Customizing the above variables is explained in detail in my Docker guide, along with the right permissions to set (very important!).
In short, TZ is the timezone, and DOCKERDIR is the docker root folder mentioned above.
In addition, replace anand with your username.
2. Create the Base Portainer Docker Compose File
Before we go ahead and add the Docker Compose for Portainer, we will have to add a few basic elements to the compose file. Once again, this is all explained in detail in my Docker tutorial. But here is a summary of it.
Note that spacing and indentation are crucial in YAML files. Therefore, pay attention to the formatting when you copy-paste and customize the Portainer Docker Compose snippet.
In your Docker Compose file, if you do not already have it, add the following:
version: "3.9" ########################### NETWORKS networks: default: driver: bridge ########################### SERVICES services:
We are specifying the version of Docker Compose reference to use and the default Docker bridge network. If you do not know what these are, do not worry.
We are going to make Portainer accessible using the Docker Host machine’s IP, using Portainer’s default port (e.g. http://22.214.171.124:9000). For this purpose, the above network block is sufficient.
3. Docker Compose for Portainer
Here is the Docker-Compose for Portainer that I use. Add it it right under services (pay attention to indentation):
# Portainer - WebUI for Containers portainer: container_name: portainer image: portainer/portainer-ce:latest restart: unless-stopped networks: - default command: -H unix:///var/run/docker.sock ports: - "9000:9000" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - $DOCKERDIR/appdata/portainer/data:/data environment: - TZ=$TZ
Customizing Portainer Docker Setup
Here are some notes to understand and customize the above Portainer docker-compose example:
- We are using latest portainer/portainer-ce docker image.
- Portainer will belong to the “default” network. This is fine for now. For advanced configurations, keep reading.
- In the ports section, we are exposing port 9000 to the host, which is the default Portainer port. Therefore, Portainer will be available on the Docker host IP at port 9000. For example, my Docker host has an IP of 192.168.1.211. So Portainer will be available at http://192.168.1.211:9000.
- Under volumes, we are mapping a persistent volume for Portainer to store its data. Make sure $DOCKERDIR is defined in .env file.
- In the volumes section we are also passing the Docker socket from the host machine to Portainer container. This is a minor security risk. If Portainer is compromised then the attacker could gain control of the host system. Although not urgent, once you have your stack well established, I strongly recommend using Socket Proxy as described in my Docker best security practices article.
- Finally, also ensure that variable $TZ is defined in the .env file.
In the above Portainer Docker Compose file, we set the network as default. This is fine.
Alternatively, you can specify the Portainer Docker container to use the host network. In this case, Portainer functions as if it were running natively on your host system. This requires all necessary ports to be free (e.g. 9000). To enable host networking, use the following block instead of networks:
In addition, you will also need to remove the ports section. Portainer should be available at http://192.168.1.211:9000, which is the same URL as the default Portainer docker compose setup shown previously.
4. Start Portainer
After customizing the Portainer Docker Compose file, you can start Portainer using the following command:
sudo docker compose -f ~/docker/docker-compose.yml up -d
Be sure to refer to my Docker guide to understand how you can follow the logs to check the start-up of the Portainer docker container. You may use Dozzle logs viewer for real-time logs viewing.
If all goes well, in a few minutes you should be to access Portainer using one of the URLs listed previously.
5. Accessing Portainer Over The Internet
Accessing Portainer from within your home network should work fine (described above). But what if you want access to Portainer on the go from outside your home network?
Well, there are many ways to do this.
The easiest and NOT RECOMMENDED way to do this is to forward port 9000 on your router/gateway to point to your Portainer servers IP address.
Accessing Portainer with VPN
A secure way to access Portainer is to connect to your home network using a VPN service. Home routers and network-attached storage devices sometimes come with a built-in VPN server. Once connected, you can use the same home network IP address of your Portainer Docker server.
You may also use a third-party VPN mesh network such as Tailscale or Zerotier-One. I use ZeroTier to tie all my key machines together in a virtual network. My Docker host is part of this network. Therefore, while on the go, I can use my Docker host’s ZeroTier network IP address with Portainer’s port number.
Another alternative is to set up your own Wireguard network. But this is a more advanced topic.
Other Posts in the Wireguard Series:
Exposing Portainer with Reverse Proxy
Another secure way to access Portainer is to put it behind a reverse proxy. But this requires a domain name or a DDNS.
Nginx Proxy Manager is very simple to setup but not very flexible.
I use and recommend Traefik. You can read all about setting it up in my Docker Traefik guide or refer to my GitHub repo.
With a reverse proxy, you can access Portainer using a nicer URL (e.g. https://portainer.example.com).
6. Securing Portainer
Portainer comes with an internal authentication (the default login page). For something as powerful as a Portainer, I highly recommend better security with multifactor authentication. This can be achieved in many ways.
This is where the power of Traefik over Nginx Proxy Manager becomes evident. You could integrate Google OAuth or Authelia Self-hosted MFA, very easily.
Alternatively, you could use Portainer’s built-in OAuth or LDAP (or Microsoft Active Directory with a Pro plan).
Once configured, you will have the option to login using internal authentication or OAuth.
Conclusions: Portainer on Docker
Portainer is one of the first apps I install while building a docker stack. It is a powerful container manager and the open-source community has been awesome in developing it fast. You cannot install it natively on the OS.
But Docker makes it much easier to install Portainer CE, and Docker Compose simplifies it even more. With the included Docker Compose for Portainer and easy steps to setup Portainer, you should be up and running in just about 5 minutes.
So if you are new to docker or just need a GUI to manage your container environment, go ahead and use the included Portainer docker-compose.