Module 4 · Deploy the server
Module 04 of 10

Deploy the server.

The lab starts here. This module walks the decisions that shape a Portainer Management Server deployment (runtime choice, storage, dedicated vs shared, the initial admin flow), then hands you off to docs.portainer.io for the exact install commands per runtime. The docs are versioned and change; this module is the surrounding context that does not.

10 chapters Procedural Lab starts here
01

Sizing and requirements

The Portainer Management Server is deliberately lightweight because it is a control plane, not a data plane. Real production installations sit comfortably on modest resources for anything up to a couple of hundred endpoints; the biggest driver of resource consumption is agent poll frequency and snapshot volume, not user activity.

For a lab install you can get away with a small VM: two vCPUs, 2 to 4 GB RAM, 10 to 20 GB of disk on top of whatever the base OS needs, and a network interface the server can reach the agents on (or the agents can reach the server on, for edge). For a small production install (up to about 50 endpoints), plan for two to four vCPUs, 4 to 8 GB RAM, and 40 GB of disk on durable storage. Beyond that, size iteratively based on how many agents you are polling, how often, and how large your BoltDB grows; the datastore is the thing that grows over time, not the running process.

Detailed sizing guidance per fleet size, including the reference architecture recommendations (Ch2-D-04 in the Portainer Enterprise Reference Architecture), lives in the reference architecture document; treat the numbers above as a lab-friendly baseline, not a production recommendation.

In your lab

Pick one of your four VMs as the Portainer Management Server. Give it a stable hostname you can reach from the other VMs (either DNS or a reservation-based IP), open the ports you need on its firewall (9443 for HTTPS, 8000 for the edge tunnel if you plan to use edge later), and get it into a state where you can install KubeSolo on it. KubeSolo is Portainer's own single-node Kubernetes distribution and is the recommended substrate for the Management Server (Module 9 explains why: add-ons are Kubernetes-only). The rest of Module 4 uses that VM.

02

Runtime choice for the Management Server

Portainer runs on Kubernetes, Docker Standalone, or Docker Swarm. All three are supported, but the recommendation is Kubernetes; the other two are provided for customers whose existing operating model is Docker or Swarm and who are not yet ready to move.

Kubernetes (recommended) is the default answer for new deployments. Portainer installs as a Helm release; you get scheduler-managed restart, PVC-backed persistent storage, ingress for the UI, backups to S3 or Azure Blob against your existing Kubernetes IAM, and (this is the load-bearing reason) the substrate needed to install add-ons. Add-ons like Portainer-Run are Kubernetes-only, and add-ons are how Portainer extends over time; running the server on Docker leaves that extensibility on the table.

Kubernetes on a single VM: use KubeSolo. Not every environment justifies a multi-node cluster for the Management Server, and standing up a full Kubernetes distribution just to host Portainer is often overkill. KubeSolo is Portainer's own lightweight single-node Kubernetes; it gives you the same Kubernetes substrate (and therefore the same add-on capability) on one VM, without the multi-node operational overhead. For small production installs and for most lab work, KubeSolo is the correct answer.

