Services And Runtimes
This page starts where 2-Minute Quick Start: Run a Remote Sandbox App Locally ends.
You already saw how to run someone else's manifest. This guide shows the next step: write your own manifest, understand the fields while you write it, and run it with either the Docker-compatible runtime path or the built-in Wasmtime path.
The goal is practical:
- create one Docker manifest by hand
- create one Wasmtime manifest by hand
- understand which fields matter and which ones you can ignore at first
- keep the whole flow simple enough that you can finish it in a few minutes
If you only want direct downloads of the built-in examples, use Runtime Examples.
What A Manifest Does
Every Fungi service manifest answers four questions:
- what runtime should execute the service
- where the service artifact comes from
- which ports and host paths the service needs
- how the service should be published through
spec.expose
Today Fungi ships two runtime paths:
runtime: dockerfor OCI-style container imagesruntime: wasmtimeforwasi-httpstyle WebAssembly components
The control flow stays almost the same for both runtimes:
fungi service pull ./my-service.yaml
fungi service start my-service
fungi service inspect my-service
Or on a remote peer:
fungi peer admin service pull --peer <peer-id> ./my-service.yaml
fungi peer admin service start --peer <peer-id> my-service
fungi access open --peer <peer-id> my-service
Start From A Blank Template
Create a new YAML file locally and paste this skeleton first:
apiVersion: fungi.dev/v1alpha1
kind: ServiceManifest
metadata:
# Service instance name inside Fungi.
name: your-service-name
spec:
# Allowed values: docker, wasmtime.
runtime: docker
expose:
# Set enabled: true when you want catalog/access workflows.
enabled: true
# Usually keep this aligned with metadata.name at first.
serviceId: your-service-name
displayName: Your Service
transport:
# Allowed values: tcp, raw.
kind: tcp
usage:
# Allowed values: web, ssh, raw.
kind: web
path: /
source:
# Docker uses image.
image: nginx:stable-alpine
# Wasmtime uses exactly one of file or url instead.
# file: ./your-component.wasm
# url: https://example.com/your-component.wasm
ports:
- # Allowed values for hostPort: auto or a fixed port number.
hostPort: auto
# Required for expose.enabled=true with tcp transport.
name: http
servicePort: 80
# Allowed values: tcp, udp.
protocol: tcp
# Optional host mounts.
mounts: []
# Optional environment variables.
env: {}
# Optional overrides. Leave empty at first.
command: []
entrypoint: []
workingDir: null
You do not need every field on day one. For a minimal first service, focus on:
metadata.namespec.runtimespec.sourcespec.portsspec.expose
Example 1: Write A Docker Manifest For Nginx
Before writing the Docker example, confirm the target node actually has Docker support available:
fungi info runtime
# or, for a remote node
fungi peer capability --peer <peer-id>
If Docker is not available on that node, install Docker first and restart fungi daemon, or skip this example.
Create my-nginx.service.yaml and paste this:
apiVersion: fungi.dev/v1alpha1
kind: ServiceManifest
metadata:
name: my-nginx
spec:
# Allowed values: docker, wasmtime.
runtime: docker
expose:
enabled: true
serviceId: my-nginx
displayName: My Nginx
transport:
# Allowed values: tcp, raw.
kind: tcp
usage:
# Allowed values: web, ssh, raw.
kind: web
path: /
source:
image: nginx:stable-alpine
ports:
- # Allowed values for hostPort: auto or a fixed port number.
hostPort: auto
name: http
servicePort: 80
# Allowed values: tcp, udp.
protocol: tcp
mounts: []
env: {}
What each important field means here:
runtime: dockertells Fungi to use the Docker-compatible container runtime pathsource.imageis the image reference Fungi should pull if it is missinghostPort: autoasks the target node to allocate a permitted host port for youname: httpis important because exposed TCP services need at least one named TCP portusage.kind: webpluspath: /tells Fungi this endpoint should be treated like a web app
Run it locally:
fungi service pull ./my-nginx.service.yaml
fungi service start my-nginx
fungi service inspect my-nginx
Copy the local_endpoints.local_address address in your browser and you should see the default Nginx welcome page.
If you want to see logs:
fungi service logs my-nginx --tail 50
Example 2: Write A Wasmtime Manifest For A Local .wasm
Fungi's Wasmtime path supports both of these source forms:
spec.source.filefor a local.wasmfilespec.source.urlfor a direct HTTP or HTTPS URL to a single.wasmfile
We use the sample-wasi-http-rust project in this example.
Get a sample-wasi-http-rust.wasm file from bytecodealliance/sample-wasi-http-rust, then put that .wasm file in the same directory as this YAML file.
Create sample-wasi-http.service.yaml:
apiVersion: fungi.dev/v1alpha1
kind: ServiceManifest
metadata:
name: sample-wasi-http
spec:
# Allowed values: docker, wasmtime.
runtime: wasmtime
expose:
enabled: true
serviceId: sample-wasi-http
displayName: Sample WASI HTTP
transport:
# Allowed values: tcp, raw.
kind: tcp
usage:
# Allowed values: web, ssh, raw.
kind: web
path: /
source:
file: ./sample-wasi-http-rust.wasm
ports:
- # Allowed values for hostPort: auto or a fixed port number.
hostPort: auto
name: http
servicePort: 8080
# Allowed values: tcp, udp.
protocol: tcp
mounts: []
env: {}
Run it locally:
fungi service pull ./sample-wasi-http.service.yaml
fungi service start sample-wasi-http
fungi service inspect sample-wasi-http
Copy the local_endpoints.local_address address in your browser and you should see the Hello, wasi:http/proxy world! page.
For this local example, keep the .wasm file next to the YAML file and use a relative path like ./sample-wasi-http-rust.wasm.
For remote deployment, do not start with spec.source.file. Prefer spec.source.url first.
Mounts, ${APP_HOME}, And Working Directories
Mounts are optional. When you do need one, start with ${APP_HOME}.
Example:
mounts:
- hostPath: ${APP_HOME}/data
runtimePath: data
That means:
${APP_HOME}resolves on the target node tofungi_home/services/<service-name>- Fungi creates the mount directory automatically before launch
- for Wasmtime,
runtimePath: databecomes a guest directory exposed asdata
Use this pattern when you want a service-specific persistent directory without hard-coding host paths.
workingDir is optional. If you do not set it, Fungi uses the runtime service directory it prepared for that service.
The Fields You Will Use Most Often
metadata.name
- the Fungi service instance name
- used by
fungi service start <name>and related commands - also affects
${APP_HOME}
spec.runtime
dockerorwasmtime- this decides which source fields are valid
spec.source
- Docker:
image - Wasmtime: exactly one of
fileorurl fileshould point to a single local.wasmfileurlshould be a direct HTTP or HTTPS URL to a single.wasmfile
spec.ports
servicePortis the port the app listens on inside its runtimehostPort: autois usually the easiest starting pointnameshould be present for exposed TCP services
spec.expose
- tells Fungi how to publish the service to catalog/access workflows
- keep
serviceIdstable once other nodes depend on it usage.kind: webis the common case for browser-facing apps
spec.mounts
- maps host paths into the workload
- host paths still have to pass the target node's runtime safety policy
Local Flow Vs Remote Flow
Use the local flow when you are still designing the manifest itself:
fungi service pull ./my-service.yaml
fungi service start my-service
fungi service inspect my-service
fungi service logs my-service --tail 50
Use the remote flow once the manifest already works locally:
fungi peer capability --peer <peer-id>
fungi peer admin service pull --peer <peer-id> ./my-service.yaml
fungi peer admin service start --peer <peer-id> my-service
fungi access open --peer <peer-id> my-service
Runtime Notes
- The Docker-compatible runtime path targets host Docker endpoints on Windows, macOS, and Linux.
- On Windows, the common endpoint is
\\.\pipe\docker_engine; on macOS it is often$HOME/.docker/run/docker.sock; on Linux it is often/var/run/docker.sock. - The container path automatically pulls the referenced image if it is missing locally.
- The Wasmtime path supports a local
.wasmfile or a direct HTTP/HTTPS URL to a single.wasmfile. - Wasmtime mount directories are created automatically before launch.
- The Wasmtime path is not available on Android yet.
spec.expose.enabled=truewith TCP transport requires at least one named TCP port inspec.ports[].name.
Current Limits
- Archive packages and hash verification are not implemented yet.
- The Wasmtime path currently targets single-component
.wasmpayloads rather than richer package formats. - Container image pull progress is not yet streamed through the CLI.
Continue Reading
- Runtime Examples: direct downloads of the built-in example manifests.
- Remote Service Control: the user-facing
peer,catalog, andaccessflow. - 2-Minute Quick Start: Forward A TCP Port: the shortest path for raw TCP forwarding after your devices are already connected.