Deploy manually
The installer only writes a compose file and brings it up — you can write one yourself. Generate an encryption key first, and keep it: losing it makes stored registry and git credentials undecryptable.
openssl rand -base64 32 # SOL2DOCKER_ENCRYPTION_KEY
openssl rand -hex 24 # agent token, only if you deploy the node agent
Standalone (docker compose)
services:
sol2docker:
image: ghcr.io/sol2docker/sol2docker:beta
container_name: sol2docker
ports: ["8080:8080"]
environment:
SOL2DOCKER_ENCRYPTION_KEY: "paste-the-generated-key"
SOL2DOCKER_AGENT_BOOTSTRAP_TOKEN: "paste-the-agent-token" # only with the agent
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
restart: unless-stopped
deploy: # docker compose v2 honours these limits
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
memory: 128M
agent: # optional — see the node agent guide
image: ghcr.io/sol2docker/agent:beta
environment:
SOL2DOCKER_SERVER_URL: "http://sol2docker:8080"
SOL2DOCKER_AGENT_TOKEN: "paste-the-agent-token" # same value as the server's
SOL2DOCKER_INSECURE_HTTP: "true" # required over plain http — see below
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
deploy:
resources:
limits:
cpus: "0.5"
memory: 128M
reservations:
memory: 32M
docker compose up -d # → http://localhost:8080
These are safe ceilings, not requirements. sol2docker itself is light — the server sits
around 40–60 MiB in steady state (peaking ~165 MiB during boot/migrations) and the agent
runs at ~5 MiB. The caps above leave generous headroom for busy fleets and log streaming;
raise memory if you manage many environments with heavy log/stat traffic, or drop the
deploy: blocks entirely to run uncapped.
Swarm (docker stack deploy)
Same idea, plus deploy: blocks and a shared overlay. Run docker stack deploy on the
manager that should hold the data:
services:
sol2docker:
image: ghcr.io/sol2docker/sol2docker:beta
ports: ["8080:8080"]
environment:
SOL2DOCKER_ENCRYPTION_KEY: "paste-the-generated-key"
SOL2DOCKER_AGENT_BOOTSTRAP_TOKEN: "paste-the-agent-token"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/sol2docker:/data
networks: [sol2docker]
deploy:
placement:
constraints: [node.hostname == THIS-MANAGER] # see below
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
memory: 128M
agent:
image: ghcr.io/sol2docker/agent:beta
environment:
SOL2DOCKER_SERVER_URL: "http://sol2docker:8080"
SOL2DOCKER_AGENT_TOKEN: "paste-the-agent-token"
SOL2DOCKER_INSECURE_HTTP: "true"
SOL2DOCKER_NODE_NAME: "{{.Node.Hostname}}"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks: [sol2docker]
deploy:
mode: global
resources:
limits:
cpus: "0.5"
memory: 128M
reservations:
memory: 32M
networks: { sol2docker: { driver: overlay } }
docker stack deploy -c docker-stack.yml sol2docker
Two things that catch people out
SOL2DOCKER_INSECURE_HTTP: "true"The agent refuses plain http:// to anything that isn't loopback, and sol2docker is a
service name. Without the acknowledgement the agent exits at startup and crash-loops. (Use
https:// and you don't need it.)
With node.role == manager, a reschedule can move the service to a different manager and
start it against an empty /data — which looks exactly like losing your database. Replace
THIS-MANAGER with the output of docker info -f '{{.Name}}' on the node you deploy from.
Everything else is optional — TLS, health checks, a second network for a reverse proxy. See
Configuration for the full SOL2DOCKER_* surface.