> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Run User Code on Fly Machines

[Fly Machines](/machines/overview) are [Firecracker VMs](https://firecracker-microvm.github.io/) with a fast REST API that can boot instances in about 300ms, in any region supported by [Fly.io](/reference/regions).

One use for Machines is to run user code to extend your service, or as a service in itself. People sometimes call this **Functions-as-a-Service (FaaS)**.

User code is fraught with peril. Fly Machines run it safely - even the most awful, buggy, and downright hostile user code.
Most FaaS work similarly. The general idea: package up users' code, define a runtime environment, launch the code in a VM, then turn the VM off when it idles to save on compute bills. All while charging users per request!

Packaging user code as a Docker image is mostly up to you. The rest, we can help with.

## Working with the Machines API

Machines are operated over a simple REST API. First, visit the [Machines documentation](/machines/overview) to get ready for this guide.

## Grab or create a runtime Docker image

Your function-as-a-service needs a well-defined runtime environment that can boot user code and then shut it down when it's idle.

Here we'll use a [simple Fastify server](https://github.com/fly-apps/fastify-functions) running behind a small Golang HTTP proxy that exits after a few minutes of inactivity.

## Create an app

Pick a unique name and create the required application to group machines together. This application is also the gateway to accessing the machines from the internet.

```
curl -i -X POST \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps" \\
  -d '{
      "app_name": "my-app-name",
      "org_slug": "personal",
      "network": "my-app-name-network"
    }'

```

**Status: 201**

Note the `network` field. This is necessary to isolate the app from other private networks on the organization. Learn more about [custom private networks](/networking/custom-private-networks).

Allocate an IP address to the app. This makes our app accessible at the IP, and via `my-app-name.fly.dev`.

```bash theme={null}
fly ips allocate-v4 -a my-app-name
```

## Launch a new machine

Launch a user machine by supplying a Docker image and a networking configuration.

```
curl -i -X POST \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps/my-app-name/machines" \\
  -d '{
      "name": "quirky-machine",
      "config": {
        "image": "flyio/fastify-functions",
        "env": {
          "APP_ENV": "production"
        },
        "services": [
          {
            "ports": [
              {
                "port": 443,
                "handlers": [
                  "tls",
                  "http"
                ]
              },
              {
                "port": 80,
                "handlers": [
                  "http"
                ]
              }
            ],
            "protocol": "tcp",
            "internal_port": 8080
          }
        ],
        "checks": {
            "httpget": {
                "type": "http",
                "port": 8080,
                "method": "GET",
                "path": "/",
                "interval": "15s",
                "timeout": "10s"
            }
        }
      }
    }'

```

**Status: 200**

Machines are permanent, so keep the ID from the response handy.

Your users' service will boot immediately after this API call. Launch speed is a function of image size. Tiny images should boot in less than 2 seconds. Large, complex images are much slower to boot.

Try accessing your new machine at `https://my-app-name.fly.dev`. If no requests arrive within 120 seconds ([default](https://github.com/fly-apps/fastify-functions/blob/0f4ef94451/start.sh#L3) but configurable), the machine will exit, but a request will force it to start back up automatically.

## Launch a Machine in another region

That machine was launched in the region nearest to you. Say you want your user function to run fast for users in Australia. Let's launch another machine there.

The Anycast IP you allocated will route traffic to the nearest region with a deployed machine. If it's stopped, it will start up automatically.

```
curl -i -X POST \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps/my-app-name/machines" \\
  -d '{
      "name": "machine-syd",
      "config": {
        "image": "flyio/fastify-functions",
        "env": {
          "APP_ENV": "production"
        },
        "services": [
          {
            "ports": [
              {
                "port": 443,
                "handlers": [
                  "tls",
                  "http"
                ]
              },
              {
                "port": 80,
                "handlers": [
                  "http"
                ]
              }
            ],
            "protocol": "tcp",
            "internal_port": 8080
          }
        ]
      },
      "region": "syd"
    }'

```

**Status: 200**

## Stop a machine

In a FaaS environment, you'll usually want to wait for a machine to exit. You can stop them with an API call, however, if needed.

```
curl -i -X POST \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps/my-app-name/machines/d5683210c7968e/stop" 

```

**Status: 200**

```json theme={null}
{
  "ok": true
}
```

## Start an existing machine

Once created, a machine may be stopped and started until you delete it. The good news is, images stay cached after first launch. Starting an existing machine is very fast.

Use the existing machine ID again to start it:

```
curl -i -X POST \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps/my-app-name/machines/d5683210c7968e/start" 

```

**Status: 200**

```json theme={null}
{
  "previous_state": "stopped"
}
```

The start API call only returns successfully if the machine is in a stopped state. It's safe to call start on a running machine, though. If you're unsure of the machine state, just call start and ignore the error response.

Start operations clear filesystem changes. The user process comes up with a fresh runtime environment. It is safe to share machines between users, as long as you stop them before they get reassigned.

## Get details about the deployment

Now we have a couple machines running, we can use `fly logs -a my-app-name` to see what's going on. Also, for an overview:

<CodeGroup>
  ```bash cmd theme={null}
  fly status -a my-app-name
  ```

  ```out out theme={null}
  App
    Name     = my-app-name
    Owner    = personal
    Hostname = my-app-name.fly.dev

  Machines
  ID            	NAME          	REGION	STATE    	CREATED
  10e286064b1867	machine-syd   	syd   	started	2022-05-20T17:07:36Z
  0e286e40cee686	quirky-machine	cdg   	stopped	2022-05-20T17:07:04Z
  ```
</CodeGroup>

Here we see that one of the Machines has exited.

The closest equivalent API call lists all Machines in an app:

```
curl -i -X GET \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps/my-app-name/machines" 

```

**Status: 200**

## Delete a machine

When you're done, delete the machine:

```
curl -i -X DELETE \\
    -H "Authorization: Bearer ${FLY_API_TOKEN}" -H "Content-Type: application/json" \\
    "${FLY_API_HOSTNAME}/v1/apps/my-app-name/machines/d5683210c7968e" 

```

**Status: 200**

```json theme={null}
{
  "ok": true
}
```

## Additional notes

The Machines API is young and full of potential. We haven't worked everything out, so please [post on our forums](https://community.fly.io/) with questions! Here are a few things worth noting:

The *wake-on-request* behavior described above will be unpredictable when running more than one machine per region.

Standard `flyctl` operations like `deploy`, `scale`, `autoscaling` aren't currently supported by Machines.

`ssh` is supported. You can SSH to a machine using its IPv6 address (from `fly machines list`):

```bash theme={null}
fly ssh console 'your:machines:ipv6:address:0:0:0:0'
```

Or you can select a machine to connect to from a list using `fly ssh console -s`:

```bash theme={null}
fly ssh console -a my-app-name -s
? Select instance:  [Use arrows to move, type to filter]
> sjc (fdaa:0:6787:a7b:a15f:ee6a:3882:2)
  sjc (fdaa:0:6787:a7b:a15f:c306:4566:2)
  sjc (fdaa:0:6787:a7b:a15f:1a8c:2c01:2)
```
