Early access: Ailimu is free while we build to 1.0. We'd love your feedback. Send feedback Get notified at 1.0
Ailimu

Install

Ailimu ships as one container. It needs a FileMaker Server it can reach over HTTPS and an account it can sign in as. The database can be on your own network, in your data centre or cloud, or with a hosting provider. Run Ailimu anywhere that can reach it, on your network or on a cloud server or VPS of its own, and point it at the database's address. Claris FileMaker Cloud is not supported yet, because it signs API clients in with a Claris ID.

Before you start

Create a dedicated FileMaker account for Ailimu rather than reusing a person's. Give it a privilege set that can see only what you are willing to expose: Ailimu is another client and your privilege set still governs it, so this is your strongest control.

That account's privilege set needs extended privileges:

Extended privilege Needed for
fmodata Reading tables. This is the default and the better choice: real field types, declared keys, relationships and your field comments.
fmrest Scripts, and the layout list they run against. Also the fallback way of reading data, through layouts.

Enable both if you intend to expose scripts. If you only want to read tables, fmodata alone is enough.

Reading through layouts instead of tables. The Data API sees only fields placed on a layout, and returns the literal text <No Access> for fields the account cannot reach through it. On one large file that meant 4,352 fields of which 85% were unreadable, against 2,099 readable fields over OData. Use OData unless it is unavailable to you.

Get Docker

Ailimu runs as a Docker container, so the machine that runs it needs Docker Engine and the Docker Compose plugin. If docker compose version already prints a version, skip to Run it.

Which machine. For real use, a Linux server: on your network, in the cloud or a VPS. A Mac is fine for trying Ailimu out. The image is published for both Intel/AMD (amd64) and ARM (arm64) processors, and Docker pulls the right one by itself: Intel and AMD servers, Apple silicon Macs, and ARM servers such as AWS Graviton all run it natively.

Linux (Ubuntu 22.04 or 24.04)

Install Docker from Docker's own package repository, which carries current versions and the Compose plugin:

# Docker's signing key and repository
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Docker Engine and the Compose plugin
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Check it works:

sudo docker run --rm hello-world
docker compose version

To run docker without sudo, add yourself to the docker group, then log out and back in:

sudo usermod -aG docker $USER

Docker starts on boot by default, and the compose file below restarts Ailimu with it. On another distribution (Debian, RHEL, Fedora), follow Docker's instructions for it at docs.docker.com/engine/install.

macOS

  1. Install Docker Desktop from docker.com/products/docker-desktop, choosing Apple silicon or Intel chip to match your Mac (Apple menu > About This Mac). With Homebrew you can run brew install --cask docker instead.

  2. Open Docker Desktop once from Applications and wait until it says the engine is running. It must be running whenever Ailimu is.

  3. Check in Terminal:

    docker run --rm hello-world
    docker compose version
    

Run it

The same steps on Linux and macOS, typed in a terminal. On a Mac, open Terminal from Applications > Utilities, or search for it with Cmd+Space. On a Linux server, sign in with SSH as usual.

1. Make a folder for Ailimu

Work in it. Everything Ailimu needs to start is in this folder; everything it saves goes into a Docker volume.

mkdir -p ~/ailimu && cd ~/ailimu

2. Create .env

A small text file holding the FileMaker account Ailimu signs in as. Its name starts with a dot, which hides it in Finder and most file browsers, so create it in the terminal, in the ailimu folder from step 1.

Open it in nano, a simple text editor that comes with macOS and Linux:

nano .env

Type these two lines, with your FileMaker account name and password in place of the examples:

FM_USER=ailimu
FM_PASS=your-filemaker-password

Then save and close: press Ctrl+O, then Enter to save, then Ctrl+X to leave. (That is the Control key, on a Mac as well, not Cmd.)

Or do it in one go instead. Change the two values first, then paste the whole block into the terminal and press Enter:

cat > .env <<'EOF'
FM_USER=ailimu
FM_PASS=your-filemaker-password
EOF

Those two lines are the account every connection uses. If you will connect files on different servers, or files that need different FileMaker accounts, add a pair for each one later. Each connection can have its own, and the Reference explains the names: Credentials for several files. Any change to .env takes effect when you restart the container.

Check what it holds, and make it readable only by you:

cat .env
chmod 600 .env

cat .env should print your two lines. Those are the only required settings. Credentials are read from the environment and are never written to the config file, so they stay out of your backups. See the reference for the optional ones.

3. Create docker-compose.yml

services:
  ailimu:
    image: ailimu/ailimu:latest
    ports:
      - "8081:8081"
    env_file:
      - path: .env
        required: false
    volumes:
      - ailimu-config:/config
    restart: unless-stopped
