Set Up Managed Services

Managed services are databases and storage systems that Temps provisions as Docker containers on your server. You create them once, link them to projects, and Temps handles credential generation, networking, environment variable injection, and backups.


Available service types

ServiceDefault ImageUse case
PostgreSQLgotempsh/postgres-walg:18-bookwormPrimary database with WAL-G streaming backups
Redisgotempsh/redis-walg:8-bookwormCaching, sessions, pub/sub, and queues
MongoDBgotempsh/mongodb-walg:8.0Document database
S3 Storagerustfs/rustfs:1.0.0-alpha.78S3-compatible object storage (powered by RustFS)

Temps also provides higher-level abstractions built on these services:

ServiceBacked byPurpose
KVRedisKey-value storage accessible via the Temps SDK
BlobRustFSFile/blob storage accessible via the Temps SDK

Create a service

From the dashboard

  1. In the sidebar, click Services
  2. Click Create Service
  3. Select the service type
  4. Enter a name and adjust parameters if needed
  5. Click Create

From the API

curl -X POST "https://your-temps-instance/api/external-services" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-postgres",
    "service_type": "postgres",
    "parameters": {
      "port": "5432",
      "max_connections": "200"
    }
  }'

Configuration by service type

PostgreSQL:

ParameterDefaultEditable after creation
portAuto-assigned from 5432Yes
docker_imagegotempsh/postgres-walg:18-bookwormYes
max_connections100Yes
ssl_modedisableYes
databasepostgresNo (read-only)
usernamepostgresNo (read-only)
passwordAuto-generated (16 chars)No (read-only)

Redis:

ParameterDefaultEditable after creation
portAuto-assigned from 6379Yes
docker_imagegotempsh/redis-walg:8-bookwormYes
passwordAuto-generatedNo (read-only)

MongoDB:

ParameterDefaultEditable after creation
portAuto-assigned from 27017Yes
docker_imagegotempsh/mongodb-walg:8.0Yes
databaseadminNo (read-only)
usernameadminNo (read-only)
passwordAuto-generatedNo (read-only)

S3 / RustFS:

ParameterDefaultEditable after creation
portAuto-assigned from 9000Yes
console_portAuto-assigned from 9001Yes
docker_imagerustfs/rustfs:1.0.0-alpha.78Yes
access_keyAuto-generatedNo (read-only)
secret_keyAuto-generatedNo (read-only)

Linking injects the service's connection credentials as environment variables into your project's containers at deploy time.

From the dashboard

  1. Open your project
  2. Click Services in the project sidebar
  3. Click Link Service
  4. Select the service
  5. Click Link

From the API

curl -X POST "https://your-temps-instance/api/external-services/{service_id}/projects" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": 1
  }'

What happens when you link

  1. Per-project isolation — For PostgreSQL, a dedicated database is created named {project_slug}_{environment_slug}. For Redis, a database number (0-15) is assigned. For S3, a dedicated bucket is created.
  2. Environment variables — Connection credentials are generated using the Docker container name as the hostname (for internal networking) and injected on the next deploy.
  3. One per type — Only one service of each type can be linked to a project. To switch PostgreSQL instances, unlink the current one first.

Preview environment variables

To see what variables will be injected without deploying:

# Preview variable names
curl "https://your-temps-instance/api/external-services/{service_id}/preview-environment-names" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Preview with masked values
curl "https://your-temps-instance/api/external-services/{service_id}/preview-environment-masked" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Get actual values for a project
curl "https://your-temps-instance/api/external-services/{service_id}/projects/{project_id}/environment" \
  -H "Authorization: Bearer YOUR_TOKEN"

Unlink a service

curl -X DELETE "https://your-temps-instance/api/external-services/{service_id}/projects/{project_id}" \
  -H "Authorization: Bearer YOUR_TOKEN"

Unlinking does not delete the database or data inside the service — it only stops injecting environment variables. You can re-link later.


Import an existing container

If you already have a PostgreSQL or Redis container running on your server, you can import it into Temps instead of creating a new one.

  1. Go to Services
  2. Click Import Container
  3. Temps scans for running Docker containers that match known service types
  4. Select the container to import
  5. Provide the connection credentials (Temps cannot read them from the container)

From the API:

# List importable containers
curl "https://your-temps-instance/api/external-services/available-containers" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Import one
curl -X POST "https://your-temps-instance/api/external-services/import" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "container_id": "abc123...",
    "name": "existing-postgres",
    "service_type": "postgres",
    "parameters": {
      "host": "localhost",
      "port": "5432",
      "database": "postgres",
      "username": "postgres",
      "password": "your-existing-password"
    }
  }'

