お一人様misskeyサーバを立てた個人的記録

2024年2月20日追記
情報が頻繁に変わって更新が追いつかず、本記事の方法でつまづく場合があります。そういう時は、まず公式サイトの最新ドキュメントを読んでください。

https://misskey-hub.net/ja/docs/for-admin/install/guides/

2023年4月21日
あくまで「個人的にこうしたら成功した」という記録です。質問されてもお答えできませんので悪しからず。

クローズドmisskeyサーバ「こづか山荘」の管理人、小束弓月と申します。
初めてmisskeyサーバを立てた時の記録を記事に仕立てました。

目標

misskeyをUbuntuサーバにインストールしWeb公開する

現環境

  1. 静的コンテンツをキャッシュさせてサーバーの負荷を低減させる

  2. DNSプロキシを使うと、公開されるIPアドレスがCloudflareのv4・v6アドレスになる

    • サーバの真のIPアドレスが露出しにくくなりDoS攻撃などを緩和できる

    • 80/443番ポートを開放できるのがIPv6のみの環境(IPoE IPv6光回線など)でも、IPv4からアクセス可能になる(自宅v6アドレス宛てに変換してくれる)

参考:

はじめの作業

ファイアウォール/ufw設定

IPv6も利用する設定。
Conohaの場合、VPSネットワーク設定でWebポートを開けると80・443の他に20・21も開くので、意図的に閉める
セキュリティグループ機能で通信ポートを細かく制御できるようになりました。
https://www.conoha.jp/vps/function/port/

$ sudo ufw default deny

$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp

$ sudo ufw status
Status: active
To                         Action   From
80/tcp                     ALLOW    Anywhere
443/tcp                    ALLOW    Anywhere
80/tcp (v6)                ALLOW    Anywhere (v6)
443/tcp (v6)               ALLOW    Anywhere (v6)

$ sudo systemctl enable ufw
$ sudo ufw reload

パッケージのインストール

メモリアロケータ「jemalloc2」含む

$ sudo apt install build-essential curl ffmpeg lsb_release gnupg2 ca-certificates ubuntu-keyring libjemalloc2

PostgreSQLインストール

PostgreSQL 15.x以上

$ wget https://salsa.debian.org/postgresql/postgresql-common/raw/master/pgdg/apt.postgresql.org.sh
$ chmod 764 ./apt.postgresql.org.sh
$ sudo sh apt.postgresql.org.sh -i -v 15
$ psql --version
psql (PostgreSQL) 15.2 (Ubuntu 15.2-1.pgdg22.04+1)

PostgreSQL のデータベースとユーザを作成する

$ sudo -u postgres psql
postgres=# CREATE ROLE misskey LOGIN CREATEDB PASSWORD '<yourpassword>';
postgres=# CREATE DATABASE mk1 OWNER misskey;

postgres=# exit

Node.jsインストール

Node.js 20.10.x以上(misskey 2023.12.0以降) Node.js 20.x以上

$ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/nodesource.gpg
$ NODE_MAJOR=20; echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
$ sudo apt update
$ sudo apt install nodejs

$ node -v
v20.10.0

$ sudo corepack enable

Redisインストール

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy
$ curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
$ echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb jammy main
$ sudo apt update
$ sudo apt install redis

$ redis-server -v
Redis server v=7.2.4 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=xxxxxxxxxxxxxxxx
$ sudo systemctl enable redis-server
$ sudo systemctl start redis-server

nginxインストール

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
>     | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
$ gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
 pub   rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
       573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
 uid                      nginx signing key <signing-key@nginx.com>
$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
> http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
>     | sudo tee /etc/apt/sources.list.d/nginx.list
 deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu jammy nginx
$ echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
>     | sudo tee /etc/apt/preferences.d/99nginx
 Package: *
 Pin: origin nginx.org
 Pin: release o=nginx
 Pin-Priority: 900
$ sudo apt update
$ sudo apt install nginx

