User:Dart Raiden/Server setup

From Miranda NG
Jump to navigation Jump to search

Export Prosody database from old server

mysqldump --user=prosody --password="p@ssword" --default-character-set=utf8 prosody > prosody.sql

Backup forum, wiki, and website

cd /var/www/forum.miranda-ng.org

sudo ./zipme.sh

cd /var/www/wiki.miranda-ng.org

sudo ./zipme.sh

cd /var/www/miranda-ng.org

sudo ./zipme.sh

UFW

sudo apt install ufw

sudo ufw allow 22/tcp

sudo ufw enable

SSH

sudo nano /etc/ssh/sshd_config.d/deny_password_authentication.conf

PasswordAuthentication no

sudo nano /etc/ssh/sshd_config.d/deny_root_login.conf

PermitRootLogin no

sudo nano /etc/ssh/sshd_config.d/enable_pubkey_authentication.conf

PubkeyAuthentication yes

sudo systemctl restart ssh

MariaDB

sudo apt install mariadb-server

sudo mysql_secure_installation (do not set a root password; enable the other restrictions)

sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf

max_connections         = 1000

sudo mysql -u root

CREATE USER 'forum'@'localhost' IDENTIFIED BY 'p@ssword';
CREATE DATABASE forum_miranda_ng_org;
quit

sudo mysql -u root -f forum_miranda_ng_org < ~/forum_miranda_ng_org.sql

sudo mysql -u root

GRANT ALL ON forum_miranda_ng_org.* to 'forum'@'localhost';
FLUSH PRIVILEGES;
quit

sudo mysql -u root

CREATE USER 'wiki'@'localhost' IDENTIFIED BY 'p@ssword';
CREATE DATABASE wiki_miranda_ng_org;
quit

sudo mysql -u root -f wiki_miranda_ng_org < ~/wiki_miranda_ng_org.sql

sudo mysql -u root

GRANT ALL ON wiki_miranda_ng_org.* to 'wiki'@'localhost';
FLUSH PRIVILEGES;
quit

sudo mysql -u root

CREATE USER 'prosody'@'localhost' IDENTIFIED BY 'p@ssword';
CREATE DATABASE prosody;
quit

sudo mysql -u root -f prosody < ~/prosody.sql

sudo mysql -u root

GRANT ALL ON prosody.* to 'prosody'@'localhost';
FLUSH PRIVILEGES;
quit

PHP

sudo apt install php-fpm php-mysql php-mbstring php-curl php-gd php-xml php-intl memcached

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

listen = /run/php/php-fpm.sock

pm = static

pm.max_children = 200

Nginx

sudo apt install nginx

sudo nano /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

events {
	worker_connections 768;
	# multi_accept on;
}

http {
	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	include logging.params;

	include gzip.params;

	include http.params;

	include ssl.params;

	server_names_hash_bucket_size 48;

        server_tokens off;
	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}

sudo nano /etc/nginx/logging.params

log_format main
    '$remote_addr - $remote_user [$time_local] '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$gzip_ratio"';

sudo nano /etc/nginx/gzip.params

gzip on;
gzip_http_version 1.0;
gzip_comp_level 8;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types
    # text/html is always compressed by HttpGzipModule
    text/css
    text/javascript
    text/xml
    text/plain
    text/x-component
    application/javascript
    application/x-javascript
    application/json
    application/xml
    application/rss+xml
    font/truetype
    font/opentype
    application/vnd.ms-fontobject
    image/svg+xml;
gzip_static on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "msie6";
gzip_vary on;

sudo nano /etc/nginx/http.params

client_max_body_size 20m;
client_header_timeout 1m;
client_body_timeout 1m;
send_timeout 1m;

connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

output_buffers 1 32k;
postpone_output 1460;

keepalive_timeout 75 20;

ignore_invalid_headers on;

sudo nano /etc/nginx/ssl.params

ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

sudo nano /etc/nginx/public.params