Manage service lifecycle

Start and stop

Services can be started and stopped independently:

# Stop a service (keeps data)
curl -X POST "https://your-temps-instance/api/external-services/{id}/stop" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Start it again
curl -X POST "https://your-temps-instance/api/external-services/{id}/start" \
  -H "Authorization: Bearer YOUR_TOKEN"

Stopping a service does not delete any data — the Docker volume persists. Applications linked to a stopped service will fail to connect until the service is started again.

Health check

curl "https://your-temps-instance/api/external-services/{id}/health" \
  -H "Authorization: Bearer YOUR_TOKEN"

Delete a service

curl -X DELETE "https://your-temps-instance/api/external-services/{id}" \
  -H "Authorization: Bearer YOUR_TOKEN"

Upgrade a service

To update the Docker image (e.g. from PostgreSQL 17 to 18):

curl -X POST "https://your-temps-instance/api/external-services/{id}/upgrade" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "docker_image": "gotempsh/postgres-walg:18-bookworm"
  }'

Or from the dashboard, go to the service details page and click Upgrade.


PostgreSQL HA clusters

A PostgreSQL service can run as a high-availability cluster instead of a single standalone container. Cluster services have topology = "cluster" and service_type = "postgres", and run on the gotempsh/postgres-ha:18-bookworm-walg image. A cluster is made up of a pg_auto_failover monitor plus one or more data members tracked in the service_members table. Applications connect through the cluster's virtual address — <cluster>.temps.local — using a libpq connection string with target_session_attrs=read-write, which always lands writes on the current primary.

Cluster backups and restore use WAL-G physical backups (basebackup plus continuous WAL archiving) rather than the per-engine pg_dump/pg_dumpall path used for standalone services.

Cluster backup

When you back up a cluster (from the service's Backup button or the standard backup API), Temps routes through ExternalServiceManager::backup_postgres_cluster instead of the standalone path. That method:

  1. Finds the current writable primary by asking pg_auto_failover for the member whose live state is primary or single.

  2. Writes a /var/lib/postgresql/walg.env credentials file to every running data member (not the monitor). Writing it everywhere means archiving keeps working after a failover promotes a different member to primary.

  3. Runs wal-g backup-push /var/lib/postgresql/pgdata against the primary to upload the basebackup to S3. WAL segments are lz4-compressed by default.

  4. Enables continuous WAL archiving by running, against the primary:

    ALTER SYSTEM SET archive_command = '. /var/lib/postgresql/walg.env && wal-g wal-push %p';
    ALTER SYSTEM SET archive_mode = 'on';
    ALTER SYSTEM SET wal_level = 'replica';
    SELECT pg_reload_conf();
    

Because archive_command is stored in postgresql.auto.conf — which is part of pgdata and is streamed to replicas — the setting survives a failover. A new primary inherits it without an operator re-running anything, so WAL keeps flowing to the same S3 prefix.

In-place cluster restore

An in-place restore of a cluster backup routes through ExternalServiceManager::restore_postgres_cluster. It first snapshots the existing member topology (names, ordinals, roles, node assignments), then runs in three phases:

PhaseWhat it does
1. TeardownRemoves every member: deletes DNS records, force-removes each container, removes each {container}_data volume, drops the role/VIP DNS records, and deletes the service_members rows. The parent external_services row is kept on purpose, so the service URL, credentials, and UI bookmarks survive.
2. Pre-seed primaryRuns a one-shot helper container (same gotempsh/postgres-ha:18-bookworm-walg image, bind-mounting the primary's volume) that runs wal-g backup-fetch "$PGDATA" LATEST, writes recovery.signal, and writes a postgresql.auto.conf with restore_command = '. /var/lib/postgresql/walg-restore.env && wal-g wal-fetch %f %p'.
3. RebuildRe-runs initialize_cluster with the original member specs. PostgreSQL recovers from WAL, pg_auto_failover rebuilds the cluster, and replicas re-basebackup from the new primary.

Because container names derive deterministically from ordinal (postgres-<cluster>-<ordinal>) and the cluster connection string targets <cluster>.temps.local, the rebuilt cluster keeps the same names, ordinals, and DNS. Application connections reconnect transparently once the cluster is back up.

Was this page helpful?