SETUP.md
117 lines · 5934 bytes · executable
1# Config
2
3SkunkyArt reads `config.json` from the working directory, or the file named
4with `-c`. The default file is optional: without it the built-in defaults
5below apply. A file named with `-c` must exist.
6
7* `listen` — IP and port to listen on, `ip:port`. Default `127.0.0.1:3003`.
8* `uri` — Instance URI. Example: `"uri":"/art/"` -> https://skunky.example.com/art/.
9 Default `/`.
10* `cache` — On-disk cache for proxied media, avatars and emotes. On by
11 default. A proxying instance with no cache re-fetches every image from
12 wixmp on every view, which is the pattern that gets an egress IP blocked.
13 * `enabled` — boolean, default true.
14 * `path` — Cache directory, default `cache`. It must be writable by the
15 user SkunkyArt runs as, and SkunkyArt refuses to start if it is not. The
16 container image runs as uid 10000, so a bind-mounted cache needs
17 `sudo chown -R 10000:10000 <dir>` on the host.
18 * `memcache` — Also keep served media in RAM, on top of the on-disk cache.
19 Entries are scored by how often they are requested and dropped once they
20 go a round unused. The cache is bounded only by that scoring, so leave it
21 off unless you have RAM to spare for your traffic. Default false.
22 * `lifetime` — How long a cached file is kept, in the time units below.
23 Default `1w`.
24 * `max-size` — Cache size cap in megabytes, default 200. When the cache
25 grows past it the whole directory is emptied, not trimmed.
26 * `update-interval` — Seconds between rotation passes, default 1. Each
27 pass reads the whole cache directory, so raise it on a large cache.
28* `api-cache` — In-memory cache of DeviantArt API responses. Every page,
29 feed poll and API call that asks DeviantArt the same question within the
30 TTL is answered from memory, and concurrent requests for one thing make
31 one upstream call. On by default; DeviantArt bans egress IPs that ask too
32 often, so leave it on unless you are debugging.
33 * `enabled` — boolean, default true.
34 * `max-size` — Megabytes of response bodies to hold, default 64. Least
35 recently used entries are dropped past this.
36 * `ttl` — How long a response is reused, in the time units below. Default
37 `5i`.
38* `rate-limit` — Per-client budget for page, feed and API requests, so one
39 crawler cannot spend the whole upstream budget. Media, avatars and static
40 files are not counted. Over budget answers 429 with `Retry-After`.
41 Behind a reverse proxy the client is taken from the rightmost
42 `X-Forwarded-For` entry, but only when the connection itself comes from a
43 loopback or private address; a direct client's header is ignored.
44 * `per-minute` — Sustained requests per minute per client, default 60.
45 `0` turns the limit off.
46 * `burst` — How many requests a client can make at once before the rate
47 applies, default 20.
48* `static-path` — Directory of templates, styles and catalogues, read into
49 memory at startup. Default `static`. Ignored by a binary built with the
50 `embed` tag.
51* `download-proxy` — Outbound proxy used when fetching media from DeviantArt's
52 CDN. Leave empty (`""`) unless you actually run a proxy: if this points at
53 something that isn't listening, every image 502s while pages still render,
54 because only media fetches go through it. Inside a container `127.0.0.1` is
55 the container itself, so a host-side proxy must be addressed by service name
56 or host IP, not loopback.
57* `user-agent` — The User-Agent SkunkyArt sends to DeviantArt.
58* `proxy` — Serve media through this instance instead of linking straight to
59 DeviantArt's CDN. Required by `cache`; when off, clients fetch images from
60 wixmp directly. Default true.
61* `nsfw` — Show mature content. Default false.
62* `hide-ai` — Omit AI-generated deviations (those flagged `[🤖]`) from all
63 listings: search, daily deviations, galleries and favourites. Default false.
64* `theme` — Palette for the interface. `auto` (default) serves the dark theme
65 and lets a visitor whose system asks for light get the light one, through
66 `prefers-color-scheme` — no cookie, no query string, no JavaScript. `dark` or
67 `light` pins one for everybody. An unrecognised value stops startup rather
68 than quietly falling back.
69* `language` — Interface language. `auto` (default) reads the browser's own
70 `Accept-Language` header, which it sends on every request anyway, so nothing
71 extra is stored or asked for. A language code (`en`, `es`) pins one for
72 everybody. An unknown code falls back to English rather than refusing to
73 start, since a missing catalogue is a worse reason to be down than to be in
74 the wrong language.
75
76 Catalogues live in `static/lang/*.json`, keyed by the strings the templates
77 ask for. `en.json` is the reference and is always complete; a catalogue that
78 is missing a key shows the English for that one string, so a partial
79 translation is useful immediately. To add a language, copy `en.json`,
80 translate it, and name it after the code.
81
82# Time units
83
84A number followed by one of:
85
86* `i` — minutes
87* `h` — hours
88* `d` — days
89* `w` — weeks
90* `m` — months (30 days)
91* `y` — years (360 days)
92
93# robots.txt
94
95`/robots.txt` is served automatically. It disallows search, the API, user
96and group pages, media and paginated URLs, and asks for a 10 second crawl
97delay; the index, daily deviations and posts stay crawlable.
98
99# Setting up reverse proxy
100
101Pretty much business as usual, except for the [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) header setting.
102
103Nginx example configuration:
104```apache
105server {
106 listen 443 ssl;
107 server_name skunky.example.com;
108
109 # In case of subdomain, use / instead of ((BASE_URL))
110 location ((BASE_URL)) {
111 proxy_set_header X-Forwarded-Proto $scheme;
112 proxy_set_header Host $host;
113 proxy_http_version 1.1;
114 proxy_pass http://((IP)):((PORT));
115 }
116}
117```