앞선 글의 댓글에서 많은 분들이 Nginx에서 Flarum을 사용할 때 404 등의 문제가 발생한다고 남겨 주셨는데, 이는 퍼머링크 규칙이 제대로 설정되지 않았기 때문인 것으로 보입니다. 공식 문서에서는 다양한 환경에서 Flarum의 퍼머링크를 설정하는 방법을 자세히 설명하고 있으며, Nginx의 규칙은 다음과 같습니다.

include /path/to/flarum/.nginx.conf;

이는 Flarum 루트 디렉터리 아래의 .nginx.conf 파일을 가리킨다는 의미입니다. 이렇게 하면 Flarum을 업데이트할 때마다 퍼머링크 규칙을 업데이트해야 하는지 신경 쓰지 않아도 된다는 장점이 있습니다. 물론 Baota의 퍼머링크 설정에 .nginx.conf 파일의 내용을 직접 입력할 수도 있습니다.

다음은 세 가지 일반적인 환경에서 사용하는 Flarum 퍼머링크 규칙입니다.

Apache

<IfModule mod_rewrite.c>
  RewriteEngine on

  # Ensure the Authorization HTTP header is available to PHP
  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

  # Uncomment the following lines if you are not using a `public` directory
  # to prevent sensitive resources from being exposed.
  # RewriteRule /\.git / [F,L]
  # RewriteRule ^composer\.(lock|json)$ / [F,L]
  # RewriteRule ^config.php$ / [F,L]
  # RewriteRule ^flarum$ / [F,L]
  # RewriteRule ^storage/(.*)?$ / [F,L]
  # RewriteRule ^vendor/(.*)?$ / [F,L]

  # Pass requests that don't refer directly to files in the filesystem to index.php
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^ index.php [QSA,L]
</IfModule>

# Disable directory listings
Options -Indexes

# MultiViews can mess up our rewriting scheme
Options -MultiViews

# The following directives are based on best practices from H5BP Apache Server Configs
# https://github.com/h5bp/server-configs-apache

# Expire rules for static content
<IfModule mod_expires.c>
  ExpiresActive on
  ExpiresDefault                                      "access plus 1 month"
  ExpiresByType text/css                              "access plus 1 year"
  ExpiresByType application/atom+xml                  "access plus 1 hour"
  ExpiresByType application/rdf+xml                   "access plus 1 hour"
  ExpiresByType application/rss+xml                   "access plus 1 hour"
  ExpiresByType application/json                      "access plus 0 seconds"
  ExpiresByType application/ld+json                   "access plus 0 seconds"
  ExpiresByType application/schema+json               "access plus 0 seconds"
  ExpiresByType application/vnd.geo+json              "access plus 0 seconds"
  ExpiresByType application/vnd.api+json              "access plus 0 seconds"
  ExpiresByType application/xml                       "access plus 0 seconds"
  ExpiresByType text/calendar                         "access plus 0 seconds"
  ExpiresByType text/xml                              "access plus 0 seconds"
  ExpiresByType image/vnd.microsoft.icon              "access plus 1 week"
  ExpiresByType image/x-icon                          "access plus 1 week"
  ExpiresByType text/html                             "access plus 0 seconds"
  ExpiresByType application/javascript                "access plus 1 year"
  ExpiresByType application/x-javascript              "access plus 1 year"
  ExpiresByType text/javascript                       "access plus 1 year"
  ExpiresByType application/manifest+json             "access plus 1 week"
  ExpiresByType application/x-web-app-manifest+json   "access plus 0 seconds"
  ExpiresByType text/cache-manifest                   "access plus 0 seconds"
  ExpiresByType text/markdown                         "access plus 0 seconds"
  ExpiresByType audio/ogg                             "access plus 1 month"
  ExpiresByType image/bmp                             "access plus 1 month"
  ExpiresByType image/gif                             "access plus 1 month"
  ExpiresByType image/jpeg                            "access plus 1 month"
  ExpiresByType image/png                             "access plus 1 month"
  ExpiresByType image/svg+xml                         "access plus 1 month"
  ExpiresByType image/webp                            "access plus 1 month"
  ExpiresByType video/mp4                             "access plus 1 month"
  ExpiresByType video/ogg                             "access plus 1 month"
  ExpiresByType video/webm                            "access plus 1 month"
  ExpiresByType application/wasm                      "access plus 1 year"
  ExpiresByType font/collection                       "access plus 1 month"
  ExpiresByType application/vnd.ms-fontobject         "access plus 1 month"
  ExpiresByType font/eot                              "access plus 1 month"
  ExpiresByType font/opentype                         "access plus 1 month"
  ExpiresByType font/otf                              "access plus 1 month"
  ExpiresByType application/x-font-ttf                "access plus 1 month"
  ExpiresByType font/ttf                              "access plus 1 month"
  ExpiresByType application/font-woff                 "access plus 1 month"
  ExpiresByType application/x-font-woff               "access plus 1 month"
  ExpiresByType font/woff                             "access plus 1 month"
  ExpiresByType application/font-woff2                "access plus 1 month"
  ExpiresByType font/woff2                            "access plus 1 month"
  ExpiresByType text/x-cross-domain-policy            "access plus 1 week"
