Repository navigation
Image Lock
← Config-Env-Vars · Compat-V15
Every container image the generated compose files and the CLI's own tools (ACME client, admin pull, monitoring fragments) use comes from one file: internal/compose/images.yaml (authored), compiled into internal/compose/images.lock.json (generated, embedded in the binary). A scan test (internal/compose/images_literal_scan_test.go) fails the build when a non-test Go file under internal/ or cmd/ spells an image reference as a single string literal.
What the scan does not see: literals assembled from parts (for example "postgres:" + version, tracked as debt D-0213), Dockerfile templates inside raw strings (scaffold output), tools/, untagged repository strings, and the dead docker-compose.monitoring.yml. Three allowlisted tool images remain (plugin author tool, CI job image, controlplane test harness).
Each entry records name, role (core, optional, monitoring, tool, plugin), the fully qualified repository, version, the index_digest of the multi-arch index, the per-platform digests (linux/amd64, linux/arm64, linux/arm/v7 when upstream publishes them), legacy_ref, license, source and mirror.
The first lock records what each effective reference resolved to on 2026-10-04. No version moved: legacy_ref is the exact string the CLI emitted before the lock existed. legacy_ref stays frozen: a pin bump moves version (and the digests) only, so legacy mode keeps emitting the pre-lock string. The lock test checks that legacy_ref names the same repository with a tag; it does not require legacy_ref to equal repository:version.
| Value | Image string | Default in |
|---|---|---|
legacy |
the entry's legacy_ref, byte-identical to earlier releases (redis:7-alpine, nginx:alpine) |
v1.4.x |
lock |
repository:version@sha256:<index digest> |
v1.5.0 (NSELF_V15=1) |
Set IMAGE_PINNING=lock in .env to opt a project in early. Moving to lock changes every image string, so the next nself start recreates the containers; plan for that on a serving box.
A *_VERSION key in the env cascade is an explicit override and is used as given, unpinned, unless it equals the lock version or the legacy_ref tag. The legacy_ref tag is what the config defaults and the .env files written by nself setup carry (HASURA_VERSION=v2.44.0), so it counts as "the default" and stays pinned after a bump. To run the pre-lock version itself, use IMAGE_PINNING=legacy.
| Setting | IMAGE_PINNING=lock |
IMAGE_PINNING=legacy |
|---|---|---|
unset, or equal to the lock version or the legacy_ref tag (REDIS_VERSION=7-alpine) |
docker.io/library/redis:7-alpine@sha256:... |
redis:7-alpine |
any other value (REDIS_VERSION=6.2-alpine) |
redis:6.2-alpine (no digest) |
redis:6.2-alpine |
POSTGRES_IMAGE / CS_N_IMAGE
|
used as given | used as given |
An IMAGE_PINNING value other than lock or legacy (case ignored) is an error: nself build and every command that loads the config refuse to run rather than fall back silently.
A project digest file written by nself update images (.nself-image-digests.json) still applies to unpinned references; a lock reference already carries its digest and is left alone.
Redis 7.4 and later is RSALv2/SSPLv1, so the lock carries a valkey entry (docker.io/valkey/valkey:8.1-alpine, BSD-3-Clause) and the redis compose service runs it by default in v1.5. The service name, REDIS_* variables and REDIS_URL stay. The engine is chosen by REDIS_ENGINE (valkey or redis), then by the engine of the project lock's redis pin, then by the mode default (v1.4 redis, v1.5 valkey):
| Project | Result |
|---|---|
| v1.5, new project (no lock, no existing compose) | Valkey from the lock entry, volume valkey_data
|
| v1.5, lock pins a redis image | stays Redis; nself build --plan shows no cache change |
v1.5, no lock, existing docker-compose.yml runs redis |
stays Redis (the first lock takes the pin from that file) |
REDIS_ENGINE=valkey, any mode |
Valkey; a v1.4 project switches with nself config set REDIS_ENGINE valkey, then nself build --plan, nself build, nself start
|
REDIS_ENGINE=redis, any mode |
Redis, whatever the lock pins |
Valkey runs valkey-server with the same flags, user, port and network, and its health check is valkey-cli ping (no reliance on redis-* symlinks). A REDIS_VERSION equal to the Redis default (7-alpine) means the Valkey default; any other value is used as the Valkey tag.
Queued jobs are not migrated: Valkey starts on an empty valkey_data volume, and the plan shows a stateful recreate of the redis service. redis_data is kept, so setting REDIS_ENGINE=redis again reuses it.
- Edit the entry's
versionininternal/compose/images.yaml(a version bump is its own reviewed change). Leavelegacy_refalone. The weekly bump (tools/imagebump,.github/workflows/image-pin-bump.yml) does the same. -
go run ./tools/imagelock -resolvereads each index through the docker CLI (network), proves each digest addresses the index it came from, and rewrites the lock. -
go run ./tools/imagelock -checkverifies the lock offline: header, sorted, every entry has an index digest andlinux/amd64, and the lock coversimages.yaml. Adding an entry without resolving fails it. -
go run ./tools/imagelock -resolve -plugins images.jsonalso merges the plugins repository'simages.jsonv1:kind: pluginentries becomeplugin/<slug>,kind: upstreamentries keep their name,kind: cientries are ignored.
An upstream that publishes no digest-addressable index, or misses a required platform, stops the run with the image named; raise it before locking.
Each non-plugin entry names a mirror, docker.io/nself/<name>, at the same digest, for pulls when upstream deletes a tag. Plugin entries have no mirror: their repository is already ours.
tools/imagelist prints service<TAB>repository:version@digest for every entry; .github/workflows/default-images-pullable.yml runs docker manifest inspect on each line and triggers on a change to images.yaml or images.lock.json.
compose.LockedRef(name) returns one entry, compose.LockedImages() all of them sorted by name, compose.ImageRef(name, version) the string for the active mode, and compose.PinningMode() the resolved mode.
Getting Started
Commands
- Commands, Overview
- Lifecycle: cmd-init · cmd-build · cmd-start · cmd-stop · cmd-restart · cmd-dev
- Monitoring: cmd-status · cmd-logs · cmd-health · cmd-urls · cmd-doctor · cmd-monitor · cmd-alerts · cmd-sentry · cmd-watchdog
- Data: cmd-db · cmd-backup · cmd-dr · cmd-queue · cmd-webhooks
- Config: cmd-config · cmd-service · cmd-env · cmd-promote
- Networking: cmd-ssl · cmd-trust · cmd-dns-setup
- Security: cmd-access · cmd-security · cmd-secrets
- Tenancy: cmd-tenant · cmd-billing
- Plugins: cmd-plugin · cmd-license · cmd-dogfood (extracted, CLI-R11) · cmd-k8s (extracted, CLI-R11) · cmd-encryption (extracted, CLI-R11) · cmd-waf (extracted, CLI-R11) · cmd-federation (extracted, CLI-R11) · cmd-mail (extracted, CLI-R11) · cmd-dlq (extracted, CLI-R11)
- AI: cmd-ai · cmd-claw · cmd-model
- Templates: cmd-template
- Utilities: cmd-exec · cmd-clean · cmd-reset · cmd-update · cmd-upgrade · cmd-version · cmd-admin · cmd-migrate · cmd-migrate-firebase · cmd-migrate-supabase · cmd-completion
Features
- Features, Overview
- Feature-Auth
- Feature-Storage
- Feature-Search
- Feature-Functions
- Feature-Email
- Feature-Monitoring
- Feature-Plugins
- Feature-nClaw, AI Assistant
- Feature-nChat, Messaging
- Feature-nFamily, Family Social
- Feature-nCloud, Managed Hosting
- Feature-Memory-Rooms, Knowledge Organization
- Feature-Agent-Dashboard, Agent Metrics
- Feature-Image-Generation, AI Image Generation
Configuration
- Configuration, Overview
- Config-Env-Vars
- Config-Postgres
- Config-Hasura
- Config-Auth
- Config-Nginx
- Shared-Proxy
- Config-Optional-Services
- Config-Custom-Services
- Config-System
Plugins (87 + 10 monitoring)
- Plugin-Overview
- Plugin-Catalog
- Plugin-Install
- Plugin-Licensing
- Plugin-Architecture
- Plugin-Dev-Guide
- Plugin-Migrations-Contract
Free (25)
- plugin-backup
- plugin-content-acquisition
- plugin-content-progress
- plugin-cron
- plugin-donorbox
- plugin-feature-flags
- plugin-github
- plugin-github-runner
- plugin-invitations
- plugin-jobs
- plugin-link-preview
- plugin-mdns
- plugin-mlflow
- plugin-monitoring
- plugin-notifications
- plugin-notify
- plugin-paypal
- plugin-search
- plugin-shopify
- plugin-stripe
- plugin-subtitle-manager
- plugin-tokens
- plugin-torrent-manager
- plugin-vpn
- plugin-webhooks
Pro (62)
- plugin-access-controls
- plugin-activity-feed
- plugin-admin-api
- plugin-analytics
- plugin-auth
- plugin-bots
- plugin-browser
- plugin-calendar
- plugin-cdn
- plugin-chat
- plugin-claw
- plugin-claw-budget
- plugin-claw-news
- plugin-claw-web
- plugin-cloudflare
- plugin-cms
- plugin-compliance
- plugin-ddns
- plugin-devices
- plugin-documents
- plugin-entitlements
- plugin-file-processing
- plugin-game-metadata
- plugin-geocoding
- plugin-geolocation
- plugin-google
- plugin-home
- plugin-idme
- plugin-knowledge-base
- plugin-linkedin
- plugin-livekit
- plugin-media-processing
- plugin-meetings
- plugin-moderation
- plugin-mux
- plugin-object-storage
- plugin-observability
- plugin-photos
- plugin-podcast
- plugin-post
- plugin-realtime
- plugin-retro-gaming
- plugin-rom-discovery
- plugin-social
- plugin-sports
- plugin-support
- plugin-tmdb
- plugin-voice
- plugin-web3
- plugin-workflows
Planned (26)
plugin-auditplugin-blogplugin-checkoutplugin-commerceplugin-drmplugin-exportplugin-flowplugin-importplugin-ldapplugin-mailgunplugin-mediaplugin-oauth-providersplugin-pagesplugin-postmarkplugin-rate-limitplugin-reportsplugin-samlplugin-schedulerplugin-sendgridplugin-ssoplugin-subscriptionplugin-thumbplugin-transcoderplugin-twilioplugin-wafplugin-watermark
Guides
- Guide-Production-Deployment
- Guide-SSL-Setup
- Guide-Multi-Tenancy
- Guide-Security-Hardening
- Guide-Monitoring-Setup
- Guide-Backup-Restore
- Guide-Custom-Services
- Guide-Migration-from-v1
Architecture
- Architecture
- Architecture-Guardrails
- Service-Graph
- Compose-Generation
- Nginx-Generation
- Plugin-Architecture
Reference
Machine interface
-
JSON-Output,
--jsonenvelope -
Command-Registry,
nself help --json - Exit-Codes
- error-codes, Error Codes
-
Compat-V15,
NSELF_V15gate
Licensing
Security
Brand
Operations
- operations/release-cascade, Release Cascade
- operations/self-healing, Self-Healing Schema
- operations/redis-tuning, Redis Pool Tuning
- operations/meilisearch-warmup, MeiliSearch Warm-Up
- operations/jwt-rotation, JWT Key Rotation
- operations/windows-wsl2-setup, Windows / WSL2 Setup
- operations/gemini-oauth-reauth, Gemini OAuth Reauth
Contributing
Admin
- USER-ACTION-QUEUE, Pending Admin Actions
All commands (21)
- A: cmd-add · cmd-admin
- B: cmd-backup · cmd-build
- C: cmd-clean · cmd-config
- D: cmd-db · cmd-deploy · cmd-doctor
- E: cmd-exec
- I: cmd-init
- L: cmd-license · cmd-logs
- M: cmd-mcp
- R: cmd-remove · cmd-reset · cmd-restart
- S: cmd-start · cmd-status · cmd-stop
- U: cmd-update