systemctlで状態を確認

$ sudo systemctl status nginx

もしactiveでなければ起動+自動起動を有効化。

$ sudo systemctl start nginx
$ sudo systemctl enable nginx

動作を確認

$ curl http://localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

・・・・・

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Let's Encrypt SSL証明書

<<~>>内にCloudflareに登録したメールアドレスとAPI Keyを書く。

$ sudo apt install certbot python3-certbot-dns-cloudflare
$ sudo mkdir /etc/cloudflare
$ sudo vi /etc/cloudflare/cloudflare.ini
dns_cloudflare_email = <<yourmail@example.tld>>
dns_cloudflare_api_key = <<your key>>
$ sudo chmod 600 /etc/cloudflare/cloudflare.ini
$ sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/cloudflare/cloudflare.ini --dns-cloudflare-propagation-seconds 60 --server https://acme-v02.api.letsencrypt.org/directory -d <<yourdomain.tld>> -d <<*.yourdomain.tld>>

misskeyのインストール

misskey専用ユーザ作成

$ sudo adduser --disabled-password --disabled-login misskey
$ sudo su - misskey

Misskeyのインストール

$ git clone -b master https://github.com/misskey-dev/misskey.git --recurse-submodules
$ cd misskey
$ git checkout master

pnpmで必要なnpmパッケージをインストール。

$ NODE_ENV=production pnpm install --frozen-lockfile

設定ファイルの作成をする。example.ymlをコピーして作成して編集。

$ cp .config/example.yml .config/default.yml
$ vi .config/default.yml

【default.yml】<<~>>内が変更点

# Misskey configuration
# https://github.com/misskey-dev/misskey/blob/develop/.config/example.yml

url: <<https://yourdomain.example.tld/>>

port: 3000

db:
host: localhost
port: 5432
db: <<mk1>>
user: <<misskey>>
pass: <<yourdbpassword>>

dbReplications: false

redis:
host: localhost
port: 6379

id: 'aid'

proxyBypassHosts:
  - api.deepl.com
  - api-free.deepl.com
  - www.recaptcha.net
  - hcaptcha.com
  - challenges.cloudflare.com

proxyRemoteFiles: true
signToActivityPubGet: true

そしてビルド。成功したらユーザ「misskey」からログアウト。

$ NODE_ENV=production pnpm run build
$ pnpm run init
$ exit

nginxの設定

$ sudo vi /etc/nginx/conf.d/misskey.conf

【misskey.conf】<<~>>内が変更点

# For WebSocket
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;

server {
    listen 80;
    listen [::]:80;
    server_name <<yourdomain.example.tld>>;

    # For SSL domain validation
    root /var/www/html;
    location /.well-known/acme-challenge/ { allow all; }
    location /.well-known/pki-validation/ { allow all; }
    location / { return 301 https://$server_name$request_uri; }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name <<yourdomain.example.tld>>;
    ssl_session_timeout 1d;
    ssl_session_cache shared:ssl_session_cache:10m;
    ssl_session_tickets off;

    # To use Let's Encrypt certificate
    ssl_certificate     /etc/letsencrypt/live/<<example.tld>>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<<example.tld>>/privkey.pem;

    # To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate)
    #ssl_certificate      /etc/ssl/certs/ssl-cert-snakeoil.pem;
    #ssl_certificate_key  /etc/ssl/private/ssl-cert-snakeoil.key;

    # SSL protocol settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_stapling on;
    ssl_stapling_verify on;

    # Change to your upload limit
    client_max_body_size 80m;

# Proxy to Node
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_redirect off;

        # If it's behind another reverse proxy or CDN, remove the following.
        # proxy_set_header X-Real-IP $remote_addr;
        # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # proxy_set_header X-Forwarded-Proto https;

        # For WebSocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # Cache settings
        proxy_cache cache1;
        proxy_cache_lock on;
        proxy_cache_use_stale updating;
        proxy_force_ranges on;
        add_header X-Cache $upstream_cache_status;
    }
}

