User:Dart Raiden/Server setup: Difference between revisions
Dart Raiden (talk | contribs) No edit summary |
Dart Raiden (talk | contribs) |
||
| (82 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
== Export Prosody database from old server == | |||
<tt>mysqldump --user=prosody --password="p@ssword" --default-character-set=utf8 prosody > prosody.sql</tt> | |||
== Backup forum, wiki, and website == | |||
<tt>sudo apt install unzip zip</tt> | |||
<tt>cd /var/www/forum.miranda-ng.org</tt> | |||
<tt>sudo ./zipme.sh</tt> | |||
<tt>cd /var/www/wiki.miranda-ng.org</tt> | |||
<tt>sudo ./zipme.sh</tt> | |||
<tt>cd /var/www/miranda-ng.org</tt> | |||
<tt>sudo ./zipme.sh</tt> | |||
== UFW == | |||
<tt>sudo apt install ufw</tt> | |||
<tt>sudo ufw allow 22/tcp</tt> | |||
<tt>sudo ufw enable</tt> | |||
== SSH == | |||
<tt>sudo nano /etc/ssh/sshd_config.d/deny_password_authentication.conf</tt> | |||
<pre style="overflow:auto;"> | |||
PasswordAuthentication no | |||
</pre> | |||
<tt>sudo nano /etc/ssh/sshd_config.d/deny_root_login.conf</tt> | |||
<pre style="overflow:auto;"> | |||
PermitRootLogin no | |||
</pre> | |||
<tt>sudo nano /etc/ssh/sshd_config.d/enable_pubkey_authentication.conf</tt> | |||
<pre style="overflow:auto;"> | |||
PubkeyAuthentication yes | |||
</pre> | |||
<tt>sudo systemctl reload ssh</tt> | |||
== MariaDB == | |||
<tt>sudo apt install mariadb-server</tt> | |||
<tt>sudo mariadb-secure-installation</tt> | |||
(do not set a root password; enable the other restrictions) | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket; | |||
FLUSH PRIVILEGES; | |||
quit | |||
</pre> | |||
<tt>sudo nano /etc/mysql/mariadb.conf.d/99-custom.cnf</tt> | |||
<pre style="overflow:auto;"> | |||
[mysqld] | |||
innodb_buffer_pool_size = 6G | |||
max_connections = 1000 | |||
thread_cache_size = 100 | |||
wait_timeout = 1800 | |||
interactive_timeout = 1800 | |||
</pre> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
CREATE USER 'forum'@'localhost' IDENTIFIED BY 'p@ssword'; | |||
CREATE DATABASE forum_miranda_ng_org; | |||
quit | |||
</pre> | |||
<tt>sudo mysql -u root -f forum_miranda_ng_org < ~/forum_miranda_ng_org.sql</tt> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
GRANT ALL ON forum_miranda_ng_org.* to 'forum'@'localhost'; | |||
FLUSH PRIVILEGES; | |||
quit | |||
</pre> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
CREATE USER 'wiki'@'localhost' IDENTIFIED BY 'p@ssword'; | |||
CREATE DATABASE wiki_miranda_ng_org; | |||
quit | |||
</pre> | |||
<tt>sudo mysql -u root -f wiki_miranda_ng_org < ~/wiki_miranda_ng_org.sql</tt> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
GRANT ALL ON wiki_miranda_ng_org.* to 'wiki'@'localhost'; | |||
FLUSH PRIVILEGES; | |||
quit | |||
</pre> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
CREATE USER 'prosody'@'localhost' IDENTIFIED BY 'p@ssword'; | |||
CREATE DATABASE prosody; | |||
quit | |||
</pre> | |||
<tt>sudo mysql -u root -f prosody < ~/prosody.sql</tt> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
GRANT ALL ON prosody.* to 'prosody'@'localhost'; | |||
FLUSH PRIVILEGES; | |||
quit | |||
</pre> | |||
== PHP == | |||
<tt>sudo apt install php-fpm php-mysql php-mbstring php-curl php-gd php-xml php-intl memcached</tt> | |||
<tt>sudo nano /etc/php/8.5/fpm/pool.d/www.conf</tt> | |||
<pre style="overflow:auto;"> | |||
pm = ondemand | |||
pm.max_children = 20 | |||
</pre> | |||
== Nginx == | |||
<tt>sudo apt install nginx</tt> | |||
<tt>sudo nano /etc/nginx/nginx.conf</tt> | |||
<pre style="overflow:auto;"> | |||
user www-data; | |||
worker_processes auto; | |||
worker_cpu_affinity 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; | |||
## | |||
# Basic Settings | |||
## | |||
sendfile on; | |||
tcp_nopush on; | |||
types_hash_max_size 2048; | |||
server_tokens off; | |||
client_max_body_size 20m; | |||
tcp_nodelay on; | |||
keepalive_timeout 75 20; | |||
## | |||
# Logging Settings | |||
## | |||
log_format main | |||
'$remote_addr - $remote_user [$time_local] ' | |||
'"$request" $status $bytes_sent ' | |||
'"$http_referer" "$http_user_agent" ' | |||
'"$gzip_ratio"'; | |||
access_log /var/log/nginx/access.log main; | |||
## | |||
# Gzip Settings | |||
## | |||
gzip on; | |||
gzip_vary on; | |||
gzip_proxied expired no-cache no-store private auth; | |||
gzip_comp_level 6; | |||
gzip_min_length 1100; | |||
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/ttf | |||
font/otf | |||
image/svg+xml; | |||
gzip_static on; | |||
## | |||
# Virtual Host Configs | |||
## | |||
include /etc/nginx/conf.d/*.conf; | |||
include /etc/nginx/sites-enabled/*; | |||
} | |||
</pre> | |||
<tt>sudo nano /etc/nginx/snippets/public.conf</tt> | |||
<pre style="overflow:auto;"> | |||
log_not_found off; | |||
access_log off; | |||
</pre> | |||
<tt>sudo nano /etc/nginx/snippets/phpfpm.conf</tt> | |||
<pre style="overflow:auto;"> | |||
fastcgi_index index.php; | |||
fastcgi_pass unix:/run/php/php8.5-fpm.sock; | |||
include fastcgi.conf; | |||
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; | |||
</pre> | |||
<tt>sudo ufw allow 80/tcp</tt> | |||
<tt>sudo ufw allow 443/tcp</tt> | |||
== Restore forum backup == | |||
<tt>sudo mkdir /var/www/forum.miranda-ng.org</tt> | |||
<tt>sudo unzip ~/forum.zip -d /var/www/forum.miranda-ng.org</tt> | |||
<tt>sudo nano /etc/nginx/sites-available/forum.miranda-ng.org</tt> | |||
<pre style="overflow:auto;"> | |||
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; | |||
index index.php; | |||
location = /favicon.ico { | |||
include snippets/public.conf; | |||
} | |||
location = /robots.txt { | |||
include snippets/public.conf; | |||
} | |||
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; | |||
include snippets/phpfpm.conf; | |||
} | |||
location ^~ /Packages/ { | |||
allow 127.0.0.1; | |||
deny all; | |||
} | |||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2)$ { | |||
expires max; | |||
log_not_found off; | |||
} | |||
location ~ /\.ht { | |||
deny all; | |||
} | |||
} | |||
server { | |||
listen 80; | |||
server_name forum.miranda-ng.org; | |||
return 301 https://$host$request_uri; | |||
} | |||
</pre> | |||
<tt>sudo ln -s /etc/nginx/sites-available/forum.miranda-ng.org /etc/nginx/sites-enabled/</tt> | |||
<tt>sudo chown -R www-data:www-data /var/www/forum.miranda-ng.org</tt> | |||
<tt>sudo chmod -R 644 /var/www/forum.miranda-ng.org</tt> | |||
<tt>sudo find /var/www/forum.miranda-ng.org -type d -print0 | sudo xargs -0 chmod 755</tt> | |||
<tt>sudo chmod +x /var/www/forum.miranda-ng.org/zipme.sh</tt> | |||
Use repair_settings.php and status.php from https://github.com/SimpleMachines/tools/ | |||
== Restore wiki backup == | |||
<tt>sudo mkdir /var/www/wiki.miranda-ng.org</tt> | |||
<tt>sudo unzip ~/wiki.zip -d /var/www/wiki.miranda-ng.org</tt> | |||
<tt>sudo nano /etc/nginx/sites-available/wiki.miranda-ng.org</tt> | |||
<pre style="overflow:auto;"> | |||
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; | |||
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 ^~ /images/ { | |||
expires max; | |||
log_not_found off; | |||
location ~ \.php$ { | |||
deny all; | |||
} | |||
} | |||
location ~ \.php$ { | |||
try_files $uri @404; | |||
include snippets/phpfpm.conf; | |||
} | |||
location @404 { | |||
return 404; | |||
} | |||
# 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 { | |||
listen 80; | |||
server_name wiki.miranda-ng.org; | |||
return 301 https://$host$request_uri; | |||
} | |||
</pre> | |||
<tt>sudo ln -s /etc/nginx/sites-available/wiki.miranda-ng.org /etc/nginx/sites-enabled/</tt> | |||
<tt>sudo chown -R www-data:www-data /var/www/wiki.miranda-ng.org</tt> | |||
<tt>sudo chmod -R 644 /var/www/wiki.miranda-ng.org</tt> | |||
<tt>sudo find /var/www/wiki.miranda-ng.org -type d -print0 | sudo xargs -0 chmod 755</tt> | |||
<tt>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</tt> | |||
<tt>php /var/www/wiki.miranda-ng.org/htdocs/maintenance/run.php update</tt> | |||
== Restore website backup == | |||
<tt>sudo apt install hugo</tt> | |||
<tt>sudo mkdir /var/www/miranda-ng.org</tt> | |||
<tt>sudo unzip ~/mainsite.zip -d /var/www/miranda-ng.org</tt> | |||
<tt>sudo nano /etc/nginx/sites-available/oauth.miranda-ng.org</tt> | |||
<pre style="overflow:auto;"> | |||
# 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; | |||
access_log /var/log/nginx/oauth.miranda-ng.org_access.log main; | |||
error_log /var/log/nginx/oauth.miranda-ng.org_error.log; | |||
location / { | |||
return 301 https://miranda-ng.org/verification$is_args$args; | |||
} | |||
} | |||
server { | |||
listen 80; | |||
server_name oauth.miranda-ng.org; | |||
return 301 https://miranda-ng.org/verification$is_args$args; | |||
} | |||
</pre> | |||
<tt>sudo ln -s /etc/nginx/sites-available/oauth.miranda-ng.org /etc/nginx/sites-enabled/</tt> | |||
<tt>sudo nano /etc/nginx/sites-available/miranda-ng.org</tt> | |||
<pre style="overflow:auto;"> | |||
# case-sensitive user agent blocking | |||
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; | |||
access_log /var/log/nginx/miranda-ng.org_access.log main if=$excluded_ua; | |||
error_log /var/log/nginx/miranda-ng.org_error.log; | |||
if ($excluded_ua = "0") { | |||
return 403; | |||
} | |||
index index.html; | |||
autoindex off; | |||
error_page 404 /404.html; | |||
# CloudFile: verification.php | |||
location ~* \.php$ { | |||
try_files $uri =404; | |||
include snippets/phpfpm.conf; | |||
} | |||
# CloudFile: /verification -> /verification.php | |||
location ~ /verification { | |||
rewrite ^/verification(.*)$ /verification.php$1 break; | |||
try_files $uri =404; | |||
include snippets/phpfpm.conf; | |||
} | |||
location ~ /distr { | |||
# downloads are stored outside Hugo's public directory | |||
# to prevent them from being removed/rebuilt by Hugo | |||
root /var/www/miranda-ng.org; | |||
autoindex on; | |||
} | |||
location ~ /(x32|x64) { | |||
# downloads are stored outside Hugo's public directory | |||
# to prevent them from being removed/rebuilt by Hugo | |||
root /var/www/miranda-ng.org/distr; | |||
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; | |||
} | |||
location = /favicon.ico { | |||
include snippets/public.conf; | |||
} | |||
location = /robots.txt { | |||
include snippets/public.conf; | |||
} | |||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|pdf)$ { | |||
expires max; | |||
log_not_found off; | |||
} | |||
location ~ /hotcoffee { | |||
add_header Cache-Control "no-cache,no-store,must-revalidate" always; | |||
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 miranda-ng.org/p/PluginName > wiki.miranda-ng.org/index.php?title=Plugin:PluginName | |||
location ~ /p/ { | |||
rewrite ^/p/(.*?)/?$ https://wiki.miranda-ng.org/index.php?title=Plugin:$1 permanent; | |||
} | |||
} | |||
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 { | |||
# downloads are stored outside Hugo's public directory | |||
# to prevent them from being removed/rebuilt by Hugo | |||
root /var/www/miranda-ng.org; | |||
add_header Cache-Control "private" always; | |||
add_header Content-Disposition "attachment" always; | |||
autoindex on; | |||
} | |||
} | |||
</pre> | |||
<tt>sudo ln -s /etc/nginx/sites-available/miranda-ng.org /etc/nginx/sites-enabled/</tt> | |||
<tt>sudo nano /etc/nginx/sites-available/www.miranda-ng.org</tt> | |||
<pre style="overflow:auto;"> | |||
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 www.miranda-ng.org; | |||
access_log off; | |||
error_log off; | |||
return 301 https://miranda-ng.org$request_uri; | |||
} | |||
server { | |||
listen 80; | |||
server_name www.miranda-ng.org; | |||
return 301 https://miranda-ng.org$request_uri; | |||
} | |||
</pre> | |||
<tt>sudo ln -s /etc/nginx/sites-available/www.miranda-ng.org /etc/nginx/sites-enabled/</tt> | |||
<tt>sudo nano /etc/nginx/sites-available/addons.miranda-ng.org</tt> | |||
<pre style="overflow:auto;"> | |||
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; | |||
access_log off; | |||
error_log off; | |||
return 301 https://miranda-ng.org/addons$request_uri; | |||
} | |||
server { | |||
listen 80; | |||
server_name addons.miranda-ng.org; | |||
return 301 https://miranda-ng.org/addons$request_uri; | |||
} | |||
</pre> | |||
<tt>sudo ln -s /etc/nginx/sites-available/addons.miranda-ng.org /etc/nginx/sites-enabled/</tt> | |||
<tt>sudo chown -R www-data:www-data /var/www/miranda-ng.org</tt> | |||
<tt>sudo chmod -R 644 /var/www/miranda-ng.org</tt> | |||
<tt>sudo find /var/www/miranda-ng.org -type d -print0 | sudo xargs -0 chmod 755</tt> | |||
<tt>sudo chmod -R 775 /var/www/miranda-ng.org/htdocs/content /var/www/miranda-ng.org/htdocs/static /var/www/miranda-ng.org/distr</tt> | |||
<tt>sudo chmod +x /var/www/miranda-ng.org/zipme.sh /var/www/miranda-ng.org/scripts/*</tt> | |||
== Hugo == | |||
<tt>sudo apt install hugo</tt> | |||
<tt>sudo groupadd website-editors</tt> | |||
Add all website content editors to <tt>website-editors</tt> group: | |||
<tt>sudo usermod -aG website-editors ghazan</tt> | |||
<tt>sudo usermod -aG website-editors dartraiden</tt> | |||
<tt>sudo usermod -aG website-editors tweimer</tt> | |||
<tt>sudo usermod -aG website-editors dracosha</tt> | |||
<tt>sudo chown -R www-data:website-editors /var/www/miranda-ng.org/htdocs</tt> | |||
<tt>sudo chown -R www-data:www-data /var/www/miranda-ng.org/public/</tt> | |||
<tt>sudo chmod 2755 /var/www/miranda-ng.org/htdocs</tt> | |||
<tt>sudo find /var/www/miranda-ng.org/htdocs/{content,layouts,static,themes} -type d -exec chmod 2775 {} \;</tt> | |||
<tt>sudo find /var/www/miranda-ng.org/htdocs/{content,layouts,static,themes} -type f -exec chmod 664 {} \;</tt> | |||
<tt>sudo chown www-data:website-editors /var/www/miranda-ng.org/htdocs/config.toml</tt> | |||
<tt>sudo chmod 664 /var/www/miranda-ng.org/htdocs/config.toml</tt> | |||
<tt>sudo nano /usr/local/sbin/build-site</tt> | |||
<pre style="overflow:auto;"> | |||
#!/bin/bash | |||
set -euo pipefail | |||
SITE_DIR="/var/www/miranda-ng.org/htdocs" | |||
PUBLIC_DIR="$SITE_DIR/public" | |||
NEW_DIR="$SITE_DIR/.public-new" | |||
OLD_DIR="$SITE_DIR/.public-old" | |||
echo "==> Building site..." | |||
cd "$SITE_DIR" | |||
rm -rf "$NEW_DIR" | |||
rm -rf "$OLD_DIR" | |||
mkdir "$NEW_DIR" | |||
chown www-data:www-data "$NEW_DIR" | |||
runuser -u www-data -- hugo \ | |||
--config "$SITE_DIR/config.toml" \ | |||
--destination "$NEW_DIR" | |||
echo "==> Hugo build successful." | |||
if [ ! -f "$NEW_DIR/index.html" ]; then | |||
echo "ERROR: Hugo build did not produce index.html" | |||
rm -rf "$NEW_DIR" | |||
exit 1 | |||
fi | |||
chown -R www-data:www-data "$NEW_DIR" | |||
find "$NEW_DIR" -type d -exec chmod 755 {} \; | |||
find "$NEW_DIR" -type f -exec chmod 644 {} \; | |||
echo "==> Installing new site..." | |||
mv "$PUBLIC_DIR" "$OLD_DIR" | |||
if mv "$NEW_DIR" "$PUBLIC_DIR"; then | |||
rm -rf "$OLD_DIR" | |||
echo "==> Site successfully deployed." | |||
echo " $PUBLIC_DIR" | |||
else | |||
echo "ERROR: Failed to install new site. Rolling back..." | |||
if mv "$OLD_DIR" "$PUBLIC_DIR"; then | |||
echo "ERROR: Rollback completed. Old site restored." | |||
else | |||
echo "CRITICAL: Rollback failed!" | |||
echo " Old site is at: $OLD_DIR" | |||
exit 2 | |||
fi | |||
exit 1 | |||
fi | |||
</pre> | |||
<tt>sudo chmod +x /usr/local/sbin/build-site</tt> | |||
<tt>sudo visudo -f /etc/sudoers.d/website-editors</tt> | |||
<pre style="overflow:auto;"> | |||
%website-editors ALL=(root) NOPASSWD: /usr/local/sbin/build-site | |||
</pre> | |||
To build/deploy the site, simply run | |||
<tt>sudo build-site</tt> | |||
To update the theme to a specific release | |||
<tt>sudo -u www-data hugo mod get github.com/Lednerb/bilberry-hugo-theme/v4@v4.15.5</tt> | |||
<tt>sudo -u www-data hugo mod tidy</tt> | |||
replace v4.15.5 with the desired release. Note: New versions of the theme may require a newer version of Hugo. Check the theme's release notes/requirements before updating. | |||
== Certbot == | == Certbot == | ||
<tt>sudo apt install certbot python3-certbot-nginx</tt> | <tt>sudo apt install certbot python3-certbot-nginx</tt> | ||
<tt>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</tt> | <tt>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</tt> | ||
<tt>sudo systemctl reload nginx</tt> | |||
== Postfix == | == Postfix == | ||
| Line 12: | Line 747: | ||
miranda-ng.org | miranda-ng.org | ||
empty | empty | ||
miranda-ng.org, localhost.localdomain, localhost | |||
No | No | ||
default | default | ||
| Line 26: | Line 761: | ||
</pre> | </pre> | ||
<tt>sudo systemctl enable -now | <tt>sudo systemctl enable --now opendkim</tt> | ||
<tt>sudo opendkim-genkey -D /etc/dkimkeys/ --domain miranda-ng.org --selector dkim</tt> | <tt>sudo opendkim-genkey -D /etc/dkimkeys/ --domain miranda-ng.org --selector dkim</tt> | ||
<tt> | <tt>sudo nano /etc/opendkim.conf</tt> | ||
<pre style="overflow:auto;"> | <pre style="overflow:auto;"> | ||
LogWhy yes | |||
UMask 002 | UMask 002 | ||
Socket local:/var/spool/postfix/run/opendkim/opendkim.sock | Socket local:/var/spool/postfix/run/opendkim/opendkim.sock | ||
AutoRestart | InternalHosts refile:/etc/dkimkeys/TrustedHosts | ||
AutoRestart yes | |||
AutoRestartRate 10/1h | AutoRestartRate 10/1h | ||
ExternalIgnoreList refile:/etc/dkimkeys/TrustedHosts | ExternalIgnoreList refile:/etc/dkimkeys/TrustedHosts | ||
KeyTable refile:/etc/dkimkeys/KeyTable | KeyTable refile:/etc/dkimkeys/KeyTable | ||
SigningTable refile:/etc/dkimkeys/SigningTable | SigningTable refile:/etc/dkimkeys/SigningTable | ||
| Line 70: | Line 804: | ||
<tt>sudo chown -R opendkim:opendkim /etc/dkimkeys</tt> | <tt>sudo chown -R opendkim:opendkim /etc/dkimkeys</tt> | ||
<tt>sudo chmod 600 /etc/dkimkeys/ | <tt>sudo chmod -R 600 /etc/dkimkeys</tt> | ||
<tt>sudo chmod 700 /etc/dkimkeys</tt> | |||
<tt>sudo nano /etc/postfix/main.cf</tt> | <tt>sudo nano /etc/postfix/main.cf</tt> | ||
<pre style="overflow:auto;"> | <pre style="overflow:auto;"> | ||
milter_protocol = 2 | milter_protocol = 2 | ||
milter_default_action = accept | milter_default_action = accept | ||
smtpd_milters = unix:/run/opendkim/opendkim.sock | smtpd_milters = unix:/run/opendkim/opendkim.sock | ||
non_smtpd_milters = unix:/run/opendkim/opendkim.sock | non_smtpd_milters = unix:/run/opendkim/opendkim.sock | ||
</pre> | </pre> | ||
| Line 82: | Line 818: | ||
<tt>sudo nano /etc/hosts</tt> | <tt>sudo nano /etc/hosts</tt> | ||
<pre style="overflow:auto;"> | <pre style="overflow:auto;"> | ||
139.100.207.143 miranda-ng.org | |||
</pre> | </pre> | ||
<tt>sudo hostnamectl set-hostname miranda-ng.org</tt> | <tt>sudo hostnamectl set-hostname miranda-ng.org</tt> | ||
<tt>sudo systemctl | <tt>sudo systemctl reload opendkim</tt> | ||
<tt>sudo systemctl | <tt>sudo systemctl reload postfix</tt> | ||
DNS records: | DNS records: | ||
| Line 96: | Line 832: | ||
miranda-ng.org TXT v=spf1 +a +mx -all | miranda-ng.org TXT v=spf1 +a +mx -all | ||
DKIM._DOMAINKEY.miranda-ng.org TXT dkim_from_/etc/dkimkeys/dkim.txt | DKIM._DOMAINKEY.miranda-ng.org TXT dkim_from_/etc/dkimkeys/dkim.txt | ||
_DMARC.miranda-ng.org TXT v=DMARC1; p= | _DMARC.miranda-ng.org TXT v=DMARC1; p=reject; aspf=r; sp=reject | ||
</pre> | </pre> | ||
<tt>echo "Subject: hello" | sendmail test@example.com</tt> | <tt>echo "Subject: hello" | sendmail test@example.com</tt> | ||
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. | |||
<tt>sudo nano /etc/postfix/sasl_passwd</tt> | |||
<pre style="overflow:auto;"> | |||
[smtp.mail.ru]:587 noreply@miranda-ng.org:appP@ssword | |||
</pre> | |||
<tt>sudo postmap /etc/postfix/sasl_passwd</tt> | |||
<tt>sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db</tt> | |||
<tt>sudo nano /etc/postfix/generic</tt> | |||
<pre style="overflow:auto;"> | |||
www-data noreply@miranda-ng.org | |||
</pre> | |||
<tt>sudo postmap /etc/postfix/generic</tt> | |||
<tt>sudo nano etc/postfix/main.cf</tt> | |||
<pre style="overflow:auto;"> | |||
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 | |||
</pre> | |||
<tt>sudo apt install libsasl2-modules</tt> | |||
<tt>sudo systemctl reload postfix</tt> | |||
== Prosody == | == Prosody == | ||
<tt>sudo wget https://prosody.im/downloads/repos/$(lsb_release -sc)/prosody.sources -O/etc/apt/sources.list.d/prosody.sources</tt> | <tt>sudo wget https://prosody.im/downloads/repos/$(lsb_release -sc)/prosody.sources -O/etc/apt/sources.list.d/prosody.sources</tt> | ||
<tt>sudo apt update</tt> | |||
<tt>sudo apt install prosody lua-dbi-mysql</tt> | <tt>sudo apt install prosody lua-dbi-mysql</tt> | ||
| Line 110: | Line 896: | ||
CREATE USER 'prosody'@'localhost' IDENTIFIED BY 'p@ssw0rd'; | CREATE USER 'prosody'@'localhost' IDENTIFIED BY 'p@ssw0rd'; | ||
CREATE DATABASE prosody; | CREATE DATABASE prosody; | ||
quit | |||
</pre> | |||
<tt>sudo mysql -u root -f prosody < ~/prosody.sql</tt> | |||
<tt>sudo mysql -u root</tt> | |||
<pre style="overflow:auto;"> | |||
GRANT ALL ON prosody.* to 'prosody'@'localhost'; | GRANT ALL ON prosody.* to 'prosody'@'localhost'; | ||
FLUSH PRIVILEGES; | FLUSH PRIVILEGES; | ||
quit | quit | ||
</pre> | </pre> | ||
| Line 121: | Line 914: | ||
modules_enabled = { | modules_enabled = { | ||
--"register"; -- Allow users to register on this server | --"register"; -- Allow users to register on this server | ||
" | "mam"; -- Store recent messages to allow multi-device synchronization | ||
} | } | ||
modules_disabled = { | modules_disabled = { | ||
"s2s"; -- Handle server-to-server connections | |||
} | } | ||
| Line 132: | Line 925: | ||
sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "p@ssword", host = "localhost" } | sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "p@ssword", host = "localhost" } | ||
archive_expires_after = " | 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" | VirtualHost "miranda-ng.org" | ||
ssl = { | ssl = { | ||
key = "/etc/letsencrypt/live/miranda-ng.org/privkey.pem"; | |||
certificate = "/etc/letsencrypt/live/miranda-ng.org/fullchain.pem"; | |||
} | } | ||
| Line 154: | Line 945: | ||
<tt>sudo prosodyctl adduser username@miranda-ng.org</tt> | <tt>sudo prosodyctl adduser username@miranda-ng.org</tt> | ||
<tt>sudo systemctl enable -now prosody</tt> | <tt>sudo systemctl enable --now prosody</tt> | ||
<tt>sudo ufw allow 5000/tcp</tt> | |||
<tt>sudo ufw allow 5222/tcp</tt> | |||
Latest revision as of 01:47, 14 September 2026
Export Prosody database from old server
mysqldump --user=prosody --password="p@ssword" --default-character-set=utf8 prosody > prosody.sql
Backup forum, wiki, and website
sudo apt install unzip zip
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 reload ssh
MariaDB
sudo apt install mariadb-server
sudo mariadb-secure-installation (do not set a root password; enable the other restrictions)
sudo mysql -u root
ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket; FLUSH PRIVILEGES; quit
sudo nano /etc/mysql/mariadb.conf.d/99-custom.cnf
[mysqld] innodb_buffer_pool_size = 6G max_connections = 1000 thread_cache_size = 100 wait_timeout = 1800 interactive_timeout = 1800
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.5/fpm/pool.d/www.conf
pm = ondemand pm.max_children = 20
Nginx
sudo apt install nginx
sudo nano /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
worker_cpu_affinity 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;
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 20m;
tcp_nodelay on;
keepalive_timeout 75 20;
##
# Logging Settings
##
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
access_log /var/log/nginx/access.log main;
##
# Gzip Settings
##
gzip on;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 6;
gzip_min_length 1100;
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/ttf
font/otf
image/svg+xml;
gzip_static on;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
sudo nano /etc/nginx/snippets/public.conf
log_not_found off; access_log off;
sudo nano /etc/nginx/snippets/phpfpm.conf
fastcgi_index index.php; fastcgi_pass unix:/run/php/php8.5-fpm.sock; include fastcgi.conf; 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 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 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;
index index.php;
location = /favicon.ico {
include snippets/public.conf;
}
location = /robots.txt {
include snippets/public.conf;
}
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;
include snippets/phpfpm.conf;
}
location ^~ /Packages/ {
allow 127.0.0.1;
deny all;
}
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2)$ {
expires max;
log_not_found off;
}
location ~ /\.ht {
deny all;
}
}
server {
listen 80;
server_name forum.miranda-ng.org;
return 301 https://$host$request_uri;
}
sudo ln -s /etc/nginx/sites-available/forum.miranda-ng.org /etc/nginx/sites-enabled/
sudo chown -R www-data:www-data /var/www/forum.miranda-ng.org
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 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;
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 ^~ /images/ {
expires max;
log_not_found off;
location ~ \.php$ {
deny all;
}
}
location ~ \.php$ {
try_files $uri @404;
include snippets/phpfpm.conf;
}
location @404 {
return 404;
}
# 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 {
listen 80;
server_name wiki.miranda-ng.org;
return 301 https://$host$request_uri;
}
sudo ln -s /etc/nginx/sites-available/wiki.miranda-ng.org /etc/nginx/sites-enabled/
sudo chown -R www-data:www-data /var/www/wiki.miranda-ng.org
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/run.php update
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 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;
access_log /var/log/nginx/oauth.miranda-ng.org_access.log main;
error_log /var/log/nginx/oauth.miranda-ng.org_error.log;
location / {
return 301 https://miranda-ng.org/verification$is_args$args;
}
}
server {
listen 80;
server_name oauth.miranda-ng.org;
return 301 https://miranda-ng.org/verification$is_args$args;
}
sudo ln -s /etc/nginx/sites-available/oauth.miranda-ng.org /etc/nginx/sites-enabled/
sudo nano /etc/nginx/sites-available/miranda-ng.org
# case-sensitive user agent blocking
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;
access_log /var/log/nginx/miranda-ng.org_access.log main if=$excluded_ua;
error_log /var/log/nginx/miranda-ng.org_error.log;
if ($excluded_ua = "0") {
return 403;
}
index index.html;
autoindex off;
error_page 404 /404.html;
# CloudFile: verification.php
location ~* \.php$ {
try_files $uri =404;
include snippets/phpfpm.conf;
}
# CloudFile: /verification -> /verification.php
location ~ /verification {
rewrite ^/verification(.*)$ /verification.php$1 break;
try_files $uri =404;
include snippets/phpfpm.conf;
}
location ~ /distr {
# downloads are stored outside Hugo's public directory
# to prevent them from being removed/rebuilt by Hugo
root /var/www/miranda-ng.org;
autoindex on;
}
location ~ /(x32|x64) {
# downloads are stored outside Hugo's public directory
# to prevent them from being removed/rebuilt by Hugo
root /var/www/miranda-ng.org/distr;
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;
}
location = /favicon.ico {
include snippets/public.conf;
}
location = /robots.txt {
include snippets/public.conf;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|pdf)$ {
expires max;
log_not_found off;
}
location ~ /hotcoffee {
add_header Cache-Control "no-cache,no-store,must-revalidate" always;
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 miranda-ng.org/p/PluginName > wiki.miranda-ng.org/index.php?title=Plugin:PluginName
location ~ /p/ {
rewrite ^/p/(.*?)/?$ https://wiki.miranda-ng.org/index.php?title=Plugin:$1 permanent;
}
}
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 {
# downloads are stored outside Hugo's public directory
# to prevent them from being removed/rebuilt by Hugo
root /var/www/miranda-ng.org;
add_header Cache-Control "private" always;
add_header Content-Disposition "attachment" always;
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; # 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 www.miranda-ng.org;
access_log off;
error_log off;
return 301 https://miranda-ng.org$request_uri;
}
server {
listen 80;
server_name www.miranda-ng.org;
return 301 https://miranda-ng.org$request_uri;
}
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;
access_log off;
error_log off;
return 301 https://miranda-ng.org/addons$request_uri;
}
server {
listen 80;
server_name addons.miranda-ng.org;
return 301 https://miranda-ng.org/addons$request_uri;
}
sudo ln -s /etc/nginx/sites-available/addons.miranda-ng.org /etc/nginx/sites-enabled/
sudo chown -R www-data:www-data /var/www/miranda-ng.org
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/*
Hugo
sudo apt install hugo
sudo groupadd website-editors
Add all website content editors to website-editors group:
sudo usermod -aG website-editors ghazan
sudo usermod -aG website-editors dartraiden
sudo usermod -aG website-editors tweimer
sudo usermod -aG website-editors dracosha
sudo chown -R www-data:website-editors /var/www/miranda-ng.org/htdocs
sudo chown -R www-data:www-data /var/www/miranda-ng.org/public/
sudo chmod 2755 /var/www/miranda-ng.org/htdocs
sudo find /var/www/miranda-ng.org/htdocs/{content,layouts,static,themes} -type d -exec chmod 2775 {} \;
sudo find /var/www/miranda-ng.org/htdocs/{content,layouts,static,themes} -type f -exec chmod 664 {} \;
sudo chown www-data:website-editors /var/www/miranda-ng.org/htdocs/config.toml
sudo chmod 664 /var/www/miranda-ng.org/htdocs/config.toml
sudo nano /usr/local/sbin/build-site
#!/bin/bash
set -euo pipefail
SITE_DIR="/var/www/miranda-ng.org/htdocs"
PUBLIC_DIR="$SITE_DIR/public"
NEW_DIR="$SITE_DIR/.public-new"
OLD_DIR="$SITE_DIR/.public-old"
echo "==> Building site..."
cd "$SITE_DIR"
rm -rf "$NEW_DIR"
rm -rf "$OLD_DIR"
mkdir "$NEW_DIR"
chown www-data:www-data "$NEW_DIR"
runuser -u www-data -- hugo \
--config "$SITE_DIR/config.toml" \
--destination "$NEW_DIR"
echo "==> Hugo build successful."
if [ ! -f "$NEW_DIR/index.html" ]; then
echo "ERROR: Hugo build did not produce index.html"
rm -rf "$NEW_DIR"
exit 1
fi
chown -R www-data:www-data "$NEW_DIR"
find "$NEW_DIR" -type d -exec chmod 755 {} \;
find "$NEW_DIR" -type f -exec chmod 644 {} \;
echo "==> Installing new site..."
mv "$PUBLIC_DIR" "$OLD_DIR"
if mv "$NEW_DIR" "$PUBLIC_DIR"; then
rm -rf "$OLD_DIR"
echo "==> Site successfully deployed."
echo " $PUBLIC_DIR"
else
echo "ERROR: Failed to install new site. Rolling back..."
if mv "$OLD_DIR" "$PUBLIC_DIR"; then
echo "ERROR: Rollback completed. Old site restored."
else
echo "CRITICAL: Rollback failed!"
echo " Old site is at: $OLD_DIR"
exit 2
fi
exit 1
fi
sudo chmod +x /usr/local/sbin/build-site
sudo visudo -f /etc/sudoers.d/website-editors
%website-editors ALL=(root) NOPASSWD: /usr/local/sbin/build-site
To build/deploy the site, simply run
sudo build-site
To update the theme to a specific release
sudo -u www-data hugo mod get github.com/Lednerb/bilberry-hugo-theme/v4@v4.15.5
sudo -u www-data hugo mod tidy
replace v4.15.5 with the desired release. Note: New versions of the theme may require a newer version of Hugo. Check the theme's release notes/requirements before updating.
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 reload nginx
Postfix
sudo DEBIAN_PRIORITY=low apt install postfix opendkim opendkim-tools
sudo dpkg-reconfigure postfix
Internet Site miranda-ng.org empty miranda-ng.org, localhost.localdomain, localhost 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 reload opendkim
sudo systemctl reload 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=reject; aspf=r; sp=reject
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 reload 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";
}
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