# File mounts
URL: https://synquic.tech/docs/guides/file-mounts.md

Put a config file, certificate or key into a container without baking it into the image. Synq stores the contents encrypted, writes the file on the server and mounts it read-only.

import { Step, Steps } from 'fumadocs-ui/components/steps';

Some programs want a **file**, not an environment variable: an `nginx.conf`, a `config.yml`, a TLS
certificate, a service-account JSON key. A **file mount** lets you paste that file into the panel. Synq keeps
the contents encrypted, writes the file on the server when the container is created, and mounts it into the
container **read-only** at the path you choose.

You don't need to commit the file to your repository or build it into the image, and changing it doesn't
need a rebuild, only a redeploy.

<Callout title="What you need first">
- A project deployed with Docker to one of your own servers.
- Permission to change the project's settings.
</Callout>

## Where file mounts are

- **A single app:** open the project and choose **Storage** in the project menu. The **File mounts** card is
  below the volumes and persistent storage. (It is also on the **Configuration** tab.)
- **A service** of a compose or monorepo project: open **Apps & Services**, click the service and open its
  **Volumes** tab. The **File mounts** card is under the service's volumes.

## Add a file

<Steps>

<Step>

### Press Add file mount

</Step>

<Step>

### Fill in the form

| Field | What to enter |
| --- | --- |
| **Container path** | The absolute path of the file inside the container, for example `/etc/app/config.yml`. |
| **Mode** | Optional octal permissions such as `0600`. Empty means `0644` (readable by every user in the container, which images that don't run as root need). |
| **File contents** | Paste the whole file. Up to 1 MiB. |

</Step>

<Step>

### Save, then redeploy

Press **Save file**. The toast says **File saved. Redeploy to update the container.** The running container
keeps the old file (or no file) until it is recreated, so redeploy the project (or the service) to put it in
place.

</Step>

</Steps>

Example: an nginx site config mounted over the default one.

```nginx
server {
  listen 8080;
  root /usr/share/nginx/html;
  location /api/ { proxy_pass http://api:3000/; }
}
```

With **Container path** `/etc/nginx/conf.d/default.conf` and the default mode, the next deploy starts nginx
with this file.

## Edit, rename or remove

Each file is listed with its path, mode, size and a **Read-only** badge.

- **Edit** loads the current contents into the form. Change them, or change the **Container path** to move
  the file, and press **Save file**.
- **Delete** asks **Remove the file mounted at ...?** Press **Remove**.

Both take effect on the next deploy.

## How it behaves

- **Read-only in the container.** The app can read the file but not change it. If the program writes to its
  config file, mount the file somewhere else and copy it at start, or use a [volume](/docs/guides/volumes-backups).
- **Encrypted at rest.** The contents are stored encrypted with the rest of the project's secrets. The list
  only shows path, mode and size; the contents are loaded only when someone with write permission presses
  **Edit**.
- **Survives redeploys.** Synq writes the file again from the stored contents each time it deploys the
  container, so a fresh container always gets the current version.
- **Replaces what the image has.** A file mounted at a path that already exists in the image hides the image's
  file.

## Limits

- Up to 1 MiB per file, 4 MiB for all the files of one app or service together, and 64 files.
- The path must be absolute, point at a file (not end in `/`), and contain no `..`, `:` or control
  characters. Two entries can't use the same path, and one can't sit inside another (`/etc/app` and
  `/etc/app/config.yml`).
- The mode is three octal digits, optionally with a leading `0` (`644`, `0600`). Setuid, setgid and sticky
  bits (such as `1755` or `2755`) are not accepted.
- Only for containers on your own servers. An app that runs directly on the host, without Docker, doesn't get
  file mounts.

## From the API

```bash
# List a single app's file mounts (path, mode, size; no contents)
curl -H "Authorization: Bearer $SYNQ_TOKEN" \
  "$SYNQ_URL/api/projects/$PROJECT_ID/file-mounts"

# Create or replace one
curl -X PUT -H "Authorization: Bearer $SYNQ_TOKEN" -H "Content-Type: application/json" \
  -d '{"path":"/etc/app/config.yml","content":"log_level: info\n","mode":"0600"}' \
  "$SYNQ_URL/api/projects/$PROJECT_ID/file-mounts"

# Remove it
curl -X DELETE -H "Authorization: Bearer $SYNQ_TOKEN" \
  "$SYNQ_URL/api/projects/$PROJECT_ID/file-mounts?path=/etc/app/config.yml"
```

`SYNQ_URL` is your panel address (for example `https://app.example.com`). For a service, use
`/api/projects/:id/services/:serviceId/file-mounts`. To rename a file in one call, send `previousPath` with
the old path.

## Related guides

<Cards>
  <Card title="Environment variables" href="/docs/guides/environment-variables" description="For single values and secrets, a variable is simpler than a file." />
  <Card title="Volumes & volume backups" href="/docs/guides/volumes-backups" description="For data the app writes and must keep." />
  <Card title="Container settings" href="/docs/guides/container-settings" description="Restart policy, command, capabilities and other Docker options." />
</Cards>
