docker.mdx•6.22 kB
---
title: Docker
description: Setting up a Storyden container with Docker
---
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
Getting an instance of Storyden online is criminally easy. There's almost zero configuration required and lots of sane defaults which you can adapt later as needed.
<Callout type="warn">
Note that this guide assumes you already have SSL termination set up for your
server. Storyden does not accept HTTPS connections and always assumes that
it's behind a load balancer or reverse proxy. We recommend
[Caddy](https://caddyserver.com/) as an easy to set up reverse proxy.
</Callout>
## Running the container
You can spin up a local Storyden instance using Docker. The main Docker image includes both frontend and API services and can be started with:
```sh
docker run -p 8000:8000 ghcr.io/southclaws/storyden
```
This will start the full stack (API and web interface) accessible at `http://localhost:8000`.

<Callout type="warn">
The first account that is registered will automatically be given the Admin
role which provides you all permissions. When deploying a new *public*
instance, be careful with how long you leave the freshly deployed instance
without registering the admin account.
</Callout>
### API only
If you're looking to just play with the API, you can run the API-only container image:
```sh
docker run -p 8000:8000 ghcr.io/southclaws/storyden:edge-backend
```
This will run the API at `http://localhost:8000` and you can check the OpenAPI documentation at `http://localhost:8000/api/docs`.
All CORS and cookie rules are default configured to support `localhost:8000` out of the box.

## Configuration
When running a production instance of Storyden, you must set some configuration values to ensure basic functionality and security.
Storyden's infrastructure-level configuration is applied via environment variables. You can read more about the available options [here](/docs/operation/configuration).
For this guide, we'll focus on the bare minimum to get up and running.
### `PUBLIC_WEB_ADDRESS`
This is the frontend address, or, the URL users will visit in their browser. [More info.](/docs/operation/configuration#public_web_address)
Example: `PUBLIC_WEB_ADDRESS=https://the-secret-agent.club`
### `PUBLIC_API_ADDRESS`
This is the API address, where the web frontend sends API calls. [More info.](/docs/operation/configuration#public_api_address)
Example: `PUBLIC_API_ADDRESS=https://api.the-secret-agent.club`
<Callout>
These can be the same, for example when running the full-stack image and both
your browser requests and API requests go to the same container. In this case,
set both environment variables to the same value.
</Callout>
## Mounting `/storyden/data`
Storyden does not depend on external services by default, so unless you specify, persistent storage such as the database and assets are stored on the local disk.
- If you haven't specified a [`DATABASE_URL`](/docs/operation/configuration#database_url) a local embedded SQLite database will be used.
- If you haven't specified a [`ASSET_STORAGE_TYPE`](/docs/operation/configuration#asset_storage_type) uploaded files will be stored to disk.
The Docker image data directory is `/storyden/data` which is set as a volume by default, if you want to mount a local directory instead of a Docker-managed volume, you can specify the `--volume` flag and bind it to a directory on your host machine's filesystem.
## All together
Using Docker's managed volume:
<Tabs groupId="shell" items={["Escaped", "One line", "NuShell"]}>
<Tab value="Escaped">
```sh
docker run \
--name storyden \
--publish 8000:8000 \
--env PUBLIC_WEB_ADDRESS=https://the-secret-agent.club \
--env PUBLIC_API_ADDRESS=https://api.the-secret-agent.club \
ghcr.io/southclaws/storyden
```
</Tab>
<Tab value="One line">
```sh
docker run --name storyden --publish 8000:8000 --env PUBLIC_WEB_ADDRESS=https://the-secret-agent.club --env PUBLIC_API_ADDRESS=https://api.the-secret-agent.club ghcr.io/southclaws/storyden
```
</Tab>
<Tab value="NuShell">
```sh
(docker run
--name storyden
--publish 8000:8000
--env PUBLIC_WEB_ADDRESS=https://the-secret-agent.club
--env PUBLIC_API_ADDRESS=https://api.the-secret-agent.club
ghcr.io/southclaws/storyden)
```
</Tab>
</Tabs>
Or with a directory mounted into the container:
<Tabs groupId="shell" items={["Escaped", "One line", "NuShell"]}>
<Tab value="Escaped">
```sh
docker run \
--name storyden \
--publish 8000:8000 \
--volume /my/local/storyden/data:/storyden/data \
--env PUBLIC_WEB_ADDRESS=https://the-secret-agent.club \
--env PUBLIC_API_ADDRESS=https://api.the-secret-agent.club \
ghcr.io/southclaws/storyden
```
</Tab>
<Tab value="One line">
```sh
docker run --name storyden --publish 8000:8000 --volume /my/storyden/data:/storyden/data --env PUBLIC_WEB_ADDRESS=https://the-secret-agent.club --env PUBLIC_API_ADDRESS=https://api.the-secret-agent.club ghcr.io/southclaws/storyden
```
</Tab>
<Tab value="NuShell">
```sh
(docker run
--name storyden
--publish 8000:8000
--volume /my/storyden/data:/storyden/data
--env PUBLIC_WEB_ADDRESS=https://the-secret-agent.club
--env PUBLIC_API_ADDRESS=https://api.the-secret-agent.club
ghcr.io/southclaws/storyden)
```
</Tab>
</Tabs>
## Next Steps
Now you've got an instance running, you must expose it to the internet using a reverse proxy. Storyden does not accept HTTPS connections but it requires that the site itself run on a HTTPS address for security reasons.
We recommend using something like [Caddy](https://caddyserver.com/) or [Traefik](https://traefik.io/) to act as a reverse proxy that handles HTTPS.
Alternatively, you can expose Storyden's container on port 80 and use [Cloudflare](https://www.cloudflare.com/en-gb/learning/cdn/glossary/reverse-proxy/) to handle SSL termination.
```yaml
--publish 80:8000
```