volumes:
  ailimu-config:

4. Pull the image and start it

docker compose pull
docker compose up -d

docker compose ps should show ailimu as running, and after a few seconds healthy.

5. Read the start-up message

docker compose logs ailimu

The connector prints where to go. On first start it also prints a setup code:

ailimu up on :8081

  Setup wizard:  http://<this-server>:8081/admin/
                 Replace <this-server> with this machine's address or hostname.
                 ...
  Setup code:    YOUR-SETUP-CODE   (enter it in the wizard to create the owner account)

  To connect Claude: open the wizard, choose a connection, and go to its
  Connect Claude step. Each connection has its own address and token.

Replace <this-server> with the address you use to reach the machine Docker runs on, for example http://192.168.1.20:8081/admin/. On that machine itself, localhost works. Set PUBLIC_URL in .env and the log prints the full link.

Open the wizard and create the owner account: your email, a password, and the setup code. The code proves you can see this server's logs, so nobody else who reaches the wizard first can claim it. It is the same value as ADMIN_TOKEN.

The owner can then invite everyone else from People in the wizard, as a viewer, an editor or another owner. See People.

6. Reach it from other machines

On the server itself the wizard is at http://localhost:8081/admin/. From elsewhere, use the server's name or IP address, for example http://ailimu-host:8081/admin/, and allow port 8081 through the server's firewall if it has one:

sudo ufw allow 8081/tcp      # Ubuntu, if ufw is enabled

For anything beyond a trial, put Ailimu behind HTTPS, so the wizard, passwords and Claude's tool calls are encrypted in transit. Claude Desktop and Claude's other apps expect it whenever Ailimu is reached over the internet, for example on a server in a datacentre. See Putting Ailimu on the internet with HTTPS below, and Connecting Claude for the address Claude needs.

Using a PostgreSQL database

Ailimu can serve a PostgreSQL database as well as a FileMaker file, with the same steps: choose what Claude may see, publish, connect Claude. One connector can hold both kinds side by side, and each connection says which it is.

PostgreSQL is simpler to connect than FileMaker. Ailimu reads the database's own catalog, so it knows every table, column type, primary key, foreign key and comment exactly. Nothing about keys or relationships is guessed.

Give Ailimu an account of its own

The database's permissions are the real limit on what Claude can do. Ailimu only offers what you tick in the wizard, but an account that cannot read or change something stops it however the wizard is set. Create a dedicated account and grant it only what you want Claude to have.

For reading, grant SELECT on the tables you intend to expose (or all of them in a schema):

CREATE ROLE ailimu_ro LOGIN PASSWORD 'choose-a-long-password';
GRANT CONNECT ON DATABASE shop TO ailimu_ro;
GRANT USAGE ON SCHEMA public TO ailimu_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ailimu_ro;

To let Claude change records, grant UPDATE on the columns it may change and no others, never on the whole table:

GRANT UPDATE (status, notes) ON orders TO ailimu_rw;

A column the account may not change is refused by PostgreSQL itself, even if someone ticks it as writable in the wizard.

To let Claude run a function, grant EXECUTE on that function. PostgreSQL lets everyone run a new function by default, so first withdraw that, then grant it back one function at a time:

REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC;
GRANT EXECUTE ON FUNCTION mark_paid(integer, text) TO ailimu_rw;

If you use row-level security, it applies to this account like any other.

Set the account in .env

Add the login to .env, then restart the container:

PG_USER=ailimu_ro
PG_PASSWORD=choose-a-long-password

Like the FileMaker account, it is read from the environment only and is never written to the configuration file or a backup. A connection that needs its own account uses PG_USER_<SLUG> and PG_PASSWORD_<SLUG>, where the slug is the connection's name in upper snake case (shop becomes PG_USER_SHOP). The wizard names the variables a connection is missing. PG_HOST, PG_PORT and PG_DATABASE are optional and only prefill the Connect step.

Connect

Choose New connection, then Connect to: PostgreSQL, and enter the host, port (5432 unless you changed it), the database, and the schema (public unless your tables are elsewhere). One connection serves one schema; for tables in another schema, make another connection.

Encryption defaults to encrypted, which is right for any server you reach over a network. If the server does not offer TLS, Test connection says so; choose Off only when it is on the same machine or a network you trust. Encrypted, and check the server's certificate also verifies that the server is who it says it is, which needs a certificate your system trusts.

