# Image hosting

Store character photos on Fivemanage or on your own server.

## Choose a host

Character photos must be reachable on an **HTTPS** link so Discord can load them. Wolfden Rich Presence offers two ways to store them:

| Host | Best for | You need |
| --- | --- | --- |
| **Fivemanage** (default) | The quickest setup | A free account and an API key |
| **Self-hosted** | Keeping everything on your own server | A domain and a reverse proxy |

Host settings live in `server_config.lua`. This file is loaded on the server only and is never sent to players, so your API key stays private. Never place it in `config.lua`, which every player downloads.

If no host is set up, the server console shows `Mugshots disabled` with the reason, and players see your logo instead of a photo.

> Discord webhooks are **not** supported. Discord attachment links only work with a signature that expires, and Discord's Rich Presence image proxy removes it, so webhook photos always appeared as a **?**. Webhook support was removed in 1.1.0.

## Option A: Fivemanage

1. Create an account at [fivemanage.com](https://fivemanage.com).
2. Create an **API token** with permission to upload images.
3. Add the token in one of two ways.

In `server_config.lua`:

```lua server_config.lua
ServerConfig.ImageHost = 'fivemanage'

ServerConfig.Fivemanage = {
    ApiKey = 'your-token',
```

Or leave `ApiKey = ''` and add it to `server.cfg` instead:

```cfg server.cfg
set wd_richpresence_fivemanage_key "your-token"
```

Use `set`, **not** `setr`. `setr` sends the value to every connected player.

When a character gets a new photo, the old one is deleted from Fivemanage (`DeleteOldImages = true`), so each character only uses one image of storage. If the server console shows `Could not delete old Fivemanage image`, check that your token can delete images.

## Option B: Self-hosted

Photos are saved in the resource's own `images/` folder, and your server offers them on its game port (30120) at `/wd_richpresence/m/<id>.png`. Discord needs an HTTPS address, so you put a domain with a reverse proxy in front of that one path.

You need a domain you control and access to the machine running your server. Shared game-host panels often do not allow this; use Fivemanage instead.

### 1. Point a domain at your server

Create a DNS **A record**, such as `img.yourserver.com`, pointing at your server's IP address.

### 2. Forward only the photo path

Set up **one** of the following. Each one forwards `/wd_richpresence/m/` to your server and refuses everything else, so nothing else on port 30120 is exposed.

**Caddy** is the simplest and gets an HTTPS certificate by itself. Open ports 80 and 443, install [Caddy](https://caddyserver.com), and use this `Caddyfile`:

```text Caddyfile
img.yourserver.com {
    handle /wd_richpresence/m/* {
        reverse_proxy 127.0.0.1:30120
    }
    handle {
        respond 404
    }
}
```

**nginx**, if you already run it. Get a certificate with `certbot --nginx -d img.yourserver.com`:

```nginx nginx
server {
    listen 443 ssl;
    server_name img.yourserver.com;

    ssl_certificate     /etc/letsencrypt/live/img.yourserver.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/img.yourserver.com/privkey.pem;

    location /wd_richpresence/m/ {
        proxy_pass http://127.0.0.1:30120;
        proxy_set_header Host $host;
    }

    location / {
        return 404;
    }
}
```

**Cloudflare Tunnel**, if you would rather not open ports or show your server's IP. With your domain on Cloudflare, go to **Zero Trust → Networks → Tunnels**, create a tunnel, install `cloudflared` on the server machine, and add a public hostname:

- **Hostname:** `img.yourserver.com`
- **Path:** `wd_richpresence/m/*`
- **Service:** `HTTP` → `localhost:30120`

### 3. Tell the resource your domain

```lua server_config.lua
ServerConfig.ImageHost = 'self'

ServerConfig.SelfHosted = {
    PublicUrl = 'https://img.yourserver.com',
    DeleteOldImages = true,
}
```

`PublicUrl` must start with `https://`. Without it, the console shows `self-hosting needs ServerConfig.SelfHosted.PublicUrl set to your HTTPS domain`.

### 4. Test it

1. Set `Config.Debug = true` in `config.lua` and restart.
2. Join and load a character.
3. In the server console, find the line `Stored mugshot for … https://img.yourserver.com/wd_richpresence/m/….png`.
4. Open that link in a browser. If you see the character's face, Discord can load it too.
5. Set `Config.Debug` back to `false`.

If the link does not open, the proxy is not forwarding that path yet. Check your reverse proxy and that the DNS record points at the right machine.

The old automatic `*.users.cfx.re` addresses no longer work, since Cfx.re retired them, so a domain of your own is required.

## Updating the resource

When you replace the resource with a new version, keep the `images/` folder. If you lose it, nothing breaks: missing photos are noticed and taken again automatically.

## Switching hosts

Change `ServerConfig.ImageHost` and restart the resource. Each character's photo is taken again on the new host the next time they load in.