allow all;
log_not_found off;
access_log off;

sudo nano /etc/nginx/phpfpm.params

fastcgi_index   index.php;
fastcgi_pass    unix:/run/php/php-fpm.sock;
include         fastcgi.params;
fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param   SCRIPT_NAME $fastcgi_script_name;
fastcgi_hide_header "X-Powered-By";
fastcgi_intercept_errors on;
fastcgi_next_upstream error timeout;
fastcgi_keep_conn on;

sudo nano /etc/nginx/fastcgi.params

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

sudo ufw allow 80/tcp

sudo ufw allow 443/tcp

Restore forum backup

sudo mkdir /var/www/forum.miranda-ng.org

sudo unzip ~/forum.zip -d /var/www/forum.miranda-ng.org

sudo chown -R www-data:www-data /var/www/forum.miranda-ng.org

sudo nano /etc/nginx/sites-available/forum.miranda-ng.org

server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/miranda-ng.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/miranda-ng.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name forum.miranda-ng.org;
    root /var/www/forum.miranda-ng.org/htdocs;
    add_header Strict-Transport-Security "max-age=604800; includeSubDomains" always;

    access_log /var/log/nginx/forum.miranda-ng.org_access.log main;
    error_log /var/log/nginx/forum.miranda-ng.org_error.log info;

    index index.php;

    location = /favicon.ico {
        include public.params;
    }

    location = /robots.txt {
        include public.params;
    }

    location / {
    # actions
    rewrite ^/(activate|admin|announce|ban|boardrecount|buddy|calendar|cleanperms)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(collapse|convertentities|convertutf8|coppa|deletemsg|detailedversion|display|dlattach)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(dumpdb|editpoll|editpoll2|featuresettings|featuresettings2|findmember|help|helpadmin)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(im|jsoption|jsmodify|lock|lockVoting|login|login2|logout)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(maintain|manageattachments|manageboards|managecalendar|managesearch|markasread|membergroups|mergetopics)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(mlist|modifycat|modifykarma|modlog|movetopic|movetopic2|news|notify)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(notifyboard|optimizetables|packageget|packages|permissions|pgdownload|pm|post)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(post2|postsettings|printpage|profile|profile2|quotefast|quickmod|quickmod2)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(recent|regcenter|register|register2|reminder|removetopic2|removeoldtopics2|removepoll)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(repairboards|reporttm|reports|requestmembers|search|search2|sendtopic|serversettings)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(serversettings2|smileys|smstats|spellcheck|splittopics|stats|sticky|theme)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(trackip|about:mozilla|about:unknown|unread|unreadreplies|viewErrorLog|viewmembers|viewprofile)/?$ "/index.php?pretty;action=$1" last;
    rewrite ^/(verificationcode|vote|viewquery|who|\.xml)/?$ "/index.php?pretty;action=$1" last;

    # boards + topics
    rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/[0-9]?/?$ /index.php?pretty%3Bboard=$1.0 last;
    rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/([0-9]*)/[0-9]?/?$ /index.php?pretty%3Bboard=$1.$2 last;
    rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/([-_!~*'()$a-zA-Z0-9]+)/[0-9]?/?$ /index.php?pretty%3Bboard=$1%3Btopic=$2.0 last;
    rewrite ^/([-_!~*'()$a-zA-Z0-9]+)/([-_!~*'()$a-zA-Z0-9]+)/([0-9]*|msg[0-9]*|new)/[0-9]?/?$ /index.php?pretty%3Bboard=$1%3Btopic=$2.$3 last;
    }

    location ~* \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(.*)$;
        include phpfpm.params;
    }

    location ~ /Packages {
        allow 127.0.0.1;
        deny all;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }

    location ~ /\.ht {
        deny all;
    }
}

server {
    if ($host = forum.miranda-ng.org) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name forum.miranda-ng.org;
    return 404; # managed by Certbot
}

