Skip to content

TutorialsContainers & Docker

How to install Portainer CE on Docker and keep it private

Install Portainer CE on Docker with the official LTS image, finish setup with the setup token, keep port 9443 private, then back up and update it safely.

  • Beginner
  • 20 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Prerequisites
  2. Step 1 — Create the data volume
  3. Step 2 — Start Portainer Server
  4. Step 3 — Open Portainer through an SSH tunnel and create the administrator
  5. Step 4 — Keep the firewall closed
  6. Step 5 — Serve Portainer on your domain with HTTPS (optional)
  7. Back up and restore
  8. Update Portainer
  9. Troubleshooting
  10. Your Portainer instance has timed out for security purposes
  11. The setup page rejects the setup token
  12. Origin invalid or a login loop behind a reverse proxy
  13. The browser warns about the certificate on port 9443
  14. The local environment is missing or cannot reach Docker
  15. Port 9443 is reachable from the internet
  16. Next steps

Portainer Community Edition (CE) is a web interface for Docker. You can see and manage containers, images, volumes, networks and Compose stacks from a browser instead of the command line, which is handy when several people look after the same server. This guide installs Portainer Server with the official docker run command and the lts image, keeps its ports on the loopback address, completes the first-run setup with the setup token, and shows two safe ways to reach it: an SSH tunnel, or your own domain with HTTPS through Caddy. You then back up, update and troubleshoot the installation.

Prerequisites

  • A server running Ubuntu 26.04 LTS, Ubuntu 24.04 LTS, Debian 13 or Debian 12 with Docker Engine from Docker's own repository. Follow Install Docker on Ubuntu or Install Docker on Debian first. Portainer's documentation asks for a current Docker release running as root, warns against the snap package of Docker on Ubuntu, and notes that rootless Docker needs extra configuration. Portainer validates its current release against Docker 28.5.1 and 29.8.1 on x86_64 and ARM64.
  • A non-root user with sudo rights and SSH key login, set up as in Secure a new Linux server and Set up SSH keys. The commands below assume that this user may run docker without sudo; otherwise put sudo in front of them.
  • Optional, for Step 5: a domain name such as portainer.example.com with an A (and AAAA) record pointing at the server, and Caddy installed as described in Caddy reverse proxy.
ResourceMinimum (official)Suggested starting point
CPUNot published1 vCPU for Portainer itself
MemoryNot published1 GB free for Portainer itself
DiskPersistent storage for the portainer_data volume; SSD-class storage recommended5 GB free, more if you deploy stacks from Git

Portainer does not publish CPU or memory minimums. The right-hand column is a conservative starting point for Portainer alone, not an official or benchmarked figure. Size the server for the containers you plan to run, and keep in mind that Git-based stack deployments clone repositories into the Portainer data volume.

Step 1 — Create the data volume

Portainer stores its database, users, settings and certificates in a Docker volume. Create it with the name the official documentation uses:

Bash
docker volume create portainer_data
docker volume ls

The second command lists portainer_data. The volume survives container removal, which is what makes updates painless later.

Step 2 — Start Portainer Server

Portainer's own command publishes ports 8000 and 9443 on every address of the server. Ports published by Docker are not filtered by ufw, so this guide binds them to 127.0.0.1 instead and leaves out port 8000, which only Edge agents use:

Bash
docker run -d \
  --name portainer \
  --restart=always \
  -p 127.0.0.1:9443:9443 \
  -p 127.0.0.1:9000:9000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:lts

What the options do:

  • -p 127.0.0.1:9443:9443 publishes the HTTPS interface on the loopback address only. Portainer secures it with a self-signed certificate.
  • -p 127.0.0.1:9000:9000 publishes the plain-HTTP interface, which Portainer keeps for legacy setups, again on loopback only. Only Caddy on the same server uses it in Step 5. Leave this line out if you will always use the SSH tunnel.
  • -v /var/run/docker.sock:/var/run/docker.sock lets Portainer manage the local Docker engine.
  • portainer/portainer-ce:lts is the image and tag from Portainer's install guide. The lts tag always points at the latest Long Term Support release.