設定をテストして再起動

sudo nginx -t
$ sudo systemctl restart nginx

misskeyを起動

$ sudo su - misskey
$ cd misskey
$ NODE_ENV=production pnpm run start

Now listening on port 3000 on http://<your url>
と表示されたらブラウザからURLにアクセスする。Misskeyのウェルカムページが表示される。

Misskeyのデーモンを作成(自動起動)

いったんCtrl+Cでプロセスをキルし、ユーザ「misskey」から退出。

$ exit

「/etc/systemd/system/misskey.service」を作成する。

$ sudo vi /etc/systemd/system/misskey.service

次の内容を貼り付け、保存する。
うまくいかない場合は、npmの絶対パスをwhichコマンドなどで調べる(/usr/local/bin/npmなど)。

[Unit]
Description=Misskey daemon

[Service]
Type=simple
User=misskey
ExecStart=/usr/bin/npm start
WorkingDirectory=/home/misskey/misskey
Environment="NODE_ENV=production"
Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
TimeoutSec=60
StandardOutput=journal
StandardError=journal
SyslogIdentifier=misskey
Restart=always

[Install]
WantedBy=multi-user.target

systemdを設定し、misskeyデーモンを開始。

$ sudo systemctl daemon-reload
$ sudo systemctl enable misskey
$ sudo systemctl start misskey

systemctlでデーモンの状態を確認。起動に少し時間がかかる場合も。

$ systemctl status misskey

activeならOK。

追加の設定

プッシュ通知の設定

npx web-push generate-vapid-keys

Summaly Proxyについて

2024.2.22
Summalyとはmisskeyサーバの機能の一つで、URLのプレビューに必要な情報(サムネ画像など)を取得してクライアントに渡す。
ただし、この時サーバの本当のIPアドレスが通信相手のログに残ってしまう。悪意のある相手にIPアドレスが知れた場合、DDoS攻撃などの標的になる可能性がある。
それを防ぐため、自ネットワーク外にあるサーバにSummalyを代行させて矢面に立ってもらいましょう、というのがSummaly Proxy。
(大手サーバなら負荷分散の意味もあるかも)

Summaly Proxyならmisskey.io提供の「summaly.arkjp.net」があるよという記述も多いが、こちら現在運用されていないとのこと。
https://github.com/misskey-dev/misskey/issues/12035

有志の方が公開しているSummaly proxyサーバを使わせて頂くか、自力でSummaly Proxyサーバを立てる。

https://mi.okin-jp.net/@okin_p/pages/1702658320173

Proxyサーバ

外からの防御壁という意味では、汎用のproxyサーバを自前で立てて認証やファイアウォールなどで自分専用に設定してしまうという手段もある。squidならネットにドキュメントや事例紹介も豊富。
default.ymlの「Other Configration」以下にproxyサーバの設定がある。

Proxy for HTTP/HTTPS
# proxy: http://127.0.0.1:3128

コメントアウトしてプロキシサーバのアドレス・ポートを指定すると、misskeyサーバから外部への通信がプロキシサーバを経由するようになる。

Cloudflare turnstile

BOTアクセスを防ぐCAPTCHA認証ツール。簡単に設定できて無料。

PostgreSQL

デフォルトのままではメモリ使用量が少なくパフォーマンスが低いので、サーバのメモリ搭載量に応じた設定にするとより快適になる。
ただし設定値を誤ると逆効果なので、よく調べて調整する。

misskeyのアップデート

サービスを停止しておく(作業中はmisskeyは利用できない)。

sudo systemctl stop misskey

sudo su - misskey
cd misskey

git checkout master
git pull
NODE_ENV=production pnpm install --frozen-lockfile
pnpm run clean
NODE_ENV=production pnpm run build
pnpm run migrate

exit

アップデートが終わり次第、Misskeyプロセスを再起動

sudo systemctl start misskey


この記事が気に入ったらサポートをしてみませんか?