sudo ln -s /etc/nginx/sites-available/forum.miranda-ng.org /etc/nginx/sites-enabled/

sudo chmod -R 644 /var/www/forum.miranda-ng.org

sudo find /var/www/forum.miranda-ng.org -type d -print0 | sudo xargs -0 chmod 755

sudo chmod +x /var/www/forum.miranda-ng.org/zipme.sh

Use repair_settings.php and status.php from https://github.com/SimpleMachines/tools/

Restore wiki backup

sudo mkdir /var/www/wiki.miranda-ng.org

sudo unzip ~/wiki.zip -d /var/www/wiki.miranda-ng.org

sudo chown -R www-data:www-data /var/www/wiki.miranda-ng.org

sudo nano /etc/nginx/sites-available/wiki.miranda-ng.org

server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/miranda-ng.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/miranda-ng.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name wiki.miranda-ng.org;
    root /var/www/wiki.miranda-ng.org/htdocs;
    add_header Strict-Transport-Security "max-age=604800; includeSubDomains" always;

    access_log /var/log/nginx/wiki.miranda-ng.org_access.log main;
    error_log /var/log/nginx/wiki.miranda-ng.org_error.log info;

    index index.php;

    location ~* ^(.*)(install.php|LocalSettings.php|\.git) { deny all; }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }

    location ~* \.php$ {
        try_files       $uri @404;
        include phpfpm.params;
    }

    location /images/ {
        location ~.*\.(php)?$ {
            deny all;
        }
    }

    location @404 {
        return 404;
        break;
    }

    # https://stackoverflow.com/questions/35446113/using-short-urls-for-mediawiki-with-nginx
    location / {
        try_files $uri $uri/ @mediawiki;
    }

    location @mediawiki {
        rewrite ^/([^?]*)(?:\?(.*))? /index.php?title=$1&$2 last;
    }
}

server {
    if ($host = wiki.miranda-ng.org) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name wiki.miranda-ng.org;
    return 404; # managed by Certbot
}

sudo ln -s /etc/nginx/sites-available/wiki.miranda-ng.org /etc/nginx/sites-enabled/

sudo chmod -R 644 /var/www/wiki.miranda-ng.org

sudo find /var/www/wiki.miranda-ng.org -type d -print0 | sudo xargs -0 chmod 755

sudo chmod +x /var/www/wiki.miranda-ng.org/zipme.sh /var/www/wiki.miranda-ng.org/htdocs/extensions/Scribunto/includes/engines/LuaStandalone/binaries/lua5_1_5_linux_64_generic/lua /var/www/wiki.miranda-ng.org/htdocs/extensions/SyntaxHighlight_GeSHi/pygments/pygmentize

php /var/www/wiki.miranda-ng.org/htdocs/maintenance/update.php

Restore website backup

sudo apt install hugo

sudo mkdir /var/www/miranda-ng.org

sudo unzip ~/mainsite.zip -d /var/www/miranda-ng.org

sudo chown -R www-data:www-data /var/www/miranda-ng.org

sudo nano /etc/nginx/sites-available/oauth.miranda-ng.org

# oauth for CloudFile
server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/miranda-ng.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/miranda-ng.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name oauth.miranda-ng.org;
    add_header Strict-Transport-Security "max-age=604800; includeSubDomains" always;
    # todo: remove this
    # root /var/www/miranda-ng.org/scripts;

    access_log /var/log/nginx/oauth.miranda-ng.org_access.log main;
    error_log /var/log/nginx/oauth.miranda-ng.org_error.log info;

    # todo: deny access to root (or remove root), allow only verification (or redirect whole subdomain to main domain), unify with miranda-ng.org.conf
    location ~* /verification(.*)$ { 
        return 301 https://miranda-ng.org/verification$is_args$args;
    }
}

server {
    if ($host = oauth.miranda-ng.org) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name oauth.miranda-ng.org;
    return 404; # managed by Certbot
}