Check that the container is running:

Bash
docker ps

You should see a container named portainer with the status Up.

Step 3 — Open Portainer through an SSH tunnel and create the administrator

On your own computer, open an SSH tunnel that forwards a local port to Portainer's loopback port on the server:

Bash
ssh -L 9443:127.0.0.1:9443 user@203.0.113.10

Leave that session open and browse to https://localhost:9443. Your browser warns about the self-signed certificate; that is expected for this local connection.

Since Portainer 2.43, a new instance also asks for a setup token, so that nobody else can claim a freshly started server. In your SSH session on the server, read it from the container logs:

Bash
docker logs portainer 2>&1 | grep setup_token

Copy the value after setup_token= into the Setup token field. Then create the administrator account:

  1. Change the suggested username admin to a name of your own.
  2. Enter a password of at least 12 characters, for example one generated with openssl rand -base64 24 and stored in your password manager.
  3. On the Edge Compute screen, select Skip unless you plan to manage remote Edge agents.
  4. In the environment wizard, select Get Started. Portainer detects the local Docker environment.

The home page now lists an environment called local. Open it and check that the container, image and volume counts match docker ps -a, docker images and docker volume ls.

Step 4 — Keep the firewall closed

Portainer itself needs no open ports, because it only listens on 127.0.0.1. Allow SSH, plus HTTP and HTTPS if you will use Caddy in Step 5:

Bash
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

From another machine, confirm that the Portainer ports are closed, for example with nc -vz your-server-ip 9443. The connection should be refused or time out. If you later add Edge agents, publish port 8000 and restrict it with your provider's network firewall or the DOCKER-USER chain, because ufw does not filter Docker-published ports.

Step 5 — Serve Portainer on your domain with HTTPS (optional)

An SSH tunnel is the most private option. If your team needs a normal URL, put Caddy in front of Portainer. Add this site block to /etc/caddy/Caddyfile:

Caddyfile
portainer.example.com {
    reverse_proxy 127.0.0.1:9000
}

Reload Caddy and test the new address:

Bash
sudo systemctl reload caddy
curl -I https://portainer.example.com

Caddy obtains a certificate automatically and curl prints a response from Portainer over HTTPS. The proxy talks to port 9000 because the hop never leaves the server, and because Portainer's reverse-proxy documentation requires the browser's original Host header and a matching X-Forwarded-Proto. Caddy passes Host through unchanged and sets X-Forwarded-Proto: https for a plain-HTTP upstream. With Nginx, use proxy_set_header Host $http_host; as Portainer recommends; see Nginx with Certbot or Traefik for those setups.

Back up and restore

Portainer's own data lives in the portainer_data volume. You have two complementary ways to protect it.

Built-in backup. In Portainer, open Settings, find Back up Portainer, switch on Password protect, enter a password and select Download backup. Your browser saves a tar.gz file. According to Portainer's documentation this file only contains Portainer's configuration, not containers, stacks, services or volumes.

Volume archive. For a complete copy, stop Portainer briefly and archive the volume to /opt/backups:

Bash
sudo mkdir -p /opt/backups
docker stop portainer
docker run --rm -v portainer_data:/data -v /opt/backups:/backup ubuntu tar czf /backup/portainer_data-$(date +%F).tar.gz -C /data .
docker start portainer

To restore from the built-in backup, start a fresh Portainer with an empty volume. On the initial setup page, choose Restore Portainer from backup, select the file, enter its password and the setup token from the logs, and select Restore Portainer. You then sign in with your previous credentials.

To restore a volume archive instead, remove the container, recreate the volume and unpack the archive.

Bash
docker stop portainer
docker rm portainer
docker volume rm portainer_data
docker volume create portainer_data
docker run --rm -v portainer_data:/data -v /opt/backups:/backup ubuntu tar xzf /backup/portainer_data-2026-10-09.tar.gz -C /data

