# 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.

Difficulty: Beginner\
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

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.

> **Warning**
>
> Portainer manages Docker through the Docker socket (`/var/run/docker.sock`). Docker's security documentation says that only trusted users should control the Docker daemon, and membership of the `docker` group already grants root-level privileges on the host. Anyone who signs in to Portainer as an administrator can therefore take over the server. Keep the interface private and protect it with a long, unique password.

## 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](/guides/install-docker-ubuntu) or [Install Docker on Debian](/guides/install-docker-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](/guides/secure-a-new-linux-server) and [Set up SSH keys](/guides/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](/guides/caddy-reverse-proxy).

| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| CPU | Not published | 1 vCPU for Portainer itself |
| Memory | Not published | 1 GB free for Portainer itself |
| Disk | Persistent storage for the `portainer_data` volume; SSD-class storage recommended | 5 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`.

> **Note**
>
> A new Portainer instance only waits **5 minutes** for its first administrator to be created. After that it shuts the setup down for security reasons. Continue with Step 3 straight away; if you miss the window, the first troubleshooting entry shows how to reopen it.

## 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](/guides/nginx-reverse-proxy-certbot) or [Traefik](/guides/traefik-reverse-proxy) for those setups.

> **Warning**
>
> Do not switch on **Force HTTPS only** in Portainer's settings while Caddy uses port 9000. That setting disables port 9000, and the proxy would return errors until you turn it off again.

## 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.

> **Danger**
>
> The next commands delete the current Portainer data volume. Make sure the archive you restore from is complete.

```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

- Learn the file format that most app guides use: [Docker Compose basics](/guides/docker-compose-basics).
- Put more apps behind HTTPS with [Caddy](/guides/caddy-reverse-proxy).
- Compare servers for container management on the [Portainer hosting](/portainer-hosting) and [Docker hosting](/docker-hosting) pages.
- Read the official [Portainer documentation](https://docs.portainer.io/) for users, teams, stacks and environments.

## 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.

---

Source: <https://hyperdc.com/guides/tutorials/install-portainer>\
Updated: 2026-10-09