sudo ln -s /etc/nginx/sites-available/oauth.miranda-ng.org /etc/nginx/sites-enabled/

sudo nano /etc/nginx/sites-available/miranda-ng.org

# get locale
map $http_accept_language $browser_lang {
        default en;
        ~ru ru;
}
map $cookie_lang $lang {
    default $browser_lang;
    ~en en;
    ~ru ru;
}

map $http_user_agent $excluded_ua {
    ~SemrushBot 0;
    ~facebookexternalhit 0;
    default     1;
}

server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/miranda-ng.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/miranda-ng.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name miranda-ng.org;
    root /var/www/miranda-ng.org/htdocs/public;
    add_header Strict-Transport-Security "max-age=604800; includeSubDomains" always;

    include google-analytics;

    access_log /var/log/nginx/miranda-ng.org_access.log main if=$excluded_ua;
    error_log /var/log/nginx/miranda-ng.org_error.log info;

    # case sensitive http user agent blocking
    if ($excluded_ua ~ "0") {
       return 403;
    }

    index index.html;
    autoindex off;

    # CloudFile: verification.php
    location ~* \.php$ {
        try_files $uri =404;
        include phpfpm.params;
    }

    # CloudFile: /verification -> /verification.php
    location ~ /verification {
        rewrite ^/verification(.*)$ /verification.php$1 redirect;
    }

    location ~ /distr {
        root /var/www/miranda-ng.org; # we want to keep distr outside hugo dir so it doesn't get copied on every build
        post_action @GAlog;
        proxy_set_header Cache-Control  private;
        proxy_set_header Content-Disposition "attachment";
        autoindex on;
    }

    location ~ /(x32|x64) {
        root /var/www/miranda-ng.org/distr; # we want to keep distr outside hugo dir so it doesn't get copied on every build
        post_action @GAlog;
        proxy_set_header Cache-Control  private;
        proxy_set_header Content-Disposition "attachment";
        autoindex on;
    }

    # ADDONS -> addons
    location ~ /ADDONS {
        rewrite ^/ADDONS/(.*)$ /addons/$1 redirect;
    }

    location ~ /addons/images {
        root /var/www/miranda-ng.org;
        autoindex on;
    }
    
    location ~ /addons/files {
        root /var/www/miranda-ng.org;
        autoindex on;
    }

    error_page 404 /404.html;

    location = /favicon.ico {
        include public.params;
    }

    location = /robots.txt {
        include public.params;
    }
 
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|pdf)$ {
        expires max;
        log_not_found off;
    }

    location ~ /hotcoffee {
        index index.html;
        add_header Cache-Control no-cache,no-store,must-revalidate;

        set $lang en;
        if ($cookie_LANG = 'ru'){ set $lang ru; }
        if ($http_accept_language ~* '(ru|be|kz|ua)'){ set $lang ru; }
        if ($cookie_LANG = 'en'){ set $lang en; }

        rewrite ^/hotcoffee(/?)$ /hotcoffee/$lang/index.html break;
        rewrite ^/hotcoffee/licenses/([^/]+\.html)(/?)$ /hotcoffee/$lang/licenses/$1 break;
        rewrite ^/hotcoffee/([^/]+)(/?)$ /hotcoffee/$lang/$1.html break;
    }

    # redirect from miranda-ng.org/p/PluginName to wiki.miranda-ng.org/index.php?title=Plugin:PluginName
    location ~ /p/ {
	rewrite ^\/p\/(.*)\/?$ https://wiki.miranda-ng.org/index.php?title=Plugin:$1 redirect;
    }
}

server {
    listen 80;
    server_name miranda-ng.org;

    # IM Updater doesn't support HTTPS, so we force HTTPS only for website
    location / {
        return 301 https://$host$request_uri;
    }

    # IM Updater
    location /distr {
        root /var/www/miranda-ng.org; # we want to keep distr outside hugo dir so it doesn't get copied on every build
        post_action @GAlog;
        proxy_set_header Cache-Control  private;
        proxy_set_header Content-Disposition "attachment";
        autoindex on;
    }
}