</IfModule>

# Gzip compression
<IfModule mod_deflate.c>
  <IfModule mod_filter.c>
    AddOutputFilterByType DEFLATE "application/atom+xml" \
                                  "application/javascript" \
                                  "application/json" \
                                  "application/ld+json" \
                                  "application/manifest+json" \
                                  "application/rdf+xml" \
                                  "application/rss+xml" \
                                  "application/schema+json" \
                                  "application/vnd.geo+json" \
                                  "application/vnd.ms-fontobject" \
                                  "application/wasm" \
                                  "application/x-font-ttf" \
                                  "application/x-javascript" \
                                  "application/x-web-app-manifest+json" \
                                  "application/xhtml+xml" \
                                  "application/xml" \
                                  "font/collection" \
                                  "font/eot" \
                                  "font/opentype" \
                                  "font/otf" \
                                  "font/ttf" \
                                  "image/bmp" \
                                  "image/svg+xml" \
                                  "image/vnd.microsoft.icon" \
                                  "image/x-icon" \
                                  "text/cache-manifest" \
                                  "text/calendar" \
                                  "text/css" \
                                  "text/html" \
                                  "text/javascript" \
                                  "text/plain" \
                                  "text/markdown" \
                                  "text/vcard" \
                                  "text/vnd.rim.location.xloc" \
                                  "text/vtt" \
                                  "text/x-component" \
                                  "text/x-cross-domain-policy" \
                                  "text/xml"
    </IfModule>
</IfModule>

# Fix for https://httpoxy.org vulnerability
<IfModule mod_headers.c>
  RequestHeader unset Proxy
</IfModule>

Nginx

# Pass requests that don't refer directly to files in the filesystem to index.php
location / {
  try_files $uri $uri/ /index.php?$query_string;
}

# The following directives are based on best practices from H5BP Nginx Server Configs
# https://github.com/h5bp/server-configs-nginx

# Expire rules for static content
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
  add_header Cache-Control "max-age=0";
}

location ~* \.(?:rss|atom)$ {
  add_header Cache-Control "max-age=3600";
}

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
  add_header Cache-Control "max-age=2592000";
  access_log off;
}

location ~* \.(?:css|js)$ {
  add_header Cache-Control "max-age=31536000";
  access_log off;
}

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
  add_header Cache-Control "max-age=2592000";
  access_log off;
}

# Gzip compression
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

Caddy

www.example.com {
    root /var/www/flarum/public
    rewrite {
        to {path} {path}/ /index.php
    }
    fastcgi / /var/run/php/php7.2-fpm.sock php
    header /assets {
        +Cache-Control "public, must-revalidate, proxy-revalidate"
        +Cache-Control "max-age=25000"
        Pragma "public" 
    }
    gzip
}