Skip to content
appsgit

Deploy guide

How to self-host Portainer with Docker Compose

Portainer Docker Compose setup in 10 minutes: the official LTS image, setup token and admin user, safe port binding, HTTPS, backups and upgrades for CE.

  • Updated
  • Beginner
  • About 10 minutes

You will need

  • 1 vCPU / 512 MB RAM
  • Docker + Docker Compose v2, running as root
  • SSH access to the server
  • A domain name (optional, for HTTPS)

What is Portainer?

Portainer is a web interface for managing Docker, Docker Swarm, Podman and Kubernetes. Instead of typing docker commands over SSH, you see every container, image, volume and network on a dashboard, read logs, open a console, and deploy Compose stacks from a browser or a Git repository. Portainer Community Edition (CE) is open source under the zlib license and is one of the most popular first apps on a new home server.

Requirements

  • Any Linux server with Docker Engine and Docker Compose v2. Portainer itself needs very little: 1 vCPU and 512 MB of RAM are plenty.
  • Docker running as root, which is the default install. The Portainer docs list SELinux as a known issue; if it is enforcing on your host you need to run the container with privileged: true.
  • SSH access, so you can read the setup token from the logs.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed from the official Docker Engine guide. Check that docker compose version prints v2, then create a folder:

mkdir -p ~/portainer && cd ~/portainer

Step 2: Create the Docker Compose file

Portainer is a single container. It needs the Docker socket to manage the host and a volume for its own database. Save this as docker-compose.yml:

services:
  portainer:
    image: portainer/portainer-ce:lts
    container_name: portainer
    restart: always
    ports:
      - "127.0.0.1:9443:9443"
      # Only needed if you connect Edge Agents:
      # - "8000:8000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

volumes:
  portainer_data:

The lts tag is the long-term-support channel the official docs use. The sts (short-term support) tag gets new features first, while lts changes less often, which makes it the sane choice for a server you do not want to babysit.

The port is bound to 127.0.0.1 on purpose. Portainer has full control over Docker, which means full control over the host, so its login page should not face the internet. Docker-published ports bypass ufw, so a firewall rule alone would not protect a port published on 0.0.0.0. You reach the localhost-only port through an SSH tunnel now and through a reverse proxy in Step 4.

Step 3: Start and open the app

docker compose up -d
docker compose logs portainer | grep setup_token

Copy the token value. From your laptop, open a tunnel:

ssh -L 9443:127.0.0.1:9443 user@YOUR_SERVER_IP

Now browse to https://localhost:9443 and accept the self-signed certificate warning. Paste the setup token, then create the admin user with a password of at least 12 characters. You have 5 minutes from container start to do this; after that Portainer locks the setup for security and you need to restart the container and fetch a fresh token.

On the next screen choose Get Started to manage the local Docker environment. You can now browse containers, open logs and deploy a stack under Stacks, Add stack.

Step 4: Put it behind HTTPS

If you want to reach Portainer without an SSH tunnel, put it behind a reverse proxy with a real certificate. With Caddy on the host:

portainer.example.com {
    reverse_proxy https://127.0.0.1:9443 {
        transport http {
            tls_insecure_skip_verify
        }
    }
}

The tls_insecure_skip_verify line is acceptable here because the hop is local to the server and Portainer uses a self-signed certificate on 9443. Caddy fetches a public Let's Encrypt certificate for the domain. Consider restricting the site to your own IP addresses or a VPN such as Tailscale, because an exposed Docker admin panel is a high-value target.

Backups and upgrades

Portainer's settings, users, stacks and endpoints live in the portainer_data volume. Back it up with:

docker run --rm -v portainer_data:/data -v "$PWD":/backup alpine \
  tar czf /backup/portainer-$(date +%F).tgz -C /data .

Portainer also has a built-in backup under Settings, Backup configuration, which can encrypt the archive with a password. To upgrade:

docker compose pull && docker compose up -d

Troubleshooting

  • "Your Portainer instance timed out for security purposes": you missed the 5-minute window. Run docker compose restart portainer, grab the new token and finish setup immediately.
  • Permission denied on the Docker socket: SELinux or a rootless Docker install is blocking access. Run Docker as root or add privileged: true on SELinux hosts.
  • Browser refuses the certificate: expected on 9443. Accept the self-signed certificate, or use the Caddy setup above for a trusted one.
  • Stacks created outside Portainer show "Limited" control: Portainer can list them but does not own their Compose files. Recreate them as Portainer stacks if you want to edit them in the UI.

Next steps

Deploy your next app as a Portainer stack from a Git repository so updates are one click, set up user accounts and teams, and add more servers through the Portainer Agent. Turn on the built-in scheduled backup to S3 if you use Business Edition.

Spotted something out of date? Tell us and we will update the guide.

FAQ

Portainer questions

Still curious? Email info@appsgit.com.

What port does Portainer use?

Portainer CE serves its web UI over HTTPS on port 9443 with a self-signed certificate. Port 8000 is only needed for the TCP tunnel used by Edge Agents, and port 9000 is an optional legacy HTTP port you have to publish yourself.

What is the default Portainer login?

There is no default password. On first start you create the admin user in the browser, and the password must be at least 12 characters. New installs also ask for a setup token, which you find in the container logs on the line containing setup_token=.

Why does Portainer say the instance timed out for security purposes?

The admin user must be created within 5 minutes of the container starting. If you miss the window, restart the container with docker compose restart portainer, read the new setup token from the logs and finish the setup straight away.

Is Portainer free?

Portainer Community Edition is free and open source under the zlib license. Portainer Business Edition adds features such as role-based access control and registry management, and Portainer offers it free for your first three nodes, one license per organisation.

Portainer CE vs Business Edition: which do I need?

For a homelab or a single server, CE covers stacks, containers, images, volumes and networks. Business Edition matters when several people need fine-grained permissions, audit logs or central management of many environments.

Can Portainer deploy Docker Compose stacks?

Yes. In Portainer, a stack is a Compose file. You can paste one into the web editor, upload a file or point Portainer at a Git repository, and it runs docker compose for you on the selected environment.