aboutsummaryrefslogtreecommitdiff
path: root/docs/configuration
diff options
context:
space:
mode:
authorrinpatch <rinpatch@sdf.org>2019-10-02 23:28:45 +0300
committerrinpatch <rinpatch@sdf.org>2019-10-02 23:28:45 +0300
commitacc62f327d45c0a9a0414da56bc339ec3e22cb63 (patch)
tree6ac0fbfc1c489e7e1823562f1717b29bf875d593 /docs/configuration
parentc5e937b156ea1f8f96ade7d9104fc2c5fd1dd9cd (diff)
downloadpleroma-acc62f327d45c0a9a0414da56bc339ec3e22cb63.tar.gz
Rename some directories because MkDocs uses them for categories
Diffstat (limited to 'docs/configuration')
-rw-r--r--docs/configuration/General-tips-for-customizing-Pleroma-FE.md17
-rw-r--r--docs/configuration/config.md773
-rw-r--r--docs/configuration/custom_emoji.md68
-rw-r--r--docs/configuration/hardening.md103
-rw-r--r--docs/configuration/howto_mediaproxy.md34
-rw-r--r--docs/configuration/howto_mongooseim.md10
-rw-r--r--docs/configuration/howto_proxy.md12
-rw-r--r--docs/configuration/howto_set_richmedia_cache_ttl_based_on_image.md33
-rw-r--r--docs/configuration/howto_user_recomendation.md31
-rw-r--r--docs/configuration/i2p.md196
-rw-r--r--docs/configuration/mrf.md122
-rw-r--r--docs/configuration/onion_federation.md159
-rw-r--r--docs/configuration/small_customizations.md12
-rw-r--r--docs/configuration/static_dir.md69
14 files changed, 1639 insertions, 0 deletions
diff --git a/docs/configuration/General-tips-for-customizing-Pleroma-FE.md b/docs/configuration/General-tips-for-customizing-Pleroma-FE.md
new file mode 100644
index 000000000..15c4882dd
--- /dev/null
+++ b/docs/configuration/General-tips-for-customizing-Pleroma-FE.md
@@ -0,0 +1,17 @@
+# General tips for customizing Pleroma FE
+There are some configuration scripts for Pleroma BE and FE:
+
+1. `config/prod.secret.exs`
+1. `config/config.exs`
+1. `priv/static/static/config.json`
+
+The `prod.secret.exs` affects first. `config.exs` is for fallback or default. `config.json` is for GNU-social-BE-Pleroma-FE instances.
+
+Usually all you have to do is:
+
+1. Copy the section in the `config/config.exs` which you want to activate.
+1. Paste into `config/prod.secret.exs`.
+1. Edit `config/prod.secret.exs`.
+1. Restart the Pleroma daemon.
+
+`prod.secret.exs` is for the `MIX_ENV=prod` environment. `dev.secret.exs` is for the `MIX_ENV=dev` environment respectively.
diff --git a/docs/configuration/config.md b/docs/configuration/config.md
new file mode 100644
index 000000000..262d15bba
--- /dev/null
+++ b/docs/configuration/config.md
@@ -0,0 +1,773 @@
+# Configuration
+
+This file describe the configuration, it is recommended to edit the relevant *.secret.exs file instead of the others founds in the ``config`` directory.
+If you run Pleroma with ``MIX_ENV=prod`` the file is ``prod.secret.exs``, otherwise it is ``dev.secret.exs``.
+
+## Pleroma.Upload
+* `uploader`: Select which `Pleroma.Uploaders` to use
+* `filters`: List of `Pleroma.Upload.Filter` to use.
+* `link_name`: When enabled Pleroma will add a `name` parameter to the url of the upload, for example `https://instance.tld/media/corndog.png?name=corndog.png`. This is needed to provide the correct filename in Content-Disposition headers when using filters like `Pleroma.Upload.Filter.Dedupe`
+* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host.
+* `proxy_remote`: If you're using a remote uploader, Pleroma will proxy media requests instead of redirecting to it.
+* `proxy_opts`: Proxy options, see `Pleroma.ReverseProxy` documentation.
+
+Note: `strip_exif` has been replaced by `Pleroma.Upload.Filter.Mogrify`.
+
+## Pleroma.Uploaders.Local
+* `uploads`: Which directory to store the user-uploads in, relative to pleroma’s working directory
+
+## Pleroma.Uploaders.S3
+* `bucket`: S3 bucket name
+* `bucket_namespace`: S3 bucket namespace
+* `public_endpoint`: S3 endpoint that the user finally accesses(ex. "https://s3.dualstack.ap-northeast-1.amazonaws.com")
+* `truncated_namespace`: If you use S3 compatible service such as Digital Ocean Spaces or CDN, set folder name or "" etc.
+For example, when using CDN to S3 virtual host format, set "".
+At this time, write CNAME to CDN in public_endpoint.
+* `streaming_enabled`: Enable streaming uploads, when enabled the file will be sent to the server in chunks as it's being read. This may be unsupported by some providers, try disabling this if you have upload problems.
+
+## Pleroma.Upload.Filter.Mogrify
+
+* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`.
+
+## Pleroma.Upload.Filter.Dedupe
+
+No specific configuration.
+
+## Pleroma.Upload.Filter.AnonymizeFilename
+
+This filter replaces the filename (not the path) of an upload. For complete obfuscation, add
+`Pleroma.Upload.Filter.Dedupe` before AnonymizeFilename.
+
+* `text`: Text to replace filenames in links. If empty, `{random}.extension` will be used. You can get the original filename extension by using `{extension}`, for example `custom-file-name.{extension}`.
+
+## Pleroma.Emails.Mailer
+* `adapter`: one of the mail adapters listed in [Swoosh readme](https://github.com/swoosh/swoosh#adapters), or `Swoosh.Adapters.Local` for in-memory mailbox.
+* `api_key` / `password` and / or other adapter-specific settings, per the above documentation.
+* `enabled`: Allows enable/disable send emails. Default: `false`.
+
+An example for Sendgrid adapter:
+
+```elixir
+config :pleroma, Pleroma.Emails.Mailer,
+ adapter: Swoosh.Adapters.Sendgrid,
+ api_key: "YOUR_API_KEY"
+```
+
+An example for SMTP adapter:
+
+```elixir
+config :pleroma, Pleroma.Emails.Mailer,
+ adapter: Swoosh.Adapters.SMTP,
+ relay: "smtp.gmail.com",
+ username: "YOUR_USERNAME@gmail.com",
+ password: "YOUR_SMTP_PASSWORD",
+ port: 465,
+ ssl: true,
+ tls: :always,
+ auth: :always
+```
+
+## :uri_schemes
+* `valid_schemes`: List of the scheme part that is considered valid to be an URL
+
+## :instance
+* `name`: The instance’s name
+* `email`: Email used to reach an Administrator/Moderator of the instance
+* `notify_email`: Email used for notifications.
+* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance``
+* `limit`: Posts character limit (CW/Subject included in the counter)
+* `remote_limit`: Hard character limit beyond which remote posts will be dropped.
+* `upload_limit`: File size limit of uploads (except for avatar, background, banner)
+* `avatar_upload_limit`: File size limit of user’s profile avatars
+* `background_upload_limit`: File size limit of user’s profile backgrounds
+* `banner_upload_limit`: File size limit of user’s profile banners
+* `poll_limits`: A map with poll limits for **local** polls
+ * `max_options`: Maximum number of options
+ * `max_option_chars`: Maximum number of characters per option
+ * `min_expiration`: Minimum expiration time (in seconds)
+ * `max_expiration`: Maximum expiration time (in seconds)
+* `registrations_open`: Enable registrations for anyone, invitations can be enabled when false.
+* `invites_enabled`: Enable user invitations for admins (depends on `registrations_open: false`).
+* `account_activation_required`: Require users to confirm their emails before signing in.
+* `federating`: Enable federation with other instances
+* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.
+* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
+* `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance
+* `rewrite_policy`: Message Rewrite Policy, either one or a list. Here are the ones available by default:
+ * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default)
+ * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production
+ * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See ``:mrf_simple`` section)
+ * `Pleroma.Web.ActivityPub.MRF.TagPolicy`: Applies policies to individual users based on tags, which can be set using pleroma-fe/admin-fe/any other app that supports Pleroma Admin API. For example it allows marking posts from individual users nsfw (sensitive)
+ * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (see ``:mrf_subchain`` section)
+ * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See ``:mrf_rejectnonpublic`` section)
+ * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:.
+ * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links.
+ * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed.
+ * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (see `:mrf_mention` section)
+ * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (see `:mrf_vocabulary` section)
+* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network.
+* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send.
+* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json``
+* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML)
+* `mrf_transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo).
+* `mrf_transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.
+* `scope_copy`: Copy the scope (private/unlisted/public) in replies to posts by default.
+* `subject_line_behavior`: Allows changing the default behaviour of subject lines in replies. Valid values:
+ * "email": Copy and preprend re:, as in email.
+ * "masto": Copy verbatim, as in Mastodon.
+ * "noop": Don't copy the subject.
+* `always_show_subject_input`: When set to false, auto-hide the subject field when it's empty.
+* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with
+ older software for theses nicknames.
+* `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature.
+* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow.
+* `no_attachment_links`: Set to true to disable automatically adding attachment link text to statuses
+* `welcome_message`: A message that will be send to a newly registered users as a direct message.
+* `welcome_user_nickname`: The nickname of the local user that sends the welcome message.
+* `max_report_comment_size`: The maximum size of the report comment (Default: `1000`)
+* `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). Default: `false`.
+* `healthcheck`: If set to true, system data will be shown on ``/api/pleroma/healthcheck``.
+* `remote_post_retention_days`: The default amount of days to retain remote posts when pruning the database.
+* `user_bio_length`: A user bio maximum length (default: `5000`)
+* `user_name_length`: A user name maximum length (default: `100`)
+* `skip_thread_containment`: Skip filter out broken threads. The default is `false`.
+* `limit_to_local_content`: Limit unauthenticated users to search for local statutes and users only. Possible values: `:unauthenticated`, `:all` and `false`. The default is `:unauthenticated`.
+* `dynamic_configuration`: Allow transferring configuration to DB with the subsequent customization from Admin api.
+* `max_account_fields`: The maximum number of custom fields in the user profile (default: `10`)
+* `max_remote_account_fields`: The maximum number of custom fields in the remote user profile (default: `20`)
+* `account_field_name_length`: An account field name maximum length (default: `512`)
+* `account_field_value_length`: An account field value maximum length (default: `2048`)
+* `external_user_synchronization`: Enabling following/followers counters synchronization for external users.
+
+
+
+## :logger
+* `backends`: `:console` is used to send logs to stdout, `{ExSyslogger, :ex_syslogger}` to log to syslog, and `Quack.Logger` to log to Slack
+
+An example to enable ONLY ExSyslogger (f/ex in ``prod.secret.exs``) with info and debug suppressed:
+```elixir
+config :logger,
+ backends: [{ExSyslogger, :ex_syslogger}]
+
+config :logger, :ex_syslogger,
+ level: :warn
+```
+
+Another example, keeping console output and adding the pid to syslog output:
+```elixir
+config :logger,
+ backends: [:console, {ExSyslogger, :ex_syslogger}]
+
+config :logger, :ex_syslogger,
+ level: :warn,
+ option: [:pid, :ndelay]
+```
+
+See: [logger’s documentation](https://hexdocs.pm/logger/Logger.html) and [ex_syslogger’s documentation](https://hexdocs.pm/ex_syslogger/)
+
+An example of logging info to local syslog, but warn to a Slack channel:
+```elixir
+config :logger,
+ backends: [ {ExSyslogger, :ex_syslogger}, Quack.Logger ],
+ level: :info
+
+config :logger, :ex_syslogger,
+ level: :info,
+ ident: "pleroma",
+ format: "$metadata[$level] $message"
+
+config :quack,
+ level: :warn,
+ meta: [:all],
+ webhook_url: "https://hooks.slack.com/services/YOUR-API-KEY-HERE"
+```
+
+See the [Quack Github](https://github.com/azohra/quack) for more details
+
+## :frontend_configurations
+
+This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured.
+
+Frontends can access these settings at `/api/pleroma/frontend_configurations`
+
+To add your own configuration for PleromaFE, use it like this:
+
+```elixir
+config :pleroma, :frontend_configurations,
+ pleroma_fe: %{
+ theme: "pleroma-dark",
+ # ... see /priv/static/static/config.json for the available keys.
+},
+ masto_fe: %{
+ showInstanceSpecificPanel: true
+ }
+```
+
+These settings **need to be complete**, they will override the defaults.
+
+NOTE: for versions < 1.0, you need to set [`:fe`](#fe) to false, as shown a few lines below.
+
+## :fe
+__THIS IS DEPRECATED__
+
+If you are using this method, please change it to the [`frontend_configurations`](#frontend_configurations) method.
+Please **set this option to false** in your config like this:
+
+```elixir
+config :pleroma, :fe, false
+```
+
+This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:instance`` is set to false.
+
+* `theme`: Which theme to use, they are defined in ``styles.json``
+* `logo`: URL of the logo, defaults to Pleroma’s logo
+* `logo_mask`: Whether to use only the logo's shape as a mask (true) or as a regular image (false)
+* `logo_margin`: What margin to use around the logo
+* `background`: URL of the background, unless viewing a user profile with a background that is set
+* `redirect_root_no_login`: relative URL which indicates where to redirect when a user isn’t logged in.
+* `redirect_root_login`: relative URL which indicates where to redirect when a user is logged in.
+* `show_instance_panel`: Whenether to show the instance’s specific panel.
+* `scope_options_enabled`: Enable setting an notice visibility and subject/CW when posting
+* `formatting_options_enabled`: Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to ``:instance, allowed_post_formats``
+* `collapse_message_with_subjects`: When a message has a subject(aka Content Warning), collapse it by default
+* `hide_post_stats`: Hide notices statistics(repeats, favorites, …)
+* `hide_user_stats`: Hide profile statistics(posts, posts per day, followers, followings, …)
+
+## :assets
+
+This section configures assets to be used with various frontends. Currently the only option
+relates to mascots on the mastodon frontend
+
+* `mascots`: KeywordList of mascots, each element __MUST__ contain both a `url` and a
+ `mime_type` key.
+* `default_mascot`: An element from `mascots` - This will be used as the default mascot
+ on MastoFE (default: `:pleroma_fox_tan`)
+
+## :mrf_simple
+* `media_removal`: List of instances to remove medias from
+* `media_nsfw`: List of instances to put medias as NSFW(sensitive) from
+* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline
+* `reject`: List of instances to reject any activities from
+* `accept`: List of instances to accept any activities from
+* `report_removal`: List of instances to reject reports from
+* `avatar_removal`: List of instances to strip avatars from
+* `banner_removal`: List of instances to strip banners from
+
+## :mrf_subchain
+This policy processes messages through an alternate pipeline when a given message matches certain criteria.
+All criteria are configured as a map of regular expressions to lists of policy modules.
+
+* `match_actor`: Matches a series of regular expressions against the actor field.
+
+Example:
+
+```
+config :pleroma, :mrf_subchain,
+ match_actor: %{
+ ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy]
+ }
+```
+
+## :mrf_rejectnonpublic
+* `allow_followersonly`: whether to allow followers-only posts
+* `allow_direct`: whether to allow direct messages
+
+## :mrf_hellthread
+* `delist_threshold`: Number of mentioned users after which the message gets delisted (the message can still be seen, but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable.
+* `reject_threshold`: Number of mentioned users after which the messaged gets rejected. Set to 0 to disable.
+
+## :mrf_keyword
+* `reject`: A list of patterns which result in message being rejected, each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html)
+* `federated_timeline_removal`: A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html)
+* `replace`: A list of tuples containing `{pattern, replacement}`, `pattern` can be a string or a [regular expression](https://hexdocs.pm/elixir/Regex.html)
+
+## :mrf_mention
+* `actors`: A list of actors, for which to drop any posts mentioning.
+
+## :mrf_vocabulary
+* `accept`: A list of ActivityStreams terms to accept. If empty, all supported messages are accepted.
+* `reject`: A list of ActivityStreams terms to reject. If empty, no messages are rejected.
+
+## :media_proxy
+* `enabled`: Enables proxying of remote media to the instance’s proxy
+* `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.
+* `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`.
+* `whitelist`: List of domains to bypass the mediaproxy
+
+## :gopher
+* `enabled`: Enables the gopher interface
+* `ip`: IP address to bind to
+* `port`: Port to bind to
+* `dstport`: Port advertised in urls (optional, defaults to `port`)
+
+## Pleroma.Web.Endpoint
+`Phoenix` endpoint configuration, all configuration options can be viewed [here](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-dynamic-configuration), only common options are listed here
+* `http` - a list containing http protocol configuration, all configuration options can be viewed [here](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html#module-options), only common options are listed here. For deployment using docker, you need to set this to `[ip: {0,0,0,0}, port: 4000]` to make pleroma accessible from other containers (such as your nginx server).
+ - `ip` - a tuple consisting of 4 integers
+ - `port`
+* `url` - a list containing the configuration for generating urls, accepts
+ - `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`)
+ - `scheme` - e.g `http`, `https`
+ - `port`
+ - `path`
+* `extra_cookie_attrs` - a list of `Key=Value` strings to be added as non-standard cookie attributes. Defaults to `["SameSite=Lax"]`. See the [SameSite article](https://www.owasp.org/index.php/SameSite) on OWASP for more info.
+
+
+
+**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
+
+Example:
+```elixir
+config :pleroma, Pleroma.Web.Endpoint,
+ url: [host: "example.com", port: 2020, scheme: "https"],
+ http: [
+ # start copied from config.exs
+ dispatch: [
+ {:_,
+ [
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}
+ # end copied from config.exs
+ ],
+ port: 8080,
+ ip: {127, 0, 0, 1}
+ ]
+```
+
+This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020`
+
+## :activitypub
+* ``unfollow_blocked``: Whether blocks result in people getting unfollowed
+* ``outgoing_blocks``: Whether to federate blocks to other instances
+* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question
+* ``sign_object_fetches``: Sign object fetches with HTTP signatures
+
+## :http_security
+* ``enabled``: Whether the managed content security policy is enabled
+* ``sts``: Whether to additionally send a `Strict-Transport-Security` header
+* ``sts_max_age``: The maximum age for the `Strict-Transport-Security` header if sent
+* ``ct_max_age``: The maximum age for the `Expect-CT` header if sent
+* ``referrer_policy``: The referrer policy to use, either `"same-origin"` or `"no-referrer"`
+* ``report_uri``: Adds the specified url to `report-uri` and `report-to` group in CSP header.
+
+## :mrf_user_allowlist
+
+The keys in this section are the domain names that the policy should apply to.
+Each key should be assigned a list of users that should be allowed through by
+their ActivityPub ID.
+
+An example:
+
+```elixir
+config :pleroma, :mrf_user_allowlist,
+ "example.org": ["https://example.org/users/admin"]
+```
+
+## :web_push_encryption, :vapid_details
+
+Web Push Notifications configuration. You can use the mix task `mix web_push.gen.keypair` to generate it.
+
+* ``subject``: a mailto link for the administrative contact. It’s best if this email is not a personal email address, but rather a group email so that if a person leaves an organization, is unavailable for an extended period, or otherwise can’t respond, someone else on the list can.
+* ``public_key``: VAPID public key
+* ``private_key``: VAPID private key
+
+## Pleroma.Captcha
+* `enabled`: Whether the captcha should be shown on registration
+* `method`: The method/service to use for captcha
+* `seconds_valid`: The time in seconds for which the captcha is valid
+
+### Pleroma.Captcha.Kocaptcha
+Kocaptcha is a very simple captcha service with a single API endpoint,
+the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint
+`https://captcha.kotobank.ch` is hosted by the developer.
+
+* `endpoint`: the kocaptcha endpoint to use
+
+## :admin_token
+
+Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter. Example:
+
+```elixir
+config :pleroma, :admin_token, "somerandomtoken"
+```
+
+You can then do
+
+```sh
+curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken"
+```
+
+## Oban
+
+[Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration.
+
+Configuration options described in [Oban readme](https://github.com/sorentwo/oban#usage):
+* `repo` - app's Ecto repo (`Pleroma.Repo`)
+* `verbose` - logs verbosity
+* `prune` - non-retryable jobs [pruning settings](https://github.com/sorentwo/oban#pruning) (`:disabled` / `{:maxlen, value}` / `{:maxage, value}`)
+* `queues` - job queues (see below)
+
+Pleroma has the following queues:
+
+* `activity_expiration` - Activity expiration
+* `federator_outgoing` - Outgoing federation
+* `federator_incoming` - Incoming federation
+* `mailer` - Email sender, see [`Pleroma.Emails.Mailer`](#pleromaemailsmailer)
+* `transmogrifier` - Transmogrifier
+* `web_push` - Web push notifications
+* `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivity`](#pleromascheduledactivity)
+
+Example:
+
+```elixir
+config :pleroma, Oban,
+ repo: Pleroma.Repo,
+ verbose: false,
+ prune: {:maxlen, 1500},
+ queues: [
+ federator_incoming: 50,
+ federator_outgoing: 50
+ ]
+```
+
+This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the number of max concurrent jobs set to `50`.
+
+### Migrating `pleroma_job_queue` settings
+
+`config :pleroma_job_queue, :queues` is replaced by `config :pleroma, Oban, :queues` and uses the same format (keys are queues' names, values are max concurrent jobs numbers).
+
+### Note on running with PostgreSQL in silent mode
+
+If you are running PostgreSQL in [`silent_mode`](https://postgresqlco.nf/en/doc/param/silent_mode?version=9.1), it's advised to set [`log_destination`](https://postgresqlco.nf/en/doc/param/log_destination?version=9.1) to `syslog`,
+otherwise `postmaster.log` file may grow because of "you don't own a lock of type ShareLock" warnings (see https://github.com/sorentwo/oban/issues/52).
+
+## :workers
+
+Includes custom worker options not interpretable directly by `Oban`.
+
+* `retries` — keyword lists where keys are `Oban` queues (see above) and values are numbers of max attempts for failed jobs.
+
+Example:
+
+```elixir
+config :pleroma, :workers,
+ retries: [
+ federator_incoming: 5,
+ federator_outgoing: 5
+ ]
+```
+
+### Migrating `Pleroma.Web.Federator.RetryQueue` settings
+
+* `max_retries` is replaced with `config :pleroma, :workers, retries: [federator_outgoing: 5]`
+* `enabled: false` corresponds to `config :pleroma, :workers, retries: [federator_outgoing: 1]`
+* deprecated options: `max_jobs`, `initial_timeout`
+
+## Pleroma.Web.Metadata
+* `providers`: a list of metadata providers to enable. Providers available:
+ * Pleroma.Web.Metadata.Providers.OpenGraph
+ * Pleroma.Web.Metadata.Providers.TwitterCard
+ * Pleroma.Web.Metadata.Providers.RelMe - add links from user bio with rel=me into the `<header>` as `<link rel=me>`
+* `unfurl_nsfw`: If set to `true` nsfw attachments will be shown in previews
+
+## :rich_media
+* `enabled`: if enabled the instance will parse metadata from attached links to generate link previews
+* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`.
+* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"]
+* `parsers`: list of Rich Media parsers
+
+## :fetch_initial_posts
+* `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts
+* `pages`: the amount of pages to fetch
+
+## :hackney_pools
+
+Advanced. Tweaks Hackney (http client) connections pools.
+
+There's three pools used:
+
+* `:federation` for the federation jobs.
+ You may want this pool max_connections to be at least equal to the number of federator jobs + retry queue jobs.
+* `:media` for rich media, media proxy
+* `:upload` for uploaded media (if using a remote uploader and `proxy_remote: true`)
+
+For each pool, the options are:
+
+* `max_connections` - how much connections a pool can hold
+* `timeout` - retention duration for connections
+
+## :auto_linker
+
+Configuration for the `auto_linker` library:
+
+* `class: "auto-linker"` - specify the class to be added to the generated link. false to clear
+* `rel: "noopener noreferrer"` - override the rel attribute. false to clear
+* `new_window: true` - set to false to remove `target='_blank'` attribute
+* `scheme: false` - Set to true to link urls with schema `http://google.com`
+* `truncate: false` - Set to a number to truncate urls longer then the number. Truncated urls will end in `..`
+* `strip_prefix: true` - Strip the scheme prefix
+* `extra: false` - link urls with rarely used schemes (magnet, ipfs, irc, etc.)
+
+Example:
+
+```elixir
+config :auto_linker,
+ opts: [
+ scheme: true,
+ extra: true,
+ class: false,
+ strip_prefix: false,
+ new_window: false,
+ rel: "ugc"
+ ]
+```
+
+## Pleroma.Scheduler
+
+Configuration for [Quantum](https://github.com/quantum-elixir/quantum-core) jobs scheduler.
+
+See [Quantum readme](https://github.com/quantum-elixir/quantum-core#usage) for the list of supported options.
+
+Example:
+
+```elixir
+config :pleroma, Pleroma.Scheduler,
+ global: true,
+ overlap: true,
+ timezone: :utc,
+ jobs: [{"0 */6 * * * *", {Pleroma.Web.Websub, :refresh_subscriptions, []}}]
+```
+
+The above example defines a single job which invokes `Pleroma.Web.Websub.refresh_subscriptions()` every 6 hours ("0 */6 * * * *", [crontab format](https://en.wikipedia.org/wiki/Cron)).
+
+## Pleroma.ScheduledActivity
+
+* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`)
+* `total_user_limit`: the number of scheduled activities a user is allowed to create in total (Default: `300`)
+* `enabled`: whether scheduled activities are sent to the job queue to be executed
+
+## Pleroma.ActivityExpiration
+
+# `enabled`: whether expired activities will be sent to the job queue to be deleted
+
+## Pleroma.Web.Auth.Authenticator
+
+* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
+* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
+
+## :ldap
+
+Use LDAP for user authentication. When a user logs in to the Pleroma
+instance, the name and password will be verified by trying to authenticate
+(bind) to an LDAP server. If a user exists in the LDAP directory but there
+is no account with the same name yet on the Pleroma instance then a new
+Pleroma account will be created with the same name as the LDAP user name.
+
+* `enabled`: enables LDAP authentication
+* `host`: LDAP server hostname
+* `port`: LDAP port, e.g. 389 or 636
+* `ssl`: true to use SSL, usually implies the port 636
+* `sslopts`: additional SSL options
+* `tls`: true to start TLS, usually implies the port 389
+* `tlsopts`: additional TLS options
+* `base`: LDAP base, e.g. "dc=example,dc=com"
+* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
+
+## BBS / SSH access
+
+To enable simple command line interface accessible over ssh, add a setting like this to your configuration file:
+
+```exs
+app_dir = File.cwd!
+priv_dir = Path.join([app_dir, "priv/ssh_keys"])
+
+config :esshd,
+ enabled: true,
+ priv_dir: priv_dir,
+ handler: "Pleroma.BBS.Handler",
+ port: 10_022,
+ password_authenticator: "Pleroma.BBS.Authenticator"
+```
+
+Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -m PEM -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT`
+
+## :auth
+
+* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
+* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
+
+Authentication / authorization settings.
+
+* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`.
+* `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`.
+* `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by `OAUTH_CONSUMER_STRATEGIES` environment variable. Each entry in this space-delimited string should be of format `<strategy>` or `<strategy>:<dependency>` (e.g. `twitter` or `keycloak:ueberauth_keycloak_strategy` in case dependency is named differently than `ueberauth_<strategy>`).
+
+## :email_notifications
+
+Email notifications settings.
+
+ - digest - emails of "what you've missed" for users who have been
+ inactive for a while.
+ - active: globally enable or disable digest emails
+ - schedule: When to send digest email, in [crontab format](https://en.wikipedia.org/wiki/Cron).
+ "0 0 * * 0" is the default, meaning "once a week at midnight on Sunday morning"
+ - interval: Minimum interval between digest emails to one user
+ - inactivity_threshold: Minimum user inactivity threshold
+
+## Pleroma.Emails.UserEmail
+
+- `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo.
+- `:styling` - a map with color settings for email templates.
+
+## OAuth consumer mode
+
+OAuth consumer mode allows sign in / sign up via external OAuth providers (e.g. Twitter, Facebook, Google, Microsoft, etc.).
+Implementation is based on Ueberauth; see the list of [available strategies](https://github.com/ueberauth/ueberauth/wiki/List-of-Strategies).
+
+Note: each strategy is shipped as a separate dependency; in order to get the strategies, run `OAUTH_CONSUMER_STRATEGIES="..." mix deps.get`,
+e.g. `OAUTH_CONSUMER_STRATEGIES="twitter facebook google microsoft" mix deps.get`.
+The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.server` in case you enable any strategies.
+
+Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies.
+
+Note: make sure that `"SameSite=Lax"` is set in `extra_cookie_attrs` when you have this feature enabled. OAuth consumer mode will not work with `"SameSite=Strict"`
+
+* For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https://<your_host>/oauth/twitter/callback
+
+* For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https://<your_host>/oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps/<app_id>/fb-login/settings/
+
+* For Google, [register an app](https://console.developers.google.com), configure callback URL to https://<your_host>/oauth/google/callback
+
+* For Microsoft, [register an app](https://portal.azure.com), configure callback URL to https://<your_host>/oauth/microsoft/callback
+
+Once the app is configured on external OAuth provider side, add app's credentials and strategy-specific settings (if any — e.g. see Microsoft below) to `config/prod.secret.exs`,
+per strategy's documentation (e.g. [ueberauth_twitter](https://github.com/ueberauth/ueberauth_twitter)). Example config basing on environment variables:
+
+```elixir
+# Twitter
+config :ueberauth, Ueberauth.Strategy.Twitter.OAuth,
+ consumer_key: System.get_env("TWITTER_CONSUMER_KEY"),
+ consumer_secret: System.get_env("TWITTER_CONSUMER_SECRET")
+
+# Facebook
+config :ueberauth, Ueberauth.Strategy.Facebook.OAuth,
+ client_id: System.get_env("FACEBOOK_APP_ID"),
+ client_secret: System.get_env("FACEBOOK_APP_SECRET"),
+ redirect_uri: System.get_env("FACEBOOK_REDIRECT_URI")
+
+# Google
+config :ueberauth, Ueberauth.Strategy.Google.OAuth,
+ client_id: System.get_env("GOOGLE_CLIENT_ID"),
+ client_secret: System.get_env("GOOGLE_CLIENT_SECRET"),
+ redirect_uri: System.get_env("GOOGLE_REDIRECT_URI")
+
+# Microsoft
+config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth,
+ client_id: System.get_env("MICROSOFT_CLIENT_ID"),
+ client_secret: System.get_env("MICROSOFT_CLIENT_SECRET")
+
+config :ueberauth, Ueberauth,
+ providers: [
+ microsoft: {Ueberauth.Strategy.Microsoft, [callback_params: []]}
+ ]
+
+# Keycloak
+# Note: make sure to add `keycloak:ueberauth_keycloak_strategy` entry to `OAUTH_CONSUMER_STRATEGIES` environment variable
+keycloak_url = "https://publicly-reachable-keycloak-instance.org:8080"
+
+config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth,
+ client_id: System.get_env("KEYCLOAK_CLIENT_ID"),
+ client_secret: System.get_env("KEYCLOAK_CLIENT_SECRET"),
+ site: keycloak_url,
+ authorize_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/auth",
+ token_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/token",
+ userinfo_url: "#{keycloak_url}/auth/realms/master/protocol/openid-connect/userinfo",
+ token_method: :post
+
+config :ueberauth, Ueberauth,
+ providers: [
+ keycloak: {Ueberauth.Strategy.Keycloak, [uid_field: :email]}
+ ]
+```
+
+## OAuth 2.0 provider - :oauth2
+
+Configure OAuth 2 provider capabilities:
+
+* `token_expires_in` - The lifetime in seconds of the access token.
+* `issue_new_refresh_token` - Keeps old refresh token or generate new refresh token when to obtain an access token.
+* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`.
+* `clean_expired_tokens_interval` - Interval to run the job to clean expired tokens. Defaults to `86_400_000` (24 hours).
+
+## :emoji
+* `shortcode_globs`: Location of custom emoji files. `*` can be used as a wildcard. Example `["/emoji/custom/**/*.png"]`
+* `pack_extensions`: A list of file extensions for emojis, when no emoji.txt for a pack is present. Example `[".png", ".gif"]`
+* `groups`: Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. `*` can be used as a wildcard. Example `[Custom: ["/emoji/*.png", "/emoji/custom/*.png"]]`
+* `default_manifest`: Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays).
+* `shared_pack_cache_seconds_per_file`: When an emoji pack is shared, the archive is created and cached in
+ memory for this amount of seconds multiplied by the number of files.
+
+## Database options
+
+### RUM indexing for full text search
+* `rum_enabled`: If RUM indexes should be used. Defaults to `false`.
+
+RUM indexes are an alternative indexing scheme that is not included in PostgreSQL by default. While they may eventually be mainlined, for now they have to be installed as a PostgreSQL extension from https://github.com/postgrespro/rum.
+
+Their advantage over the standard GIN indexes is that they allow efficient ordering of search results by timestamp, which makes search queries a lot faster on larger servers, by one or two orders of magnitude. They take up around 3 times as much space as GIN indexes.
+
+To enable them, both the `rum_enabled` flag has to be set and the following special migration has to be run:
+
+`mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/`
+
+This will probably take a long time.
+
+## :rate_limit
+
+This is an advanced feature and disabled by default.
+
+If your instance is behind a reverse proxy you must enable and configure [`Pleroma.Plugs.RemoteIp`](#pleroma-plugs-remoteip).
+
+A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where:
+
+* The first element: `scale` (Integer). The time scale in milliseconds.
+* The second element: `limit` (Integer). How many requests to limit in the time scale provided.
+
+It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated.
+
+See [`Pleroma.Plugs.RateLimiter`](Pleroma.Plugs.RateLimiter.html) documentation for examples.
+
+Supported rate limiters:
+
+* `:search` for the search requests (account & status search etc.)
+* `:app_account_creation` for registering user accounts from the same IP address
+* `:relations_actions` for actions on relations with all users (follow, unfollow)
+* `:relation_id_action` for actions on relation with a specific user (follow, unfollow)
+* `:statuses_actions` for create / delete / fav / unfav / reblog / unreblog actions on any statuses
+* `:status_id_action` for fav / unfav or reblog / unreblog actions on the same status by the same user
+
+## :web_cache_ttl
+
+The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration.
+
+Available caches:
+
+* `:activity_pub` - activity pub routes (except question activities). Defaults to `nil` (no expiration).
+* `:activity_pub_question` - activity pub routes (question activities). Defaults to `30_000` (30 seconds).
+
+## Pleroma.Plugs.RemoteIp
+
+**If your instance is not behind at least one reverse proxy, you should not enable this plug.**
+
+`Pleroma.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.
+
+Available options:
+
+* `enabled` - Enable/disable the plug. Defaults to `false`.
+* `headers` - A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`.
+* `proxies` - A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`.
+* `reserved` - Defaults to [localhost](https://en.wikipedia.org/wiki/Localhost) and [private network](https://en.wikipedia.org/wiki/Private_network).
diff --git a/docs/configuration/custom_emoji.md b/docs/configuration/custom_emoji.md
new file mode 100644
index 000000000..f72c0edbc
--- /dev/null
+++ b/docs/configuration/custom_emoji.md
@@ -0,0 +1,68 @@
+# Custom Emoji
+
+Before you add your own custom emoji, check if they are available in an existing pack.
+See `Mix.Tasks.Pleroma.Emoji` for information about emoji packs.
+
+To add custom emoji:
+* Create the `STATIC-DIR/emoji/` directory if it doesn't exist
+ (`STATIC-DIR` is configurable, `instance/static/` by default)
+* Create a directory with whatever name you want (custom is a good name to show the purpose of it).
+ This will create a local emoji pack.
+* Put your `.png` emoji files in that directory. In case of conflicts, you can create an `emoji.txt`
+ file in that directory and specify a custom shortcode using the following format:
+ `shortcode, file-path, tag1, tag2, etc`. One emoji per line. Note that if you do so,
+ you'll have to list all other emojis in the pack too.
+* Either restart pleroma or connect to the iex session pleroma's running and
+ run `Pleroma.Emoji.reload/0` in it.
+
+Example:
+
+image files (in `instance/static/emoji/custom`): `happy.png` and `sad.png`
+
+content of `emoji.txt`:
+```
+happy, /emoji/custom/happy.png, Tag1,Tag2
+sad, /emoji/custom/sad.png, Tag1
+foo, /emoji/custom/foo.png
+```
+
+The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) and under 50kb for compatibility with mastodon.
+
+Default file extentions and locations for emojis are set in `config.exs`. To use different locations or file-extentions, add the `shortcode_globs` to your secrets file (`prod.secret.exs` or `dev.secret.exs`) and edit it. Note that not all fediverse-software will show emojis with other file extentions:
+```elixir
+config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png", "/emoji/custom/**/*.gif"]
+```
+
+## Emoji tags (groups)
+
+Default tags are set in `config.exs`. To set your own tags, copy the structure to your secrets file (`prod.secret.exs` or `dev.secret.exs`) and edit it.
+```elixir
+config :pleroma, :emoji,
+ shortcode_globs: ["/emoji/custom/**/*.png"],
+ groups: [
+ Finmoji: "/finmoji/128px/*-128.png",
+ Custom: ["/emoji/*.png", "/emoji/custom/*.png"]
+ ]
+```
+
+Order of the `groups` matters, so to override default tags just put your group on top of the list. E.g:
+```elixir
+config :pleroma, :emoji,
+ shortcode_globs: ["/emoji/custom/**/*.png"],
+ groups: [
+ "Finmoji special": "/finmoji/128px/a_trusted_friend-128.png", # special file
+ "Cirno": "/emoji/custom/cirno*.png", # png files in /emoji/custom/ which start with `cirno`
+ "Special group": "/emoji/custom/special_folder/*.png", # png files in /emoji/custom/special_folder/
+ "Another group": "/emoji/custom/special_folder/*/.png", # png files in /emoji/custom/special_folder/ subfolders
+ Finmoji: "/finmoji/128px/*-128.png",
+ Custom: ["/emoji/*.png", "/emoji/custom/*.png"]
+ ]
+```
+
+Priority of tags assigns in emoji.txt and custom.txt:
+
+`tag in file > special group setting in config.exs > default setting in config.exs`
+
+Priority for globs:
+
+`special group setting in config.exs > default setting in config.exs`
diff --git a/docs/configuration/hardening.md b/docs/configuration/hardening.md
new file mode 100644
index 000000000..b54c28850
--- /dev/null
+++ b/docs/configuration/hardening.md
@@ -0,0 +1,103 @@
+# Hardening your instance
+Here are some suggestions which improve the security of parts of your Pleroma instance.
+
+## Configuration file
+
+These changes should go into `prod.secret.exs` or `dev.secret.exs`, depending on your `MIX_ENV` value.
+
+### `http`
+
+> Recommended value: `[ip: {127, 0, 0, 1}]`
+
+This sets the Pleroma application server to only listen to the localhost interface. This way, you can only reach your server over the Internet by going through the reverse proxy. By default, Pleroma listens on all interfaces.
+
+### `secure_cookie_flag`
+
+> Recommended value: `true`
+
+This sets the `secure` flag on Pleroma’s session cookie. This makes sure, that the cookie is only accepted over encrypted HTTPs connections. This implicitly renames the cookie from `pleroma_key` to `__Host-pleroma-key` which enforces some restrictions. (see [cookie prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Cookie_prefixes))
+
+### `:http_security`
+
+> Recommended value: `true`
+
+This will send additional HTTP security headers to the clients, including:
+
+* `X-XSS-Protection: "1; mode=block"`
+* `X-Permitted-Cross-Domain-Policies: "none"`
+* `X-Frame-Options: "DENY"`
+* `X-Content-Type-Options: "nosniff"`
+* `X-Download-Options: "noopen"`
+
+A content security policy (CSP) will also be set:
+
+```csp
+content-security-policy:
+ default-src 'none';
+ base-uri 'self';
+ frame-ancestors 'none';
+ img-src 'self' data: https:;
+ media-src 'self' https:;
+ style-src 'self' 'unsafe-inline';
+ font-src 'self';
+ script-src 'self';
+ connect-src 'self' wss://example.tld;
+ manifest-src 'self';
+ upgrade-insecure-requests;
+```
+
+#### `sts`
+
+> Recommended value: `true`
+
+An additional “Strict transport security” header will be sent with the configured `sts_max_age` parameter. This tells the browser, that the domain should only be accessed over a secure HTTPs connection.
+
+#### `ct_max_age`
+
+An additional “Expect-CT” header will be sent with the configured `ct_max_age` parameter. This enforces the use of TLS certificates that are published in the certificate transparency log. (see [Expect-CT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT))
+
+#### `referrer_policy`
+
+> Recommended value: `same-origin`
+
+If you click on a link, your browser’s request to the other site will include from where it is coming from. The “Referrer policy” header tells the browser how and if it should send this information. (see [Referrer policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy))
+
+## systemd
+
+A systemd unit example is provided at `installation/pleroma.service`.
+
+### PrivateTmp
+
+> Recommended value: `true`
+
+Use private `/tmp` and `/var/tmp` folders inside a new file system namespace, which are discarded after the process stops.
+
+### ProtectHome
+
+> Recommended value: `true`
+
+The `/home`, `/root`, and `/run/user` folders can not be accessed by this service anymore. If your Pleroma user has its home folder in one of the restricted places, or use one of these folders as its working directory, you have to set this to `false`.
+
+### ProtectSystem
+
+> Recommended value: `full`
+
+Mount `/usr`, `/boot`, and `/etc` as read-only for processes invoked by this service.
+
+### PrivateDevices
+
+> Recommended value: `true`
+
+Sets up a new `/dev` mount for the process and only adds API pseudo devices like `/dev/null`, `/dev/zero` or `/dev/random` but not physical devices. This may not work on devices like the Raspberry Pi, where you need to set this to `false`.
+
+### NoNewPrivileges
+
+> Recommended value: `true`
+
+Ensures that the service process and all its children can never gain new privileges through `execve()`.
+
+### CapabilityBoundingSet
+
+> Recommended value: `~CAP_SYS_ADMIN`
+
+Drops the sysadmin capability from the daemon.
diff --git a/docs/configuration/howto_mediaproxy.md b/docs/configuration/howto_mediaproxy.md
new file mode 100644
index 000000000..16c40c5db
--- /dev/null
+++ b/docs/configuration/howto_mediaproxy.md
@@ -0,0 +1,34 @@
+# How to activate mediaproxy
+## Explanation
+
+Without the `mediaproxy` function, Pleroma doesn't store any remote content like pictures, video etc. locally. So every time you open Pleroma, the content is loaded from the source server, from where the post is coming. This can result in slowly loading content or/and increased bandwidth usage on the source server.
+With the `mediaproxy` function you can use nginx to cache this content, so users can access it faster, because it's loaded from your server.
+
+## Activate it
+
+* Edit your nginx config and add the following location:
+```
+location /proxy {
+ proxy_cache pleroma_media_cache;
+ proxy_cache_lock on;
+ proxy_pass http://localhost:4000;
+}
+```
+Also add the following on top of the configuration, outside of the `server` block:
+```
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off;
+```
+If you came here from one of the installation guides, take a look at the example configuration `/installation/pleroma.nginx`, where this part is already included.
+
+* Append the following to your `prod.secret.exs` or `dev.secret.exs` (depends on which mode your instance is running):
+```
+config :pleroma, :media_proxy,
+ enabled: true,
+ proxy_opts: [
+ redirect_on_failure: true
+ ]
+ #base_url: "https://cache.pleroma.social"
+```
+If you want to use a subdomain to serve the files, uncomment `base_url`, change the url and add a comma after `true` in the previous line.
+
+* Restart nginx and Pleroma
diff --git a/docs/configuration/howto_mongooseim.md b/docs/configuration/howto_mongooseim.md
new file mode 100644
index 000000000..a33e590a1
--- /dev/null
+++ b/docs/configuration/howto_mongooseim.md
@@ -0,0 +1,10 @@
+# Configuring MongooseIM (XMPP Server) to use Pleroma for authentication
+
+If you want to give your Pleroma users an XMPP (chat) account, you can configure [MongooseIM](https://github.com/esl/MongooseIM) to use your Pleroma server for user authentication, automatically giving every local user an XMPP account.
+
+In general, you just have to follow the configuration described at [https://mongooseim.readthedocs.io/en/latest/authentication-backends/HTTP-authentication-module/](https://mongooseim.readthedocs.io/en/latest/authentication-backends/HTTP-authentication-module/) and do these changes to your mongooseim.cfg.
+
+1. Set the auth_method to `{auth_method, http}`.
+2. Add the http auth pool like this: `{http, global, auth, [{workers, 50}], [{server, "https://yourpleromainstance.com"}]}`
+
+Restart your MongooseIM server, your users should now be able to connect with their Pleroma credentials.
diff --git a/docs/configuration/howto_proxy.md b/docs/configuration/howto_proxy.md
new file mode 100644
index 000000000..10a635266
--- /dev/null
+++ b/docs/configuration/howto_proxy.md
@@ -0,0 +1,12 @@
+# How to configure upstream proxy for federation
+If you want to proxify all http requests (e.g. for TOR) that pleroma makes to an upstream proxy server, edit you config file (`dev.secret.exs` or `prod.secret.exs`) and add the following:
+
+```
+config :pleroma, :http,
+ proxy_url: "127.0.0.1:8123"
+```
+
+The other way to do it, for example, with Tor you would most likely add something like this:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050}
+```
diff --git a/docs/configuration/howto_set_richmedia_cache_ttl_based_on_image.md b/docs/configuration/howto_set_richmedia_cache_ttl_based_on_image.md
new file mode 100644
index 000000000..bfee5a9e6
--- /dev/null
+++ b/docs/configuration/howto_set_richmedia_cache_ttl_based_on_image.md
@@ -0,0 +1,33 @@
+# How to set rich media cache ttl based on image ttl
+## Explanation
+
+Richmedia are cached without the ttl but the rich media may have image which can expire, like aws signed url.
+In such cases the old image url (expired) is returned from the media cache.
+
+So to avoid such situation we can define a module that will set ttl based on image.
+The module must adopt behaviour `Pleroma.Web.RichMedia.Parser.TTL`
+
+### Example
+
+```exs
+defmodule MyModule do
+ @behaviour Pleroma.Web.RichMedia.Parser.TTL
+
+ @impl Pleroma.Web.RichMedia.Parser.TTL
+ def ttl(data, url) do
+ image_url = Map.get(data, :image)
+ # do some parsing in the url and get the ttl of the image
+ # return ttl is unix time
+ parse_ttl_from_url(image_url)
+ end
+end
+```
+
+And update the config
+
+```exs
+config :pleroma, :rich_media,
+ ttl_setters: [Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl, MyModule]
+```
+
+> For reference there is a parser for AWS signed URL `Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl`, it's enabled by default.
diff --git a/docs/configuration/howto_user_recomendation.md b/docs/configuration/howto_user_recomendation.md
new file mode 100644
index 000000000..c4d749d0c
--- /dev/null
+++ b/docs/configuration/howto_user_recomendation.md
@@ -0,0 +1,31 @@
+# How to activate user recommendation (Who to follow panel)
+![who-to-follow-panel-small](/uploads/9de1b1300436c32461d272945f1bc23e/who-to-follow-panel-small.png)
+
+To show the *who to follow* panel, edit `config/prod.secret.exs` in the Pleroma backend. Following code activates the *who to follow* panel:
+
+```elixir
+config :pleroma, :suggestions,
+ enabled: true,
+ third_party_engine:
+ "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}",
+ timeout: 300_000,
+ limit: 40,
+ web: "https://vinayaka.distsn.org"
+
+```
+
+`config/config.exs` already includes this code, but `enabled:` is `false`.
+
+`/api/v1/suggestions` is also provided when *who to follow* panel is enabled.
+
+For advanced customization, following code shows the newcomers of the fediverse at the *who to follow* panel:
+
+```elixir
+config :pleroma, :suggestions,
+ enabled: true,
+ third_party_engine:
+ "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-new-suggestions-api.cgi?{{host}}+{{user}}",
+ timeout: 60_000,
+ limit: 40,
+ web: "https://vinayaka.distsn.org/user-new.html"
+```
diff --git a/docs/configuration/i2p.md b/docs/configuration/i2p.md
new file mode 100644
index 000000000..62ced8b7a
--- /dev/null
+++ b/docs/configuration/i2p.md
@@ -0,0 +1,196 @@
+# I2P Federation and Accessability
+
+This guide is going to focus on the Pleroma federation aspect. The actual installation is neatly explained in the official documentation, and more likely to remain up-to-date.
+It might be added to this guide if there will be a need for that.
+
+We're going to use I2PD for its lightweightness over the official client.
+Follow the documentation according to your distro: https://i2pd.readthedocs.io/en/latest/user-guide/install/#installing
+
+How to run it: https://i2pd.readthedocs.io/en/latest/user-guide/run/
+
+## I2P Federation
+
+There are 2 ways to go about this.
+One using the config, and one using external software (fedproxy). The external software works better so far.
+
+### Using the Config
+
+**Warning:** So far, everytime I followed this way of federating using I2P, the rest of my federation stopped working. I'm leaving this here in case it will help with making it work.
+
+Assuming you're running in prod, cd to your Pleroma folder and append the following to `config/prod.secret.exs`:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 4447}
+```
+And then run the following:
+```
+su pleroma
+MIX_ENV=prod mix deps.get
+MIX_ENV=prod mix ecto.migrate
+exit
+```
+You can restart I2PD here and finish if you don't wish to make your instance viewable or accessible over I2P.
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+You can change the socks proxy port in `/etc/i2pd/i2pd.conf`.
+
+### Using Fedproxy
+
+Fedproxy passes through clearnet requests direct to where they are going. It doesn't force anything over Tor.
+
+To use [fedproxy](https://github.com/majestrate/fedproxy) you'll need to install Golang.
+```
+apt install golang
+```
+Use a different user than pleroma or root. Run the following to add the Gopath to your ~/.bashrc.
+```
+echo "export GOPATH=/home/ren/.go" >> ~/.bashrc
+```
+Restart that bash session (you can exit and log back in).
+Run the following to get fedproxy.
+```
+go get -u github.com/majestrate/fedproxy$
+cp $(GOPATH)/bin/fedproxy /usr/local/bin/fedproxy
+```
+And then the following to start it for I2P only.
+```
+fedproxy 127.0.0.1:2000 127.0.0.1:4447
+```
+If you want to also use it for Tor, add `127.0.0.1:9050` to that command.
+You'll also need to modify your Pleroma config.
+
+Assuming you're running in prod, cd to your Pleroma folder and append the following to `config/prod.secret.exs`:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 2000}
+```
+And then run the following:
+```
+su pleroma
+MIX_ENV=prod mix deps.get
+MIX_ENV=prod mix ecto.migrate
+exit
+```
+You can restart I2PD here and finish if you don't wish to make your instance viewable or accessible over I2P.
+
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+You can change the socks proxy port in `/etc/i2pd/i2pd.conf`.
+
+## I2P Instance Access
+
+Make your instance accessible using I2P.
+
+Add the following to your I2PD config `/etc/i2pd/tunnels.conf`:
+```
+[pleroma]
+type = http
+host = 127.0.0.1
+port = 14447
+keys = pleroma.dat
+```
+Restart I2PD:
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+Now you'll have to find your address.
+To do that you can download and use I2PD tools.[^1]
+Or you'll need to access your web-console on localhost:7070.
+If you don't have a GUI, you'll have to SSH tunnel into it like this:
+`ssh -L 7070:127.0.0.1:7070 user@ip -p port`.
+Now you can access it at localhost:7070.
+Go to I2P tunnels page. Look for Server tunnels and you will see an address that ends with `.b32.i2p` next to "pleroma".
+This is your site's address.
+
+### I2P-only Instance
+
+If creating an I2P-only instance, open `config/prod.secret.exs` and under "config :pleroma, Pleroma.Web.Endpoint," edit "https" and "port: 443" to the following:
+```
+ url: [host: "i2paddress", scheme: "http", port: 80],
+```
+In addition to that, replace the existing nginx config's contents with the example below.
+
+### Existing Instance (Clearnet Instance)
+
+If not an I2P-only instance, add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`.
+
+And for both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet).
+Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/):
+```
+config :pleroma, :http_security,
+ enabled: false
+```
+
+Use this as the Nginx config:
+```
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off;
+# The above already exists in a clearnet instance's config.
+# If not, add it.
+
+server {
+ listen 127.0.0.1:14447;
+ server_name youri2paddress;
+
+ # Comment to enable logs
+ access_log /dev/null;
+ error_log /dev/null;
+
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_comp_level 6;
+ gzip_buffers 16 8k;
+ gzip_http_version 1.1;
+ gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/activity+json application/atom+xml;
+
+ client_max_body_size 16m;
+
+ location / {
+
+ add_header X-XSS-Protection "1; mode=block";
+ add_header X-Permitted-Cross-Domain-Policies none;
+ add_header X-Frame-Options DENY;
+ add_header X-Content-Type-Options nosniff;
+ add_header Referrer-Policy same-origin;
+ add_header X-Download-Options noopen;
+
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $http_host;
+
+ proxy_pass http://localhost:4000;
+
+ client_max_body_size 16m;
+ }
+
+ location /proxy {
+ proxy_cache pleroma_media_cache;
+ proxy_cache_lock on;
+ proxy_ignore_client_abort on;
+ proxy_pass http://localhost:4000;
+ }
+}
+```
+reload Nginx:
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+You should now be able to both access your instance using I2P and federate with other I2P instances!
+
+[^1]: [I2PD tools](https://github.com/purplei2p/i2pd-tools) to print information about a router info file or an I2P private key, generate an I2P private key, and generate vanity addresses.
+
+### Possible Issues
+
+Will be added when encountered.
diff --git a/docs/configuration/mrf.md b/docs/configuration/mrf.md
new file mode 100644
index 000000000..45be18fc5
--- /dev/null
+++ b/docs/configuration/mrf.md
@@ -0,0 +1,122 @@
+# Message Rewrite Facility
+The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages.
+
+Possible uses include:
+
+* marking incoming messages with media from a given account or instance as sensitive
+* rejecting messages from a specific instance
+* rejecting reports (flags) from a specific instance
+* removing/unlisting messages from the public timelines
+* removing media from messages
+* sending only public messages to a specific instance
+
+The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, which disables the MRF functionality. Pleroma also includes an easy to use policy called `SimplePolicy` which maps messages matching certain pre-defined criterion to actions built into the policy module.
+It is possible to use multiple, active MRF policies at the same time.
+
+## Quarantine Instances
+
+You have the ability to prevent from private / followers-only messages from federating with specific instances. Which means they will only get the public or unlisted messages from your instance.
+
+If, for example, you're using `MIX_ENV=prod` aka using production mode, you would open your configuration file located in `config/prod.secret.exs` and edit or add the option under your `:instance` config object. Then you would specify the instance within quotes.
+```
+config :pleroma, :instance,
+ [...]
+ quarantined_instances: ["instance.example", "other.example"]
+```
+
+## Using `SimplePolicy`
+
+`SimplePolicy` is capable of handling most common admin tasks.
+
+To use `SimplePolicy`, you must enable it. Do so by adding the following to your `:instance` config object, so that it looks like this:
+
+```
+config :pleroma, :instance,
+ [...]
+ rewrite_policy: Pleroma.Web.ActivityPub.MRF.SimplePolicy
+```
+
+Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are:
+
+* `media_removal`: Servers in this group will have media stripped from incoming messages.
+* `media_nsfw`: Servers in this group will have the #nsfw tag and sensitive setting injected into incoming messages which contain media.
+* `reject`: Servers in this group will have their messages rejected.
+* `federated_timeline_removal`: Servers in this group will have their messages unlisted from the public timelines by flipping the `to` and `cc` fields.
+* `report_removal`: Servers in this group will have their reports (flags) rejected.
+
+Servers should be configured as lists.
+
+### Example
+
+This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`:
+
+```
+config :pleroma, :instance,
+ rewrite_policy: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
+
+config :pleroma, :mrf_simple,
+ media_removal: ["illegalporn.biz"],
+ media_nsfw: ["porn.biz", "porn.business"],
+ reject: ["spam.com"],
+ federated_timeline_removal: ["spam.university"],
+ report_removal: ["whiny.whiner"]
+
+```
+
+### Use with Care
+
+The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance.
+
+## Writing your own MRF Policy
+
+As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `rewrite_policy` config setting.
+
+For example, here is a sample policy module which rewrites all messages to "new message content":
+
+```elixir
+# This is a sample MRF policy which rewrites all Notes to have "new message
+# content."
+defmodule Site.RewritePolicy do
+ @behavior Pleroma.Web.ActivityPub.MRF
+
+ # Catch messages which contain Note objects with actual data to filter.
+ # Capture the object as `object`, the message content as `content` and the
+ # message itself as `message`.
+ @impl true
+ def filter(%{"type" => Create", "object" => {"type" => "Note", "content" => content} = object} = message)
+ when is_binary(content) do
+ # Subject / CW is stored as summary instead of `name` like other AS2 objects
+ # because of Mastodon doing it that way.
+ summary = object["summary"]
+
+ # Message edits go here.
+ content = "new message content"
+
+ # Assemble the mutated object.
+ object =
+ object
+ |> Map.put("content", content)
+ |> Map.put("summary", summary)
+
+ # Assemble the mutated message.
+ message = Map.put(message, "object", object)
+ {:ok, message}
+ end
+
+ # Let all other messages through without modifying them.
+ @impl true
+ def filter(message), do: {:ok, message}
+end
+```
+
+If you save this file as `lib/site/mrf/rewrite_policy.ex`, it will be included when you next rebuild Pleroma. You can enable it in the configuration like so:
+
+```
+config :pleroma, :instance,
+ rewrite_policy: [
+ Pleroma.Web.ActivityPub.MRF.SimplePolicy,
+ Site.RewritePolicy
+ ]
+```
+
+Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request.
diff --git a/docs/configuration/onion_federation.md b/docs/configuration/onion_federation.md
new file mode 100644
index 000000000..99f104995
--- /dev/null
+++ b/docs/configuration/onion_federation.md
@@ -0,0 +1,159 @@
+# Easy Onion Federation (Tor)
+Tor can free people from the necessity of a domain, in addition to helping protect their privacy. As Pleroma's goal is to empower the people and let as many as possible host an instance with as little resources as possible, the ability to host an instance with a small, cheap computer like a RaspberryPi along with Tor, would be a great way to achieve that.
+In addition, federating with such instances will also help furthering that goal.
+
+This is a guide to show you how it can be easily done.
+
+This guide assumes you already got Pleroma working, and that it's running on the default port 4000.
+Currently only has an Nginx example.
+
+To install Tor on Debian / Ubuntu:
+```
+apt -yq install tor
+```
+If using an old server version (older than Debian Stretch or Ubuntu 18.04), install from backports or PPA.
+I recommend using a newer server version instead.
+
+To have the newest, V3 onion addresses (which I recommend) in Debian, install Tor from backports.
+If you do not have backports, uncomment the stretch-backports links at the end of `/etc/apt/sources.list`.
+Then install:
+```
+apt update
+apt -t stretch-backports -yq install tor
+```
+**WARNING:** Onion instances not using a Tor version supporting V3 addresses will not be able to federate with you.
+
+Create the hidden service for your Pleroma instance in `/etc/tor/torrc`:
+```
+HiddenServiceDir /var/lib/tor/pleroma_hidden_service/
+HiddenServicePort 80 127.0.0.1:8099
+HiddenServiceVersion 3 # Remove if Tor version is below 0.3 ( tor --version )
+```
+Restart Tor to generate an adress:
+```
+systemctl restart tor@default.service
+```
+Get the address:
+```
+cat /var/lib/tor/pleroma_hidden_service/hostname
+```
+
+# Federation
+
+Next, edit your Pleroma config.
+If running in prod, cd to your Pleroma directory, edit `config/prod.secret.exs`
+and append this line:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050}
+```
+In your Pleroma directory, assuming you're running prod,
+run the following:
+```
+su pleroma
+MIX_ENV=prod mix deps.get
+MIX_ENV=prod mix ecto.migrate
+exit
+```
+restart Pleroma (if using systemd):
+```
+systemctl restart pleroma
+```
+
+# Tor Instance Access
+
+Make your instance accessible using Tor.
+
+## Tor-only Instance
+If creating a Tor-only instance, open `config/prod.secret.exs` and under "config :pleroma, Pleroma.Web.Endpoint," edit "https" and "port: 443" to the following:
+```
+ url: [host: "onionaddress", scheme: "http", port: 80],
+```
+In addition to that, replace the existing nginx config's contents with the example below.
+
+## Existing Instance (Clearnet Instance)
+If not a Tor-only instance,
+add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`.
+
+---
+For both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet).
+Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/):
+```
+config :pleroma, :http_security,
+ enabled: false
+```
+
+Use this as the Nginx config:
+```
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off;
+# The above already exists in a clearnet instance's config.
+# If not, add it.
+
+server {
+ listen 127.0.0.1:8099;
+ server_name youronionaddress;
+
+ # Comment to enable logs
+ access_log /dev/null;
+ error_log /dev/null;
+
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_comp_level 6;
+ gzip_buffers 16 8k;
+ gzip_http_version 1.1;
+ gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/activity+json application/atom+xml;
+
+ client_max_body_size 16m;
+
+ location / {
+
+ add_header X-XSS-Protection "1; mode=block";
+ add_header X-Permitted-Cross-Domain-Policies none;
+ add_header X-Frame-Options DENY;
+ add_header X-Content-Type-Options nosniff;
+ add_header Referrer-Policy same-origin;
+ add_header X-Download-Options noopen;
+
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $http_host;
+
+ proxy_pass http://localhost:4000;
+
+ client_max_body_size 16m;
+ }
+
+ location /proxy {
+ proxy_cache pleroma_media_cache;
+ proxy_cache_lock on;
+ proxy_ignore_client_abort on;
+ proxy_pass http://localhost:4000;
+ }
+}
+```
+reload Nginx:
+```
+systemctl reload nginx
+```
+
+You should now be able to both access your instance using Tor and federate with other Tor instances!
+
+---
+
+### Possible Issues
+
+* In Debian, make sure your hidden service folder `/var/lib/tor/pleroma_hidden_service/` and its contents, has debian-tor as both owner and group by using
+```
+ls -la /var/lib/tor/
+```
+If it's not, run:
+```
+chown -R debian-tor:debian-tor /var/lib/tor/pleroma_hidden_service/
+```
+* Make sure *only* the owner has *only* read and write permissions.
+If not, run:
+```
+chmod -R 600 /var/lib/tor/pleroma_hidden_service/
+```
+* If you have trouble logging in to the Mastodon Frontend when using Tor, use the Tor Browser Bundle.
diff --git a/docs/configuration/small_customizations.md b/docs/configuration/small_customizations.md
new file mode 100644
index 000000000..f91657a4c
--- /dev/null
+++ b/docs/configuration/small_customizations.md
@@ -0,0 +1,12 @@
+# Small customizations
+
+See also static_dir.md for visual settings.
+
+## Theme
+
+All users of your instance will be able to change the theme they use by going to the settings (the cog in the top-right hand corner). However, if you wish to change the default theme, you can do so by editing `theme` in `config/dev.secret.exs` accordingly.
+
+## Message Visibility
+
+To enable message visibility options when posting like in the Mastodon frontend, set
+`scope_options_enabled` to `true` in `config/dev.secret.exs`.
diff --git a/docs/configuration/static_dir.md b/docs/configuration/static_dir.md
new file mode 100644
index 000000000..5fb38c3de
--- /dev/null
+++ b/docs/configuration/static_dir.md
@@ -0,0 +1,69 @@
+# Static Directory
+
+Static frontend files are shipped in `priv/static/` and tracked by version control in this repository. If you want to overwrite or update these without the possibility of merge conflicts, you can write your custom versions to `instance/static/`.
+
+```
+config :pleroma, :instance,
+ static_dir: "instance/static/",
+```
+
+For example, edit `instance/static/instance/panel.html` .
+
+Alternatively, you can overwrite this value in your configuration to use a different static instance directory.
+
+This document is written assuming `instance/static/`.
+
+Or, if you want to manage your custom file in git repository, basically remove the `instance/` entry from `.gitignore`.
+
+## robots.txt
+
+By default, the `robots.txt` that ships in `priv/static/` is permissive. It allows well-behaved search engines to index all of your instance's URIs.
+
+If you want to generate a restrictive `robots.txt`, you can run the following mix task. The generated `robots.txt` will be written in your instance static directory.
+
+```
+mix pleroma.robots_txt disallow_all
+```
+
+## Thumbnail
+
+Put on `instance/static/instance/thumbnail.jpeg` with your selfie or other neat picture. It will appear in [Pleroma Instances](http://distsn.org/pleroma-instances.html).
+
+## Instance-specific panel
+
+![instance-specific panel demo](/uploads/296b19ec806b130e0b49b16bfe29ce8a/image.png)
+
+Create and Edit your file on `instance/static/instance/panel.html`.
+
+## Background
+
+You can change the background of your Pleroma instance by uploading it to `instance/static/`, and then changing `background` in `config/prod.secret.exs` accordingly.
+
+If you put `instance/static/images/background.jpg`
+
+```
+config :pleroma, :frontend_configurations,
+ pleroma_fe: %{
+ background: "/images/background.jpg"
+ }
+```
+
+## Logo
+
+![logo modification demo](/uploads/c70b14de60fa74245e7f0dcfa695ebff/image.png)
+
+If you want to give a brand to your instance, You can change the logo of your instance by uploading it to `instance/static/`.
+
+Alternatively, you can specify the path with config.
+If you put `instance/static/static/mylogo-file.png`
+
+```
+config :pleroma, :frontend_configurations,
+ pleroma_fe: %{
+ logo: "/static/mylogo-file.png"
+ }
+```
+
+## Terms of Service
+
+Terms of Service will be shown to all users on the registration page. It's the best place where to write down the rules for your instance. You can modify the rules by changing `instance/static/static/terms-of-service.html`.