If you run more than a handful of Docker containers, the command line starts to feel cramped. Portainer gives you a clean web dashboard for everything Docker: containers, images, networks, volumes, and Compose stacks, all manageable with clicks instead of memorized flags. In this guide you will install Portainer CE on Ubuntu 24.04, expose it securely over HTTPS, and deploy your first stack — in about 10 minutes.
Why Portainer instead of just the Docker CLI?
The Docker CLI is powerful, but it assumes you remember every flag and container ID. Portainer earns its place when:
- You manage many containers across several servers and want one screen instead of ten SSH sessions.
- Non-terminal users (a teammate, a client) need to restart a service or read logs without learning Docker commands.
- You deploy Compose stacks often — pasting a YAML file into the web editor and hitting "Deploy" is faster than
scp-ing files around and runningdocker compose upmanually. - You want visibility: live CPU/memory graphs per container, log tails, and image vulnerability overviews, all without extra tooling.
Portainer CE is free and open source; the paid Business Edition adds SSO, registries governance, and advanced RBAC — none of which a small team needs to get started.
Prerequisites
- An Ubuntu 22.04 or 24.04 server (a VPS or local VM) with sudo access
- Docker Engine installed (Step 1 below covers it if you do not have it)
- Ports 9443 (Portainer HTTPS UI) and 8000 (Edge agent) reachable on your server
Step 1 — Install Docker Engine (skip if already installed)
Portainer itself runs as a Docker container, so Docker has to exist first. Check with:
docker --version
If that errors out, install Docker from the official repository:
sudo apt update && sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
This adds Docker's official APT repo (the keyring step keeps package signatures verifiable), then installs the engine, CLI, containerd runtime, and the Compose plugin. Start and enable the daemon:
sudo systemctl enable --now docker
docker --version
You should see something like Docker version 27.x.x.
Step 2 — Create a persistent data volume
Portainer stores all its data (users, settings, stack definitions) in a Docker volume. Creating it first keeps your dashboard data safe across container recreations:
docker volume create portainer_data
This creates a named volume called portainer_data. Even if you delete and re-run the Portainer container later (for example to upgrade), mounting this same volume restores everything.
Step 3 — Run the Portainer container
Now launch Portainer CE (Community Edition — free) as a long-running container:
docker run -d \
-p 8000:8000 -p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:lts
What each flag does:
-druns the container in the background.-p 9443:9443exposes the HTTPS web UI on port 9443.-p 8000:8000exposes the Edge agent tunnel port (used when managing remote hosts).--restart=alwaysbrings Portainer back up automatically after a server reboot.-v /var/run/docker.sock:/var/run/docker.sockgives Portainer access to your local Docker daemon — this is how it lists and controls containers.portainer/portainer-ce:ltsis the official Long-Term-Support image tag.
Verify the container is healthy:
docker ps --filter name=portainer
The STATUS column should show Up.
Step 4 — Open the firewall
If you use UFW, allow the two Portainer ports:
sudo ufw allow 9443/tcp
sudo ufw allow 8000/tcp
sudo ufw status
If your server sits behind a cloud security group (AWS, DigitalOcean, etc.), allow inbound TCP on 9443 (and 8000) there too.
Step 5 — Create the admin account
Open https://YOUR_SERVER_IP:9443 in a browser. You will see a certificate warning — this is expected, because Portainer generates a self-signed certificate on first start. In Chrome click "Advanced" then "Proceed", or the equivalent in your browser.
Portainer shows a "Create the first administrator user" screen. Important: this screen is only available for the first 5 minutes after the container starts. Pick a strong password and create the admin user. If the timeout already passed and the screen is gone, simply restart the container and reload the page:
docker restart portainer
This restarts the 5-minute window without losing anything.
Step 6 — Connect to your local Docker environment
After logging in, Portainer asks which environment to manage. Choose "Get Started" — this connects to the local Docker daemon on the same server via the socket you mounted in Step 3. No agent installation is needed for the local host.
You land on the Home page showing one environment ("local") with live counts of containers, images, volumes, and networks. Click it to open the dashboard.
Step 7 — Tour the dashboard and deploy a test stack
Click through the left sidebar to see what Portainer manages:
- Containers — start, stop, restart, inspect, open a console, and tail logs of every container. The stats view shows live CPU, memory, and network graphs.
- Images — pull from Docker Hub or private registries, retag, and prune unused images to reclaim disk space.
- Networks & Volumes — create and inspect Docker networks and named volumes without touching
docker networkordocker volume. - Stacks — deploy and manage full Compose applications. Editing a stack's YAML in the web editor and redeploying takes seconds.
- Registries — connect Docker Hub, GitHub Container Registry, or a private registry once, then pull images through the UI.
Try deploying a stack: go to Stacks → Add stack, name it hello-nginx, choose the Web editor method, and paste this Compose file:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
restart: unless-stopped
Click Deploy the stack. Portainer pulls the image and starts the container. Now confirm it from the terminal:
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080
A 200 response means your Portainer-managed stack is serving traffic. You can watch its logs and resource stats live under Containers → hello-nginx_web-1.
Next steps: manage remote hosts with the Portainer Agent
One Portainer instance can manage many Docker hosts. On each remote server, run the Portainer Agent container:
docker run -d \
-p 9001:9001 \
--name portainer_agent \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
portainer/agent:lts
Then in Portainer go to Environments → Add environment → Docker Standalone → Agent, enter the remote host's IP with port 9001, and give it a name. The remote host appears alongside "local" on the Home page, and you manage its containers exactly the same way. For Docker Swarm or Kubernetes clusters, Portainer supports those environment types too — one dashboard for the whole fleet.
Verify it worked
docker psshowsportainer(andhello-nginx_web-1) as Up.https://YOUR_SERVER_IP:9443loads the Portainer login/dashboard.- The Home page shows live container/image/network counts, and the stack list contains
hello-nginx.
Common issues & fixes
1. "Your session has expired" / no admin-creation screen.
The 5-minute admin setup window passed. Fix: docker restart portainer, then reload the page within 5 minutes.
2. Port 9443 connection refused.
Either the container is not running (docker ps -a to check, docker start portainer to start) or a firewall/security group is blocking the port. Re-run the UFW commands from Step 4.
3. Browser warns about the certificate.
Normal — Portainer uses a self-signed certificate by default. For production, upload your own trusted certificate under Settings → SSL Certificate in the UI.
4. Cannot see containers owned by another user.
The Docker socket is root-owned. Either run Portainer as root (default) or add your shell user to the docker group: sudo usermod -aG docker $USER, then log out and back in.
5. Upgrading Portainer loses nothing?
Correct — as long as you keep the portainer_data volume. Upgrade with: docker stop portainer && docker rm portainer && docker pull portainer/portainer-ce:lts, then re-run the exact docker run command from Step 3.
Conclusion
You now have Portainer CE running on Ubuntu with a persistent data volume, HTTPS access, and your first Compose stack deployed from the web UI. From here you can manage remote Docker hosts with the Portainer Agent, set up user teams, and schedule container updates — all from the same dashboard.
Setting up Docker tooling, reverse proxies, or full server stacks — and would rather have an expert do it? XpertBees handles end-to-end server setup and DevOps for teams of every size.