When Ailimu runs in Docker, localhost is the container itself, not the machine around it. To reach a database on the same machine, use host.docker.internal on Docker Desktop (macOS and Windows). On Linux, add this to the ailimu service in docker-compose.yml and use the same name:

    extra_hosts:
      - "host.docker.internal:host-gateway"

A login only goes to a database server it already goes to. An editor cannot point a connection at a new server and have Ailimu send the stored password there: an owner sets a connection up the first time, as with FileMaker.

What is different from FileMaker

Putting Ailimu on the internet with HTTPS

HTTPS is the job of a reverse proxy that sits in front of Ailimu. Ailimu works with any proxy, and needs only three things from it:

  1. Forward to port 8081. The proxy sends every request for your name to Ailimu on port 8081, and passes the Host and X-Forwarded-* headers on.
  2. Don't buffer, and allow long calls. Claude's tool calls stream their results. Turn response buffering off for this name and allow requests of a few minutes.
  3. Tell Ailimu about the proxy. In .env set PUBLIC_URL to the address people use (https://ailimu.example.com) and TRUST_PROXY to the proxy's address, such as loopback for a proxy on the same machine or the Docker network's subnet for one in another container. Ailimu then reads the browser's real address from the proxy, which sign-in limits depend on. Leave TRUST_PROXY unset without a proxy: the header it trusts can otherwise be faked by anyone who can reach Ailimu directly.

Whichever proxy you use, create a DNS record (an A record) for a name such as ailimu.example.com pointing at the server first, and don't publish port 8081 to the internet once the proxy is in front.

Pick the setup that matches the server Ailimu runs on:

With Caddy

Use this when nothing else on the server uses ports 80 and 443. Caddy is a small web server that gets and renews a free certificate for you.

Open ports 80 and 443 on the server's firewall. Then make a folder, put these two files in it, and add DOMAIN=ailimu.example.com to a .env file beside them.

docker-compose.yml:

services:
  ailimu:
    image: ailimu/ailimu:latest
    env_file:
      - path: .env
        required: false
    environment:
      # Caddy is the only thing that can reach Ailimu, so trusting its
      # forwarded address is safe.
      TRUST_PROXY: 172.28.0.0/16
      PUBLIC_URL: https://${DOMAIN:?Set DOMAIN in .env, e.g. DOMAIN=ailimu.example.com}
    volumes:
      - ailimu-config:/config
    restart: unless-stopped
    networks: [web]

  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    environment:
      DOMAIN: ${DOMAIN}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
    depends_on: [ailimu]
    restart: unless-stopped
    networks: [web]

networks:
  web:
    ipam:
      config:
        - subnet: 172.28.0.0/16

volumes:
  ailimu-config:
  caddy-data:

Caddyfile:

{$DOMAIN} {
	reverse_proxy ailimu:8081 {
		# Claude's tool calls stream; do not buffer them.
		flush_interval -1
	}
}

Then run docker compose up -d. The wizard is at https://ailimu.example.com/admin/, and each connection's address starts with the same https:// name. Ailimu's own port 8081 is not published in this setup.

If the server's provider blocks port 80, Caddy cannot get its certificate the usual way. Use your DNS provider's challenge instead; see Caddy's documentation on the DNS challenge.

With Traefik

Use this if Traefik, a reverse proxy that routes traffic to Docker containers, already runs on the server and owns ports 80 and 443. Ailimu then publishes no ports of its own. The compose file below joins Traefik's Docker network and tells Traefik to route one name to Ailimu. Make a folder, put the file in it, and add these to a .env beside it:

DOMAIN=ailimu.example.com
TRAEFIK_SUBNET=172.18.0.0/16

TRAEFIK_SUBNET is the subnet of Traefik's network (docker network inspect <network> shows it). Three more settings default to the common names. Add them to .env only if yours differ:

Setting Default What it is
TRAEFIK_NETWORK traefik-public The Docker network Traefik reads containers from (docker network ls).
TRAEFIK_ENTRYPOINT websecure Your HTTPS entrypoint.
TRAEFIK_RESOLVER letsencrypt Your certificate resolver, as named in Traefik's configuration.

docker-compose.yml:

services:
  ailimu:
    image: ailimu/ailimu:latest
    env_file:
      - path: .env
        required: false
    environment:
      # Only Traefik's network can reach Ailimu, so trusting its forwarded
      # address is safe.
      TRUST_PROXY: ${TRAEFIK_SUBNET:?Set TRAEFIK_SUBNET in .env, e.g. 172.18.0.0/16}
      PUBLIC_URL: https://${DOMAIN:?Set DOMAIN in .env, e.g. DOMAIN=ailimu.example.com}
    volumes:
      - ailimu-config:/config
    restart: unless-stopped
    networks: [proxy]
    labels:
      - traefik.enable=true
      - traefik.docker.network=${TRAEFIK_NETWORK:-traefik-public}
      - traefik.http.routers.ailimu.rule=Host(`${DOMAIN}`)
      - traefik.http.routers.ailimu.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}
      - traefik.http.routers.ailimu.tls.certresolver=${TRAEFIK_RESOLVER:-letsencrypt}
      - traefik.http.services.ailimu.loadbalancer.server.port=8081

