Quantity has a quality of its own, Joseph Stalin.
Portainer is a container management platform that provides a user-friendly interface for deploying, managing, and monitoring containerized applications —especially those running on Docker or Kubernetes.
Portainer lets you:
In this guide, we’ll walk through:
sudo apt update && sudo apt upgrade -y
sudo reboot
Docker allows us to run applications in isolated containers.
# Install prerequisites
sudo apt update
sudo apt install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# Add Docker’s official GPG key and repo (optional if using get.docker.com).
# Using Docker’s official repo ensures the latest stable Docker CE.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli containerd.io
# Manage Docker as a non-root user
# Create a new user
adduser nmaximo7
# Add user nmaximo7 to the sudo and docker groups
sudo usermod -aG docker,sudo nmaximo7
# Log in to the docker group
newgrp docker
# Verify:
id nmaximo7
uid=1000(nmaximo7) gid=1000(nmaximo7) groups=1000(nmaximo7),27(sudo),100(users),990(docker)
docker version
root@ubuntu-vpn:~# docker version
Client: Docker Engine - Community
Version: 28.2.2
API version: 1.50
Go version: go1.24.3
Git commit: e6534b4
Built: Fri May 30 12:08:34 2025
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
[...]
root@ubuntu-vpn:~# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
[...]
Hello from Docker!
[...]
Portainer is a lightweight management UI for Docker that simplifies the management of Docker environments. It provides a user-friendly interface to visualize and manage containers, networks, and volumes.
Key Features:
Installation Steps
# 1. First, pull the latest version of the Portainer CE (Community Edition) image:
sudo docker pull portainer/portainer-ce:latest
# 2. Create a persistent volume where data will be permanently stored:
docker volume create portainer_data
# 2. Run the Portainer Container with the following command.
sudo docker run -d \
-p 9000:9000 \ # Map port 9000 on the host to port 9000 in the container
--name=portainer \ # Name the container "portainer" for easy management
--restart=always \ # Automatically restart the container if it stops unexpectedly
- v /var/run/docker.sock:/var/run/docker.sock \ # Allow Portainer to communicate with the Docker daemon
-v portainer_data:/data \ # Persist Portainer data in a Docker volume
portainer/portainer-ce:latest # Use the latest Portainer CE image
Access the Portainer UI. Open your favorite browser and type the following: https://your-host-ip:9000
. You will come across a security warning informing you that the connection is not private: Advanced, Proceed to [server IP address].
Create your first user. Upon launching Portainer’s web interface, you will need to create an admin account. You’ll need to choose a username and a strong password (at least 12 characters). Then click Create user to create the user.
Connect to your local environment. The installation process will automatically detect your local Docker environment. Click Get Started" to proceed with your local portainer and begin managing your Docker containers and services.
Local Dashboard. Selecting local will take you to the Portainer dashboard, where you can manage various aspects of your Docker environment, including:
Portainer is a powerful web-based management interface for Docker environments that simplifies deploying applications. One of its most valuable features is the Stacks functionality, which wraps around Docker Compose to provide an intuitive way to deploy multi-container applications.
A stack is a collection of one or more containers that work together to form a complete application. It could consist of a frontend user interface, backend api services, database servers, caching layers and/or load balancers.
This section demonstrates how to deploy a simple Nginx web server using the Docker compose functionality.
Open your web browser and access your Portainer instance (typically http://your-server-ip:9000).
Head over to the left sidebar, click on Stacks.
Choose Deployment Method: Portainer offers four deployment options: Web editor (Write/paste Docker Compose directly in the browser), Upload (Upload a docker-compose.yml file), Git repository (Deploy from a Git repository), and Custom template (Use predefined templates). For this tutorial, we’ll use the Web editor option for maximum flexibility.
In our case, we will deploy a basic Nginx web server using the web editor. Here is a Docker compose file you can use.
services:
nginx:
image: nginx:latest # Use the latest Nginx image from Docker Hub
container_name: my-blog # Name the container "my-blog"
ports:
- "8080:80" # Map port 8080 on the host to port 80 in the container
volumes:
- /var/www/html:/usr/share/nginx/html # Mount the host directory for serving HTML files
restart: always # Always restart the container unless it is stopped manually
healthcheck: # Configure a health check for the container
test: ["CMD", "curl", "-f", "http://localhost:80/"] # Check if the Nginx server is responding
interval: 30s # Check every 30 seconds
timeout: 10s # Time out after 10 seconds if there's no response
retries: 3 # Retry 3 times before marking the container as unhealthy
start_period: 40s # Wait 40 seconds before starting health checks after container starts
Next, scroll down and toggle off the Enable access control option to make the application publicly available or on if you want to restrict access to specific users or teams. Then, smash the Deploy the stack button. Your newly created stack will appear in the Stacks list section.
# Create the web root directory
sudo mkdir -p /var/www/html
# Set proper permissions
sudo chown -R 1000:1000 /var/www/html
sudo chown -R root:root /var/www/nginx
# Navigate to web root
cd /var/www/html
# Create main index.html
sudo nvim index.html
# Test local access
curl http://localhost:8080
# Test from another machine
curl http://your-server-ip:8080
# Check health status
docker exec my-blog-nginx nginx -t
Next, navigate to the web root directory on your Docker host: cd /var/www/html/
. Create an index.html file: sudo nano index.html. Next, visit your host’s IP address on port 8080.
WordPress is a free and open-source content management system written in PHP and paired with a MySQL or MariaDB database. Here’s a step-by-step guide to deploy WordPress using Docker Compose in Portainer:
Open your web browser, navigate to [http://] + your-server-ip + [:9000]
, and log in to Portainer.
In the left sidebar, go to Stacks, Add stack.
Configure Stack. Name: enter a name (e.g., mywordpress). Build Method: Portainer offers four deployment options: Web editor, Upload, Git repository (Deploy from a Git repository), and Custom template (Use predefined templates). Select Web editor
.
Copy and paste the YAML below into the editor:
version: '3.8' # Specify the version of the Docker Compose file format
services:
db: # Define the MySQL database service
image: mysql:8.0 # Use the MySQL 8.0 Docker image
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # Set the root password for MySQL
- MYSQL_DATABASE=${MYSQL_DATABASE} # Name of the database to create
- MYSQL_USER=${MYSQL_USER} # MySQL user to create
- MYSQL_PASSWORD=${MYSQL_PASSWORD} # Password for the MySQL user
volumes:
- db:/var/lib/mysql # Persist MySQL data in a Docker volume
restart: unless-stopped # Restart the container unless stopped manually
wordpress: # Define the WordPress service
image: wordpress:latest # Use the latest WordPress Docker image
ports:
- 8880:80 # Map port 8880 on the host to port 80 on the container
# If port 8880 is in use, change the left-side port in the Compose file (e.g., 8080:80).
environment:
- WORDPRESS_DB_HOST=db # Specify the database host
- WORDPRESS_DB_USER=${MYSQL_USER} # MySQL user for WordPress
- WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD} # Password for the MySQL user
- WORDPRESS_DB_NAME=${MYSQL_DATABASE} # Database name for WordPress
depends_on:
- db # Ensure the database service starts before WordPress
restart: unless-stopped # Restart the container unless stopped manually
volumes:
db: # Define a persistent volume for the MySQL database
# A volume is an abstraction of a file system that is available to applications.
To delete a volume in Portainer, first navigate to the Volumes section, select the volume(s) you wish to remove (e.g., mywordpress_db), and then click Remove. Volumes must be unused (not attached to a container or other resource) before they can be deleted. You may want to inspect a volume. portainer.io provides detailed information about it, including its name, size, and usage.
Set Environment Variables. Under Environment variables, click Add an environment variable (these are necessary variables for the containers you deploy). Define these 4 values: MYSQL_ROOT_PASSWORD (MySQL root user password, set it to a strong unique password), MYSQL_DATABASE (WordPress database name, e.g., wordpress), MYSQL_USER (MySQL user for WordPress, e.g., wordpress or wp_user), and MYSQL_PASSWORD (Password for the WordPress user).
Deploy the Stack. Scroll down and toggle off the Enable access control option to make the application publicly available. Then, smash the Deploy the stack button. Your newly created stack will appear in the Stacks list section.
Post-Deployment. Visit [http://] + your-server-ip + [:8880]
in your browser to complete WordPress setup. In Portainer, go to Stacks, your stack (e.g., mywordpress), Containers to check if both containers (mywordpress-db and mywordpress-wordpress) are running.