sudo ln -s /etc/nginx/sites-available/miranda-ng.org /etc/nginx/sites-enabled/

sudo nano /etc/nginx/sites-available/www.miranda-ng.org

server {
    listen 443;
    ssl_certificate /etc/letsencrypt/live/miranda-ng.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/miranda-ng.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name www.miranda-ng.org;
    add_header Strict-Transport-Security "max-age=604800; includeSubDomains" always;

    access_log off;
    error_log off;

    return 301 $scheme://miranda-ng.org$request_uri;
}

server {
    if ($host = www.miranda-ng.org) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name www.miranda-ng.org;
    return 404; # managed by Certbot
}

sudo ln -s /etc/nginx/sites-available/www.miranda-ng.org /etc/nginx/sites-enabled/

sudo nano /etc/nginx/sites-available/addons.miranda-ng.org

server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/miranda-ng.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/miranda-ng.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    server_name addons.miranda-ng.org;
    add_header Strict-Transport-Security "max-age=604800; includeSubDomains" always;
    return 301 $scheme://miranda-ng.org/addons$request_uri;
}

server {
    if ($host = addons.miranda-ng.org) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name addons.miranda-ng.org;
    return 404; # managed by Certbot
}

sudo ln -s /etc/nginx/sites-available/addons.miranda-ng.org /etc/nginx/sites-enabled/

sudo chmod -R 644 /var/www/miranda-ng.org

sudo find /var/www/miranda-ng.org -type d -print0 | sudo xargs -0 chmod 755

sudo chmod -R 775 /var/www/miranda-ng.org/htdocs/content /var/www/miranda-ng.org/htdocs/static /var/www/miranda-ng.org/distr

