Skip to main content

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)

docker-compose.yml
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
About the limits

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:

docker-stack.yml
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

The agent needs 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.)

Pin the Swarm placement to a real hostname

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.