Then run the command from Step 2 again. Container data is not part of either backup: back up each application's volumes and databases with the method from its own guide, and copy all backups off the server.

Update Portainer

Portainer's update procedure replaces the container and keeps the volume. Take a backup first, read the release notes, then run:

Bash
docker stop portainer
docker rm portainer
docker pull portainer/portainer-ce:lts

Start the new version with the exact docker run command from Step 2, sign in and check the version shown in the interface. Removing the container does not touch portainer_data.

About the tags: lts releases get more testing and are supported until the next LTS plus a three-month migration window (up to nine months); a new LTS is planned about every four months. sts releases ship features sooner but are only supported until the next release. In October 2026 the current CE release is 2.45 LTS. Check Portainer's lifecycle page before you plan a major version change. If you add Portainer agents later, keep them on the same version as the server.

Troubleshooting

Your Portainer instance has timed out for security purposes

Nobody created the administrator within 5 minutes of the first start, so Portainer stopped its setup. Restart the container to get a new 5-minute window:

Bash
docker stop portainer
docker start portainer

If that does not help, remove the container with docker rm -f portainer and run the Step 2 command again. If you see this message on an instance that already worked, the portainer_data volume is probably not mounted, so Portainer thinks it is a new installation.

The setup page rejects the setup token

The token must come from the logs of the container that is running now. Run docker logs portainer 2>&1 | grep setup_token again, especially after you recreated the container, and copy the whole value. For automated installs Portainer also supports the startup flags --setup-token and --admin-password, described in its setup-token FAQ.

Origin invalid or a login loop behind a reverse proxy

Portainer compares the browser's origin with the Host header it receives. Make sure your proxy forwards the original host and a correct X-Forwarded-Proto, as in Step 5. If the error remains, add your public URL as a trusted origin by recreating the container with -e TRUSTED_ORIGINS=https://portainer.example.com in the docker run command.

The browser warns about the certificate on port 9443

Portainer creates a self-signed certificate on first start, so the warning is expected when you use the SSH tunnel. Use the Caddy setup from Step 5 for a trusted certificate, or upload your own full-chain certificate under Settings in the SSL certificate section.

The local environment is missing or cannot reach Docker

Portainer manages the server through /var/run/docker.sock. Check the mount with docker inspect portainer | grep docker.sock. If it is missing, recreate the container with the Step 2 command. Rootless Docker and SELinux in enforcing mode need the extra settings described in Portainer's requirements.

Port 9443 is reachable from the internet

The container was started with Portainer's original command, which publishes on all addresses. Remove it with docker rm -f portainer and start it again with the 127.0.0.1 bindings from Step 2; your data stays in the volume.

Next steps

Frequently asked questions

Should I use the lts or the sts Portainer image tag?

Use lts on servers. Portainer’s install guide uses portainer/portainer-ce:lts; LTS releases get more testing and stay supported until the next LTS plus a three-month migration window, while sts releases bring features sooner with shorter support.

Do I need to open port 8000 for Portainer?

Only if you use Edge agents. Port 8000 is Portainer’s tunnel server for Edge Compute. A single server managed through the local Docker socket only needs the web interface, which this guide keeps on 127.0.0.1.

Where do I find the Portainer setup token?

Since Portainer 2.43, a new instance writes a one-time setup token to its logs. Run docker logs portainer, look for the line containing setup_token=, and paste the value into the setup page.

Does the Portainer backup include my containers and volumes?

No. The built-in backup only covers Portainer’s own configuration. Back up container data, volumes and databases separately, and archive the portainer_data volume if you want a full copy of Portainer itself.

Is it safe to give someone a Portainer login?

Treat Portainer administrator access like root access to the server, because Portainer controls Docker through its socket. Give other people standard user accounts, use long passwords and keep the interface off the public internet where you can.

Sources

Parooli genereerimine

Please confirm