sudo chmod +x /var/www/miranda-ng.org/zipme.sh /var/www/miranda-ng.org/scripts/*

Certbot

sudo apt install certbot python3-certbot-nginx

sudo certbot --nginx -d miranda-ng.org -d www.miranda-ng.org -d addons.miranda-ng.org -d forum.miranda-ng.org -d oauth.miranda-ng.org -d wiki.miranda-ng.org

sudo systemctl restart nginx

Postfix

sudo DEBIAN_PRIORITY=low apt install postfix opendkim opendkim-tools

sudo dpkg-reconfigure postfix

Internet Site
miranda-ng.org
empty
default
No
default
0
+
all

sudo nano /etc/postfix/main.cf

myhostname = miranda-ng.org
inet_interfaces = loopback-only

sudo systemctl enable --now opendkim

sudo opendkim-genkey -D /etc/dkimkeys/ --domain miranda-ng.org --selector dkim

sudo nano /etc/opendkim.conf

LogWhy                  yes
UMask                   002
Socket                  local:/var/spool/postfix/run/opendkim/opendkim.sock
InternalHosts           refile:/etc/dkimkeys/TrustedHosts
AutoRestart             yes
AutoRestartRate         10/1h
ExternalIgnoreList      refile:/etc/dkimkeys/TrustedHosts
KeyTable                refile:/etc/dkimkeys/KeyTable
SigningTable            refile:/etc/dkimkeys/SigningTable
SignatureAlgorithm      rsa-sha256

sudo adduser postfix opendkim

sudo mkdir -p /var/spool/postfix/run/opendkim

sudo chown opendkim:opendkim /var/spool/postfix/run/opendkim

sudo nano /etc/dkimkeys/TrustedHosts

127.0.0.1
localhost
*.miranda-ng.org

sudo nano /etc/dkimkeys/KeyTable

dkim._domainkey.miranda-ng.org miranda-ng.org:dkim:/etc/dkimkeys/dkim.private

sudo nano /etc/dkimkeys/SigningTable

*@miranda-ng.org dkim._domainkey.miranda-ng.org

sudo chown -R opendkim:opendkim /etc/dkimkeys

sudo chmod -R 600 /etc/dkimkeys

sudo chmod 700 /etc/dkimkeys

sudo nano /etc/postfix/main.cf

milter_protocol = 2
milter_default_action = accept
smtpd_milters = unix:/run/opendkim/opendkim.sock
non_smtpd_milters = unix:/run/opendkim/opendkim.sock

sudo nano /etc/hosts

139.100.207.143 miranda-ng.org

sudo hostnamectl set-hostname miranda-ng.org

sudo systemctl restart opendkim

sudo systemctl restart postfix

DNS records:

miranda-ng.org MX miranda-ng.org 10
miranda-ng.org TXT v=spf1 +a +mx -all
DKIM._DOMAINKEY.miranda-ng.org TXT dkim_from_/etc/dkimkeys/dkim.txt
_DMARC.miranda-ng.org TXT v=DMARC1; p=none; aspf=r; sp=none

echo "Subject: hello" | sendmail test@example.com

Port 25 may be blocked on cheap VPS; in this case, see the next section about SMTP relay.

SMTP relay

Remove all MX, SPF and DKIM records from DNS.

Register VK WorkSpace account.

Add and confirm miranda-ng.org domain.

Create user: noreply@miranda-ng.org.

Login to this maibox via mail.ru website.

Create passwords for external application.

sudo nano /etc/postfix/sasl_passwd

[smtp.mail.ru]:587 noreply@miranda-ng.org:appP@ssword

sudo postmap /etc/postfix/sasl_passwd

sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

sudo nano /etc/postfix/generic

www-data              noreply@miranda-ng.org

sudo postmap /etc/postfix/generic

sudo nano etc/postfix/main.cf

smtp_tls_security_level = encrypt

relayhost = [smtp.mail.ru]:587

smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_loglevel = 1
smtp_generic_maps = hash:/etc/postfix/generic

sudo apt install libsasl2-modules

sudo systemctl restart postfix

Prosody

sudo wget https://prosody.im/downloads/repos/$(lsb_release -sc)/prosody.sources -O/etc/apt/sources.list.d/prosody.sources

sudo apt update

sudo apt install prosody lua-dbi-mysql

sudo mysql -u root

CREATE USER 'prosody'@'localhost' IDENTIFIED BY 'p@ssw0rd';
CREATE DATABASE prosody;
quit

sudo mysql -u root -f prosody < ~/prosody.sql

sudo mysql -u root

GRANT ALL ON prosody.* to 'prosody'@'localhost';
FLUSH PRIVILEGES;
quit

sudo nano /etc/prosody/prosody.cfg.lua

admins = { "username@miranda-ng.org", "username2@miranda-ng.org" }

modules_enabled = {
		--"register"; -- Allow users to register on this server
        "mam"; -- Store recent messages to allow multi-device synchronization
}

modules_disabled = {
        "s2s"; -- Handle server-to-server connections
}

storage = "sql" -- Default is "internal"

sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "p@ssword", host = "localhost" }

archive_expires_after = "never" -- Keep messages forever

--VirtualHost "localhost"
-- Prosody requires at least one enabled VirtualHost to function. You can
-- safely remove or disable 'localhost' once you have added another.

VirtualHost "miranda-ng.org"
ssl = {
        key = "/etc/letsencrypt/live/miranda-ng.org/privkey.pem";
        certificate = "/etc/letsencrypt/live/miranda-ng.org/fullchain.pem";
        protocol = "tlsv1_1+";
}

Component "conference.miranda-ng.org" "muc"
modules_enabled = { "muc_mam" }

sudo chmod -R 755 /etc/letsencrypt/live

sudo prosodyctl adduser username@miranda-ng.org

sudo systemctl enable --now prosody

sudo ufw allow 5000/tcp

sudo ufw allow 5222/tcp