Docker Installation
Docker installation is currently not advised for production use. Try the Bare Metal installation instead.
System Requirements
-
Docker Engine
-
Docker Compose V2
If you are using Compose V1, replace
docker compose
withdocker-compose
in those commands below.
Docker Install
The most convenient way to install docker is using an official convenience script provided at get.docker.com:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Alternatively, you can follow the official Docker install documentation for your platform.
Once Docker is installed on your system, it is recommended to create a docker
group and add it to your user:
sudo groupadd docker
sudo usermod -aG docker $USER
Mbin Installation
Preparation
Clone git repository:
git clone https://github.com/MbinOrg/mbin.git
cd mbin
Docker image preparation
If you're using a version of Docker Engine earlier than 23.0, run export DOCKER_BUILDKIT=1
, prior to building the image. This does not apply to users running Docker Desktop. More info can be found here
- First go to the docker directory:
cd docker
- Use the existing Docker image OR build the docker image. Select one of the two options.
Build our own Docker image
If you want to build our own image, run (no need to update the compose.yml
file):
docker build --no-cache -t mbin -f Dockerfile ..
Use Mbin pre-build image
OR use our pre-build images from ghcr.io. In this case you need to update the compose.yml
file:
nano compose.yml
Find and replace or comment-out the following 4 lines:
build:
context: ../
dockerfile: docker/Dockerfile
image: mbin
And instead use the following line on all places (www
, php
, and messenger
services):
image: "ghcr.io/mbinorg/mbin:latest"
Important: Do NOT forget to change ALL LINES in that matches image: mbin
to: image: "ghcr.io/mbinorg/mbin:latest"
in the compose.yml
file (should be 4 matches in total).
- Create config files and storage directories:
cp ../.env.example_docker .env
cp compose.prod.yml compose.override.yml
mkdir -p storage/media storage/caddy_config storage/caddy_data storage/logs
sudo chown $USER:$USER storage/media storage/caddy_config storage/caddy_data storage/logs
Configure .env
and compose.override.yml
- Choose your Redis password, PostgreSQL password, RabbitMQ password, and Mercure password.
- Place the passwords in the corresponding variables in both
.env
andcompose.override.yml
. - Update the
SERVER_NAME
,KBIN_DOMAIN
andKBIN_STORAGE_URL
in.env
. - Update
APP_SECRET
in.env
, generate a new one via:node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"
- Optionally: Use a newer PostgreSQL version (current fallback is v13). Update/set the
POSTGRES_VERSION
variable in your.env
andcompose.override.yml
underdb
.
Ensure the HTTPS
environmental variable is set to TRUE
in compose.override.yml
for the php
, messenger
, and messenger_ap
containers if your environment is using a valid certificate behind a reverse proxy. This is likely true for most production environments and is required for proper federation, that is, this will ensure the webfinger responses include https:
in the URLs generated.
Configure OAuth2 keys
- Create an RSA key pair using OpenSSL:
# Replace <mbin_dir> with Mbin's root directory
mkdir <mbin_dir>/config/oauth2/
# If you protect the key with a passphrase, make sure to remember it!
# You will need it later
openssl genrsa -des3 -out ./config/oauth2/private.pem 4096
openssl rsa -in ./config/oauth2/private.pem --outform PEM -pubout -out ./config/oauth2/public.pem
- Generate a random hex string for the OAuth2 encryption key:
openssl rand -hex 16
- Add the public and private key paths to
.env
:
OAUTH_PRIVATE_KEY=%kernel.project_dir%/config/oauth2/private.pem
OAUTH_PUBLIC_KEY=%kernel.project_dir%/config/oauth2/public.pem
OAUTH_PASSPHRASE=<Your (optional) passphrase from above here>
OAUTH_ENCRYPTION_KEY=<Hex string generated in previous step>
Running the containers
By default docker compose
will execute the compose.yml
and compose.override.yml
files.
Run the container in the background (-d
means detach, but this can also be omitted for testing or debugging purposes):
# Go to the docker directory within the git repo
cd docker
# Starts the containers
docker compose up -d
See your running containers via: docker ps
.
Then, you should be able to access the new instance via http://localhost:8008. You can also access RabbitMQ management UI via http://localhost:15672.
Add auxiliary containers to compose.yml
Add any auxiliary container as you want. For example, add a Nginx container as reverse proxy to provide HTTPS encryption.
If you are building the docker images yourself, you might get merge conflicts when changing the compose.yml
Uploaded media files
Uploaded media files (e.g. photos uploaded by users) will be stored on the host directory storage/media
. They will be served by the Caddy web server in the www
container as static files.
Make sure KBIN_STORAGE_URL
in your .env
configuration file is set to be https://yourdomain.tld/media
(assuming you setup Nginx with SSL certificate by now).
You can also serve those media files on another server by mirroring the files at storage/media
and changing KBIN_STORAGE_URL
correspondingly.
Filesystem ACL support
The filesystem ACL is disabled by default, in the mbin
image. You can set the environment variable ENABLE_ACL=1
to enable it. Remember that not all filesystems support ACL. This will cause an error if you enable filesystem ACL for such filesystems.
Run Production
If you created the file compose.override.yml
with your configs (cp compose.prod.yml compose.override.yml
), running production would be the same command:
docker compose up -d
Important: The docker instance is can be reached at http://127.0.0.1:8008, we strongly advise you to put a reverse proxy (like Nginx) in front of the docker instance. Nginx can could listen on ports 80 and 443 and Nginx should handle SSL/TLS offloading. See also Nginx example below.
If you want to deploy your app on a cluster of machines, you can use Docker Swarm, which is compatible with the provided Compose files.
Mbin NGINX Server Block
NGINX reverse proxy example for the Mbin Docker instance:
upstream backend {
server 127.0.0.1:8008;
keepalive 12;
}
# Map between POST requests on inbox vs the rest
map $request $inboxRequest {
~^POST\ \/f\/inbox 1;
~^POST\ \/i\/inbox 1;
~^POST\ \/m\/.+\/inbox 1;
~^POST\ \/u\/.+\/inbox 1;
default 0;
}
map $inboxRequest $regularRequest {
1 0;
default 1;
}
# Redirect HTTP to HTTPS
server {
server_name domain.tld;
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name domain.tld;
charset utf-8;
# TLS
ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
# Don't leak powered-by
fastcgi_hide_header X-Powered-By;
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "same-origin" always;
add_header X-Download-Options "noopen" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
client_max_body_size 20M; # Max size of a file that a user can upload
# Logs
error_log /var/log/nginx/mbin_error.log;
access_log /var/log/nginx/mbin_access.log if=$regularRequest;
access_log /var/log/nginx/mbin_inbox.log if=$inboxRequest buffer=32k flush=5m;
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
location / {
proxy_http_version 1.1;
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Host $host;
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 $scheme;
proxy_set_header Connection "";
proxy_pass http://backend;
}
location /.well-known/mercure {
proxy_pass http://backend$request_uri;
proxy_read_timeout 24h;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}