|
| 1 | +--- |
| 2 | +title: Buckie |
| 3 | +description: Filesystem-native file server with a minimal S3-style REST API. Zero database, single config file. Node.js 24 and PHP 8+ implementations. |
| 4 | +template: splash |
| 5 | +hero: |
| 6 | + tagline: A lightweight file server with an S3-style REST API — no database, no cloud account, just a process and a disk. Available for Node.js and PHP. |
| 7 | + actions: |
| 8 | + - text: Install Node.js version |
| 9 | + link: https://github.com/dynamiatools/buckie-node-js |
| 10 | + icon: external |
| 11 | + variant: primary |
| 12 | + - text: Install PHP version |
| 13 | + link: https://github.com/dynamiatools/buckie-php |
| 14 | + icon: external |
| 15 | + variant: minimal |
| 16 | +--- |
| 17 | + |
| 18 | +import { Card, CardGrid, Tabs, TabItem, LinkButton, Aside } from '@astrojs/starlight/components'; |
| 19 | + |
| 20 | +## Three concepts to know |
| 21 | + |
| 22 | +<CardGrid> |
| 23 | + <Card title="Bucket" icon="open-book"> |
| 24 | + A named pointer to a directory on disk (or a remote SFTP path in Node.js). |
| 25 | + Every file operation targets a specific bucket. |
| 26 | + </Card> |
| 27 | + <Card title="Identity" icon="approve-check-circle"> |
| 28 | + A username + bcrypt-hashed secret. Think of it as a service account. Multiple identities can access the same server with different permissions. |
| 29 | + </Card> |
| 30 | + <Card title="Grant" icon="shield"> |
| 31 | + A permission rule that links an identity to a bucket: which operations (`read`, `write`, `delete`) are allowed, and optionally restricted to a path prefix. |
| 32 | + </Card> |
| 33 | +</CardGrid> |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +## 1. Start the server |
| 38 | + |
| 39 | +<Tabs> |
| 40 | +<TabItem label="Node.js"> |
| 41 | +```bash |
| 42 | +# Install globally once |
| 43 | +npm install -g @dynamia-tools/buckie |
| 44 | + |
| 45 | +# Start |
| 46 | +buckie serve --host 0.0.0.0 --port 8080 |
| 47 | +``` |
| 48 | +</TabItem> |
| 49 | +<TabItem label="PHP"> |
| 50 | +```bash |
| 51 | +# Install with Composer |
| 52 | +composer create-project dynamia-tools/buckie my-buckie-server |
| 53 | +cd my-buckie-server |
| 54 | + |
| 55 | +# Development server |
| 56 | +php bin/buckie serve --host 0.0.0.0 --port 8080 |
| 57 | + |
| 58 | +# Production: point Apache / Nginx / FrankenPHP to public/ |
| 59 | +``` |
| 60 | +</TabItem> |
| 61 | +</Tabs> |
| 62 | + |
| 63 | +<Aside type="tip"> |
| 64 | + On first run Buckie creates `.buckie/config.json` in the working directory. That single file holds every bucket, identity and grant — back it up or inject it via Docker. |
| 65 | +</Aside> |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +## 2. Create a bucket |
| 70 | + |
| 71 | +<Tabs> |
| 72 | +<TabItem label="Node.js"> |
| 73 | +```bash |
| 74 | +# Local filesystem |
| 75 | +buckie create bucket documents /mnt/storage/documents |
| 76 | + |
| 77 | +# SFTP remote (Node.js only) |
| 78 | +buckie create bucket remote-docs /uploads \ |
| 79 | + --storage sftp \ |
| 80 | + --sftp-host storage.example.com \ |
| 81 | + --sftp-username deploy \ |
| 82 | + --sftp-private-key "$(cat ~/.ssh/id_rsa)" |
| 83 | + |
| 84 | +# Verify |
| 85 | +buckie list buckets |
| 86 | +``` |
| 87 | +</TabItem> |
| 88 | +<TabItem label="PHP"> |
| 89 | +```bash |
| 90 | +# Local filesystem only |
| 91 | +php bin/buckie create bucket documents /var/storage/documents |
| 92 | + |
| 93 | +# Verify |
| 94 | +php bin/buckie list buckets |
| 95 | +``` |
| 96 | +</TabItem> |
| 97 | +</Tabs> |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +## 3. Create an identity & grant access |
| 102 | + |
| 103 | +<Tabs> |
| 104 | +<TabItem label="Node.js"> |
| 105 | +```bash |
| 106 | +# Create an identity |
| 107 | +buckie create identity erp-prod my-strong-secret |
| 108 | + |
| 109 | +# Grant full access to the whole bucket |
| 110 | +buckie grant erp-prod documents --read --write --delete |
| 111 | + |
| 112 | +# Or restrict to a path prefix (multi-tenant pattern) |
| 113 | +buckie grant erp-prod documents --read --write --delete --prefix /tenant-a/ |
| 114 | + |
| 115 | +# Verify |
| 116 | +buckie list identities |
| 117 | +``` |
| 118 | +</TabItem> |
| 119 | +<TabItem label="PHP"> |
| 120 | +```bash |
| 121 | +# Create an identity |
| 122 | +php bin/buckie create identity erp-prod my-strong-secret |
| 123 | + |
| 124 | +# Grant full access to the whole bucket |
| 125 | +php bin/buckie grant erp-prod documents --read --write --delete |
| 126 | + |
| 127 | +# Or restrict to a path prefix (multi-tenant pattern) |
| 128 | +php bin/buckie grant erp-prod documents --read --write --delete --prefix /tenant-a/ |
| 129 | + |
| 130 | +# Verify |
| 131 | +php bin/buckie list identities |
| 132 | +``` |
| 133 | +</TabItem> |
| 134 | +</Tabs> |
| 135 | + |
| 136 | +<Aside type="tip"> |
| 137 | + Use `provision` to create identity + secret + grant in a single command: |
| 138 | + |
| 139 | + ```bash |
| 140 | + # Node.js |
| 141 | + buckie provision documents --identity erp-prod --read --write --delete --prefix /tenant-a/ |
| 142 | + |
| 143 | + # PHP |
| 144 | + php bin/buckie provision documents --identity erp-prod --read --write --delete --prefix /tenant-a/ |
| 145 | + ``` |
| 146 | +</Aside> |
| 147 | + |
| 148 | +--- |
| 149 | + |
| 150 | +## 4. Consume the API |
| 151 | + |
| 152 | +Authentication is required on every request (except `/health`). |
| 153 | +Use `X-Buckie-Identity` + `X-Buckie-Secret` headers, or HTTP Basic Auth. |
| 154 | + |
| 155 | +Both the Node.js and PHP implementations expose the **exact same REST API**. |
| 156 | + |
| 157 | +### Upload a file |
| 158 | + |
| 159 | +```bash |
| 160 | +curl -X PUT http://localhost:8080/documents/tenant-a/invoice.pdf \ |
| 161 | + -H "X-Buckie-Identity: erp-prod" \ |
| 162 | + -H "X-Buckie-Secret: my-strong-secret" \ |
| 163 | + -H "Content-Type: application/octet-stream" \ |
| 164 | + --data-binary @invoice.pdf |
| 165 | +``` |
| 166 | + |
| 167 | +### Download a file |
| 168 | + |
| 169 | +```bash |
| 170 | +curl http://localhost:8080/documents/tenant-a/invoice.pdf \ |
| 171 | + -H "X-Buckie-Identity: erp-prod" \ |
| 172 | + -H "X-Buckie-Secret: my-strong-secret" \ |
| 173 | + -o invoice.pdf |
| 174 | +``` |
| 175 | + |
| 176 | +### On-the-fly thumbnail |
| 177 | + |
| 178 | +Resize an image without pre-processing — the result is cached automatically: |
| 179 | + |
| 180 | +```bash |
| 181 | +curl "http://localhost:8080/documents/photos/avatar.jpg?w=200&h=200&fit=cover&format=webp" \ |
| 182 | + -H "X-Buckie-Identity: erp-prod" \ |
| 183 | + -H "X-Buckie-Secret: my-strong-secret" \ |
| 184 | + -o avatar-thumb.webp |
| 185 | +``` |
| 186 | + |
| 187 | +Supported parameters: `w`, `h`, `fit` (`cover` | `contain` | `fill`), `format` (`webp` | `jpeg` | `png`). |
| 188 | + |
| 189 | +### List files inside a directory |
| 190 | + |
| 191 | +```bash |
| 192 | +curl http://localhost:8080/documents/tenant-a/ \ |
| 193 | + -H "X-Buckie-Identity: erp-prod" \ |
| 194 | + -H "X-Buckie-Secret: my-strong-secret" |
| 195 | +``` |
| 196 | + |
| 197 | +### List all files in a bucket (paginated) |
| 198 | + |
| 199 | +```bash |
| 200 | +# First page |
| 201 | +curl "http://localhost:8080/documents?limit=50" \ |
| 202 | + -H "X-Buckie-Identity: erp-prod" \ |
| 203 | + -H "X-Buckie-Secret: my-strong-secret" |
| 204 | + |
| 205 | +# Next page using the cursor returned in the previous response |
| 206 | +curl "http://localhost:8080/documents?limit=50&cursor=<cursor-value>" \ |
| 207 | + -H "X-Buckie-Identity: erp-prod" \ |
| 208 | + -H "X-Buckie-Secret: my-strong-secret" |
| 209 | +``` |
| 210 | + |
| 211 | +### Delete a file |
| 212 | + |
| 213 | +```bash |
| 214 | +curl -X DELETE http://localhost:8080/documents/tenant-a/invoice.pdf \ |
| 215 | + -H "X-Buckie-Identity: erp-prod" \ |
| 216 | + -H "X-Buckie-Secret: my-strong-secret" |
| 217 | +``` |
| 218 | + |
| 219 | +### Health check (public) |
| 220 | + |
| 221 | +```bash |
| 222 | +curl http://localhost:8080/health |
| 223 | +``` |
| 224 | + |
| 225 | +--- |
| 226 | + |
| 227 | +## Docker tip |
| 228 | + |
| 229 | +Mount your `config.json` at startup — no CLI bootstrap needed: |
| 230 | + |
| 231 | +```yaml |
| 232 | +# docker-compose.yml |
| 233 | +services: |
| 234 | + buckie: |
| 235 | + image: node:24-alpine |
| 236 | + command: npx @dynamia-tools/buckie serve |
| 237 | + ports: |
| 238 | + - "8080:8080" |
| 239 | + volumes: |
| 240 | + - ./buckie-config.json:/app/.buckie/config.json:ro |
| 241 | + - ./storage:/mnt/storage |
| 242 | +``` |
| 243 | +
|
| 244 | +--- |
| 245 | +
|
| 246 | +## Using Buckie with Dynamia Platform |
| 247 | +
|
| 248 | +[Entity Files](/extensions/entity-files/) — the official Dynamia Platform file management extension — has **native support for Buckie** as a storage backend. If you're running a Dynamia Platform application, you can delegate all file storage to a Buckie server with a single Maven dependency, keeping your app stateless and your files on a dedicated service. |
| 249 | +
|
| 250 | +<LinkButton href="/extensions/entity-files/" variant="secondary"> |
| 251 | + Entity Files extension → |
| 252 | +</LinkButton> |
| 253 | +
|
| 254 | +--- |
| 255 | +
|
| 256 | +## Implementations at a glance |
| 257 | +
|
| 258 | +| | Node.js | PHP | |
| 259 | +|---|---|---| |
| 260 | +| **Package** | [`@dynamia-tools/buckie`](https://www.npmjs.com/package/@dynamia-tools/buckie) on npm | [`dynamia-tools/buckie`](https://packagist.org/packages/dynamia-tools/buckie) on Packagist | |
| 261 | +| **Repository** | [buckie-node-js](https://github.com/dynamiatools/buckie-node-js) | [buckie-php](https://github.com/dynamiatools/buckie-php) | |
| 262 | +| **Runtime** | Node.js 24 + Fastify | PHP 8+ (Apache / Nginx / FrankenPHP) | |
| 263 | +| **Storage** | Local FS + SFTP | Local FS only | |
| 264 | +| **Thumbnails** | Sharp | GD / Imagick | |
| 265 | +| **Programmatic SDK** | ✅ Full TypeScript API | ❌ | |
| 266 | +| **Best for** | High-throughput, embedded use, SFTP | Shared hosting, standard PHP environments | |
| 267 | + |
| 268 | +--- |
| 269 | + |
| 270 | +MIT © [Dynamia Soluciones IT SAS](https://dynamia.tools) |
| 271 | + |
0 commit comments