Docker Standalone (legacy) is supported for customers who already run Docker as their operating model and are not yet moving to Kubernetes. One VM, Docker installed, one container. The downside is single-host with no scheduler-managed recovery (unless you wire up systemd or Docker's own restart policies), and the more significant downside is that add-ons cannot install on a Docker Standalone Management Server, so the deployment cannot grow into Portainer's extension model without a substrate change later.

Docker Swarm (legacy) is supported for customers with an existing Swarm operating model. You get scheduler-managed restart across a cluster of Docker hosts, but not active-active (Portainer is still single-writer BoltDB; see Module 3), and the same add-on constraint applies. Useful when you already run Swarm; not a reason to introduce Swarm.

MANAGEMENT SERVER DEPLOYMENT SHAPES Kubernetes (HA cluster) RECOMMENDED · LARGE node node node Portainer pod via Helm Helm chart · PVC storage scheduler-managed restart supports add-ons KubeSolo (single VM) RECOMMENDED · SMALL one VM KubeSolo Portainer pod via Helm Kubernetes substrate supports add-ons Docker (legacy) EXISTING OPERATING MODEL one VM Docker engine Portainer container docker run single-host · no add-ons or Swarm (multi-host)
Kubernetes (any size) is the recommended substrate. KubeSolo is the single-VM answer without the multi-node overhead. Docker is supported for existing Docker operating models; add-ons need Kubernetes.
03

Persistent storage

Everything the Portainer server needs to remember lives in the --data directory: the BoltDB, TLS material, backup archives, an embedded Prometheus TSDB subdirectory, and a few other bits of file state. Persist that directory across restarts or you lose everything.

On Kubernetes, this is a PersistentVolumeClaim, and the CSI driver providing it needs to support ReadWriteOnce and survive pod rescheduling. On KubeSolo, the same PVC model applies against KubeSolo's default storage class, backed by the local disk on the VM (durable, but not portable off that host without your own arrangement). On Docker Standalone, this is a bind mount or a named volume. On Docker Swarm, it is a named volume with a driver that can survive a node move, or a bind mount to shared storage the swarm nodes all have; the specifics depend on what shared storage your environment has.

Because Portainer is single-writer, the storage does not need to be simultaneously mounted across nodes; it needs to be durable, and it needs to be re-mountable on whichever node Portainer restarts on. A local disk on one node satisfies durability but not the re-mountability requirement; the pod cannot move. Shared block storage (an EBS volume you can detach and reattach, an Azure disk, a Longhorn volume, a Ceph RBD) satisfies both.

You can also enable datastore-at-rest encryption. Point --secret-key-name at a key file, and Portainer encrypts the BoltDB on write. If the key file goes missing between boots, the store will not open, and the error is clear enough to distinguish from a migration failure.

04

Dedicated vs shared management environment

A design decision to make early: does Portainer run on a dedicated management cluster, or does it share the cluster with the workloads it manages?

Dedicated is the reference-architecture recommendation for any real production install. A small Kubernetes cluster (or a couple of Docker hosts) whose only job is to run the management plane: Portainer, its backup targets, whatever supporting infrastructure lives with it. The workload clusters are separate; Portainer manages them as endpoints. This isolates the blast radius; a workload cluster having a bad day cannot take Portainer with it, and vice versa.

Shared (Portainer running on the same cluster it manages) is legitimate for small deployments where the operational overhead of a separate management cluster is not worth it. The tradeoff is that you have to be careful about how you deploy Portainer's own workload (dedicated node pool, resource requests that survive contention, priority class) so that it does not compete with the workloads it manages. In a lab you can share; in a real customer environment, default to dedicated.

For lab purposes, one VM running KubeSolo with Portainer on it is fine; you do not need a management cluster to learn the product, and KubeSolo gives you the Kubernetes substrate without the multi-node overhead. The point of this chapter is that when you start advising a real customer, this decision comes early and it is worth doing right.

05

Deploying on Kubernetes (recommended)

The Kubernetes install is a Helm chart. Portainer publishes the chart at docs.portainer.io and updates it in step with the release line. On a managed Kubernetes cluster (AKS, EKS, GKE, ROKS) you get PVCs backed by the cloud provider's default storage class, ingress through whatever ingress controller you have installed, and (usually) a working out-of-the-box result. On a self-managed cluster (RKE2, k3s, kubeadm, Talos) you get the same chart; you provide your own StorageClass and ingress.

The Helm values you will typically touch on first install: image tag (pin it to the LTS you are deploying, do not follow latest); service type or ingress configuration (LoadBalancer, NodePort, or Ingress with a hostname); persistence configuration (storage class, size); and any environment variables you want to bake in at boot (feature flags, log level, base URL if the server is served under a sub-path, trusted origins). Do not enable auto-patching at install time; wait until you have taken your first backup so you have a clean fallback point (Module 10 covers auto-patch properly).

On Kubernetes you also get PodSecurity to think about; Portainer's default chart values are meant to work under the Restricted PodSecurity Standard, but if your cluster runs a stricter admission profile you may need to tune the pod spec. If the pod cannot start, look at the events on the pod first, not the container logs; the failure is usually at admission, not at runtime.

On a single VM: KubeSolo

If a full Kubernetes cluster is overkill for your Management Server (small production install, lab, edge management node, small customer engagement), use KubeSolo. It is Portainer's own lightweight single-node Kubernetes; you get the Kubernetes substrate (and therefore add-on capability) on one VM without standing up a distribution. Install KubeSolo on the target VM per the current instructions in docs.portainer.io, then apply the Portainer Helm chart against the local KubeSolo cluster the same way you would against any other Kubernetes environment. The Helm values you touch are the same; the difference is storage class (KubeSolo's local-backed default) and ingress (KubeSolo's built-in ingress rather than one you install separately).

In your lab

Install KubeSolo on your Management Server VM per the current instructions in docs.portainer.io. Then install the Portainer Helm chart against that KubeSolo cluster. Do not paste in an old command from somewhere; chart values and image tags shift across LTS lines, and the docs are the source of truth. Once you can browse to the HTTPS endpoint, come back to chapter 8.

06

Deploying on Docker Standalone (legacy)

Docker Standalone is supported for customers whose operating model is Docker and who are not yet moving to Kubernetes. Add-ons will not install on a Docker Standalone Management Server; if extensibility matters (and for most customer engagements it will), plan a substrate move later.

The install is a single docker run that starts the Portainer BE container with a persistent volume mounted, the HTTPS port exposed, and (optionally) the tunnel port exposed for edge. The exact command changes across releases; consult docs.portainer.io for the current version and run that.

The shape of the command is: pull the portainer/portainer-ee image at the version you want, run it detached, mount a volume onto /data, publish port 9443 for HTTPS, publish port 8000 if you need the edge tunnel, and set a restart policy (--restart=always is a reasonable lab default; production usually uses systemd or a supervision layer).

Once the container is running, browse to https://<your-vm>:9443. You will see a self-signed certificate warning on first boot; that is expected in a lab, and Module 5 covers replacing it with a real certificate. The first request is the beginning of the initial-admin flow; chapter 8 picks up there.

07

Deploying on Docker Swarm (legacy)

Docker Swarm is supported for customers who already run Swarm as their operating model. Same add-on constraint as Standalone: Swarm cannot host add-ons, so extensibility requires a substrate move later.

The Swarm install is a Docker Compose stack you deploy with docker stack deploy. Portainer publishes a reference stack file for this on docs.portainer.io; the shape is a single Portainer service pinned to a manager node with a placement constraint, a named volume for /data, and published ports for 9443 and 8000.

Swarm requires you to think about which node Portainer runs on, because Portainer's state (the BoltDB) lives on whatever host the container schedules to. If you pin Portainer to a specific manager and that manager fails, Portainer will not restart on another node unless the persistent volume can follow. Either accept the constraint (Portainer stays on that manager, restart it manually if the host fails), or arrange for the storage to be sharable across the swarm.

A three-manager Swarm is the practical minimum for anything you would call production; a single-manager Swarm is a Standalone install with extra ceremony. If your customer is running a single-manager Swarm, they should probably be running Standalone; if they are running three managers, the constraint above matters, and picking the right node with the right storage matters.

08

Initial admin and the five-minute window

The first request to a fresh Portainer server puts you in the initial-admin flow. You have a bounded window (five minutes by default) to create the first administrator account; if you take longer than that, Portainer will refuse the setup on security grounds ("the setup token expired"), and you have to restart the container to reopen the window.

This is deliberate. An exposed Portainer with an open initial-admin flow is an unguarded management surface; five minutes is enough for a human standing at the keyboard and small enough that an accidentally-exposed server does not stay pwn-able for hours.

You can automate the initial-admin creation with --admin-password or --admin-password-file (mutually exclusive; setting both fails validation at boot). You can require a setup token with --setup-token. For a lab, the interactive flow is fine; for a production install driven by IaC, use the flags so the deployment is idempotent and does not depend on someone being there to click through.

The initial administrator is always user ID 1, and user ID 1 is always allowed to log in with local (internal) authentication regardless of what auth method you configure later. That is your escape hatch when LDAP or OAuth is misconfigured (Module 5 covers this). Losing that password locks you out; take it seriously.

09

Adding your license

Portainer Business needs a license. Add it either at boot with --license-key (or the PORTAINER_LICENSE_KEY environment variable), or through the UI after the initial admin exists.

Licenses are managed by liblicense v3. Adding one parses and validates it locally (an expired or revoked key fails immediately with a clear error), then checks in with the remote licensing server. A network-failed check-in is tolerated ("network connection failed" gets logged, not fatal); this is the deliberate air-gap-friendly path. Multiple licenses can stack: subscription licenses stack with subscription licenses, and V2 Free stacks with V2 Subscription; other combinations conflict, and adding one that conflicts asks you to remove or force-replace the conflicts.

What licenses do (and do not do) matters for Module 10. A missing or expired license does not stop Portainer from running; it stops non-admin users from logging in with a 403 "License is not valid," and it stops new environment provisioning for free-tier overuse. Administrators can always log in, on the theory that administrators need to be able to fix the license problem. This is the safety valve that keeps customers unblocked when a license expires unexpectedly.

In your lab

If you have a Portainer Business trial or partner license, add it now through the UI (Settings → Licenses). If you do not have one yet, Portainer Business Edition offers a free three-node tier that you can use for the rest of this course; you will hit the node limit when you get to Module 6 and start onboarding environments, but it will get you through Modules 4 and 5.

10

What is next

You now have a Portainer Management Server running, an administrator you can log in as, and a license. That is the baseline. Module 5 is about configuring it for enterprise use before you point any real environments at it: proper TLS certificates, backup targets, federated authentication (LDAP, Active Directory, OAuth), teams before users, feature flags, and firewall posture. Do Module 5 before Module 6.

Next: Module 5 · Configure for the enterprise