Introduction
Misskey uses ActivityPub protocal, which is also the protocal for Mastodon. But Bluesky does use a newer protocal, so you won't be able to reach Bluesky unless you use Bridgy Fed. Offcial documents from Misskey doesn't mention about how to use Meilisearch.
Start the installation
mkdir /opt/misskey
cd /opt/misskey
git clone -b master https://github.com/misskey-dev/misskey.git
cd misskey
git checkout master
cp .config/docker_example.yml .config/default.yml
cp .config/docker_example.env .config/docker.env
cp ./compose_example.yml ./compose.yml
Assuming docker is installed on the host and docker compose is also installed. If not, for Fedora, it's this.
Since we are using Meilisearch in this case we will also need .config/meilisearch.env , so we will modify 4 files in total.
For .config/meilisearch.env we just need to set a key with 16 characters or more.
MEILI_MASTER_KEY='YOUR-KEY-HERE'
For .config/default.yml I think everything is pretty straight forward, just set Postgres, Redis and Meilisearch. Do notice I set the ssl to false, because I think there are some bugs with it right now, it will have stream error if you enable it(might be my problem tho).
And for .config/docker.env just use what you have set in the .config/default.yml for the db
compose.yml
Things should be pretty easy so far. But for a new comer to Fedora, compose.yml made me crazy because of SELinux.(I will not tell you I just set it to permissive mode at the end lol)
Here is my configuration, tailored to Fedora, remember to uncomment meilisearch under web.
services:
web:
user: "1001:1001"
build: .
restart: always
links:
- db
- redis
# - mcaptcha
- meilisearch
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "127.0.0.1:3000:3000"
networks:
- internal_network
- external_network
env_file:
- .config/docker.env
environment:
- XDG_CACHE_HOME=/tmp/.cache
- COREPACK_HOME=/tmp/corepack
- NPM_CONFIG_CACHE=/tmp/.npm
volumes:
- ./files:/misskey/files:Z
- ./.config:/misskey/.config:Z:ro
- misskey_tmp:/tmp
redis:
user: "1000:1000"
restart: always
image: redis:7-alpine
networks:
- internal_network
volumes:
- ./redis:/data:z
healthcheck:
test: "redis-cli ping"
interval: 5s
timeout: 3s
retries: 20
db:
restart: always
image: postgres:15-alpine
user: "999:999"
networks:
- internal_network
env_file:
- .config/docker.env
volumes:
- ./db:/var/lib/postgresql/data:Z,copy
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s
timeout: 3s
retries: 20
# mcaptcha:
# restart: always
# image: mcaptcha/mcaptcha:latest
# networks:
# internal_network:
# external_network:
# aliases:
# - localhost
# ports:
# - 7493:7493
# env_file:
# - .config/docker.env
# environment:
# PORT: 7493
# MCAPTCHA_redis_URL: "redis://mcaptcha_redis/"
# depends_on:
# db:
# condition: service_healthy
# mcaptcha_redis:
# condition: service_healthy
#
# mcaptcha_redis:
# image: mcaptcha/cache:latest
# networks:
# - internal_network
# healthcheck:
# test: "redis-cli ping"
# interval: 5s
# retries: 20
meilisearch:
restart: always
image: getmeili/meilisearch:v1.3.4
environment:
- MEILI_NO_ANALYTICS=true
- MEILI_ENV=production
env_file:
- .config/meilisearch.env
networks:
- internal_network
volumes:
- ./meili_data:/meili_data
networks:
internal_network:
internal: true
external_network:
volumes:
misskey_tmp:
This is a bit different than the official compose.yml file from the repo, we applied labeling here :Z
for SELinux, used 127.0.0.1
before web's port to not let public network visit our misskey instance without using 443(will set this up later). Added a /tmp directory for cache and corepack. Added users for each service for permission management, no point of using docker if you are using root.
Set correct permissions
You must saw in the compose.yml, I also added user parameters for each service, this is for security control, also if you don't do that I think SELinux will deny access for docker container processes.
Therefore now we will set correct permission for each directory. We will use 700 here, but if that causes problems for you, 750 is also fine.
chown -R 999:999 ./db
chown -R 1000:1000 ./redis
chown -R 1001:1001 ./files
chmod -R 700 ./db
chmod -R 700 ./redis
chmod -R 700 ./files
Build
docker compose build --no-cache #This will take a while
docker compose run --rm web pnpm run init
docker compose up -d
I always build with --no-cache because it's so easy to get things wrong when there are multiple yml and env files.
If something went wrong and you didn't use --no-cache it's better to prune
docker system prune -a
After everything is up, let's double check the web
curl -I http://127.0.0.1:3000 #ofc you should get 200 OK
Set up reverse proxy and SSL
Now we pretty much just need to install nginx and set up ssl.
dnf install nginx
dnf install snapd #I used snap to install certbot
systemctl enable --now snapd.socket
ln -s /var/lib/snapd/snap /snap
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
We will configure reverse proxy now. At /etc/nginx/conf.d we add a config
vim misskey.conf
# My config is as shown below:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name your.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name your.domain.com;
# Security headers
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:; style-src 'self' 'unsafe-inline';";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
client_max_body_size 100m;
# Proxy configuration
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;
}
}
Now we add SSL using certbot, before that use nginx -t
to test your config. I don't think an instruction for certbot is needed, it's a straight forward process and it's self explanatory.
I think that's the end?
During the time I am writing the blog, I realized a labeling (that's used to be) in the compose.yml is not needed and will actually cause SELinux denying access for misskey-db-1
. The parameter is:
security_opt:
- label=type:container_file_t
With this we are forcing the container process run with the file context(container_file_t) instead of process context(container_t) or unconfined context. We already had the :Z labeling so our container process could access the file volume(in container_file_t context). label=type:container_file_t
means that even critical binaries (like bash and its libraries such as libreadline.so.8) are run in a context that isn’t allowed to read them. We can know this by running ps -Z
and we will know now docker assigned unconfined_t
or container_t
context for docker processes.
And yes, I have SELinux enabled at the end.
Comments NOTHING