networks:
  proxy:
    external: true
    name: ${TRAEFIK_NETWORK:-traefik-public}

volumes:
  ailimu-config:

Then run docker compose up -d. Check that Traefik does not buffer responses or apply short timeouts to this route.

With nginx

Use this if nginx already runs on the server as its web server or reverse proxy. nginx runs on the host, so Ailimu keeps port 8081 but only on the server itself. In your Ailimu docker-compose.yml, publish the port to 127.0.0.1 only:

    ports:
      - "127.0.0.1:8081:8081"

In .env set:

PUBLIC_URL=https://ailimu.example.com
TRUST_PROXY=loopback

Put this in /etc/nginx/conf.d/ailimu.conf. Change the name, and the two certificate paths to your own (for example from certbot):

server {
    listen 80;
    server_name ailimu.example.com;
    return 308 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name ailimu.example.com;

    ssl_certificate     /etc/letsencrypt/live/ailimu.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ailimu.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_http_version 1.1;

        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Claude's tool calls stream. Do not buffer them, and do not cut
        # a long call short.
        proxy_buffering    off;
        proxy_cache        off;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

Then run sudo nginx -t && sudo systemctl reload nginx and docker compose up -d. On nginx older than 1.25.1, write listen 443 ssl http2; and remove the separate http2 on; line.

Another proxy, or a cloud load balancer

Give it the three needs at the top of this section. In short: forward your name to port 8081, switch response buffering off with a timeout of a few minutes, and set PUBLIC_URL and TRUST_PROXY in .env. Set TRUST_PROXY to the address the proxy connects from. A hop count such as 1 also works when exactly one proxy sits in front.

Moving an install that already holds data

Switching an existing Ailimu install to HTTPS changes the address every connection uses, from http://...:8081 to https://ailimu.example.com. Your settings, accounts and connections are kept as long as the new setup uses the same data volume:

  1. Take a backup first. See Backing up and restoring.
  2. Find the volume with docker volume ls. It ends in ailimu-config, such as myproject_ailimu-config.
  3. Stop the old setup with docker compose down. Never add -v, which deletes the volume.
  4. In the new docker-compose.yml, replace the ailimu-config: line under volumes: with these three, using your volume's name:
  ailimu-config:
    external: true
    name: myproject_ailimu-config
  1. Start the new setup with docker compose up -d, then reconnect Claude to the new https:// address. Claude Desktop needs the extension from each connection's Connect Claude step downloaded again, because the old one holds the old address.

Where Ailimu keeps its data

Everything Ailimu saves is kept in one Docker volume, called ailimu-config in the docker-compose.yml above and mounted at /config inside the container. It survives restarts and updates. Your FileMaker data is never stored there, only Ailimu's own settings:

What Where in /config
Your connections, one file each profiles/<name>.json
The last schema read for each connection, so opening one is instant. Table and field names only, no record values. schema/<name>.json
The setup code and each connection's token, readable only by Ailimu tokens.json
Wizard accounts and pending invite or reset links, readable only by Ailimu. Passwords are stored as scrypt hashes. A pending link is kept so an owner can copy it again, and is deleted once used, cancelled or expired. users.json
Signed-in browsers, stored as hashes, readable only by Ailimu sessions.json
The activity log: one file per day of changes, script runs and admin actions, and activity/reads/ for Claude's reads on connections that record them. Old days are deleted automatically; see Activity log retention. activity/

Back it up. With a copy you can rebuild an install without setting anything up again. Without one, a lost volume means new tokens, and every Claude that was connected has to be connected again. The easiest way is from the wizard: see Backing up and restoring. To copy the whole volume from the terminal instead, into the current folder:

docker run --rm -v ailimu_ailimu-config:/config -v "$PWD":/backup alpine \
  tar czf /backup/ailimu-config.tgz -C /config .

Docker names the volume after the folder docker-compose.yml is in, so from the ailimu folder it is ailimu_ailimu-config. docker volume ls lists the exact name. This copy is not encrypted, and holds every token: keep it as you would a password.

Backing up and restoring

Owners back up and restore from Server in the wizard's left-hand column.

Making a backup. Choose a password, type it twice, and click Download backup. You get one file, named like ailimu-backup-2026-09-29.ailimu, holding:

It does not hold your FileMaker password, which stays in .env, or who is signed in: everyone signs in again after a restore.

The file is encrypted with the password. Keep the password somewhere safe: without it the backup cannot be opened, and nobody can recover it. A wrong password, or a file that has been changed, is refused rather than half read.

Restoring onto a new server, for a move or after losing the volume:

  1. Install Ailimu on the new server as above, with the same .env (the FileMaker account), and start it.
  2. Open the wizard. On the first screen, instead of creating an owner, choose Restore from a backup.
  3. Enter the new server's setup code from its log, choose the backup file, and enter the backup's password.
  4. Sign in with your account from the backup. Every connection, person and token is back.

If the new server has a different address, Claude setups need that new address. Their tokens still work. For Claude Desktop, change the address in the extension's settings, or download the extension again.

Restoring onto a server that is already set up replaces every connection, person and token on it with the backup's, and signs everyone out. It is under Server > Danger zone, for owners, and asks you to type replace before it runs. What was there before is kept on the config volume, in restore-previous.

Tokens

Ailimu has four kinds of token. Two of them are for Claude.

Token What it is for Where to find it
Personal key What one person's Claude uses to reach one connection, at /mcp/<name>. Given by an owner under People > Claude access; the activity log shows whose it was, and it can be taken away or reset without affecting anyone else. The person's own My Claude access screen, and inside the extension they download there. The owner never sees it.
Connection token What Claude uses to reach one connection, at /mcp/<name>, shared by everyone who has it. Each connection has its own, and it opens that connection only. The connection's Connect Claude step in the wizard, for editors and owners. It is also inside the Claude Desktop extension and the setup commands shown there.
Setup code (ADMIN_TOKEN) Creates the first owner. After that, sent as Authorization: Bearer <setup code>, it works against /admin/api with owner rights, for scripts and automation. The activity log records those calls as admin token. It does not open the wizard: people sign in with their own accounts. The start-up log, until the first owner exists. After that, Server > Server keys, for owners.
Token for the older /mcp address (MCP_TOKEN) The plain /mcp address, which works only while the server has exactly one connection. Kept so setups made before connections had their own tokens keep working. Server > Server keys, for owners.

A connection token and the /mcp token are not interchangeable: Claude pointed at /mcp/<name> with the /mcp token is refused.

The setup code and the /mcp token are generated on first start and saved on the volume, so recreating the container does not change them. Set ADMIN_TOKEN or MCP_TOKEN in .env to choose your own values instead; the environment always wins. Connection tokens are made when a connection is first published, and replaced when a connection is deleted and created again.

Activity log retention

The activity log deletes whole days once they are older than:

Setting Default Covers
ACTIVITY_RETAIN_DAYS 365 Changes, script runs and admin actions.
ACTIVITY_READS_RETAIN_DAYS 30 Claude's reads, on connections where Record reads is on.

Recording reads can use a lot of disk. Each search or lookup Claude makes adds about 300 bytes, so the size depends on how much people ask:

Use Claude tool calls a day Log a day Over 30 days of reads
Normal: 10 people about 2,000 about 0.6 MB about 18 MB
Heavy: 50 busy people about 20,000 about 6 MB about 180 MB
An agent stuck repeating itself 100,000 or more 30 MB or more 900 MB or more

Reads are off unless someone turns them on for a connection. If your volume fills its disk, lower ACTIVITY_READS_RETAIN_DAYS or turn reads off where you do not need them. An install upgraded from before the activity log keeps its old audit.log history: it is split into daily files on first start and the original is kept as audit.log.migrated.

If the only owner is locked out

Run this on the server. It prints a one-time link that sets a new password for that email and makes the account an owner, creating it if needed:

docker compose exec ailimu node apps/connector/dist/admin-cli.js reset-owner [email protected]

Being able to run it is the proof: it needs shell access to the container.

Upgrading

When a newer version is out, owners and editors see it in the wizard: a card under the Ailimu logo, and a banner on All connections listing what the new version brings and how many versions behind you are. It turns orange with a shield when any of those versions fixes security. To update:

docker compose pull && docker compose up -d

Your profiles and cached schemas are on the volume and survive. Upgrading from a version without accounts, the wizard asks for the owner setup on first open; the setup code is your existing ADMIN_TOKEN, and MCP endpoints and tokens are unchanged. A setup written before profiles existed is migrated automatically the first time the new version reads it: it becomes a profile named after the file, and the old file is renamed rather than deleted.