sudo apt-get install opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys/ENTER-YOUR-DOMAIN.COM
sudo opendkim-genkey -b 2048 -d ENTER-YOUR-DOMAIN.COM -D /etc/opendkim/keys/ENTER-YOUR-DOMAIN.COM -s mail -v
# import DNS record from mail.txt in /etc/opendkim/keys/ENTER-YOUR-DOMAIN.COM
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod -R go-rw /etc/opendkim/keys
# edit /etc/mail/sendmail.mc , add: INPUT_MAIL_FILTER(`opendkim', `S=local:/run/opendkim/opendkim.sock')
# edit /etc/opendkim.conf ,
#Domain yourdomain.com
#KeyFile /etc/opendkim/keys/yourdomain.com/mail.private
#Selector mail
sudo m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
sudo systemctl restart opendkim
sudo systemctl restart sendmail
Author: LPodolski
PostgreSQL drop and recreate database
sudo -u postgres -i pg_dump ENTER_db_name_here > /var/ENTER_db_name_here_"$(date +%Y-%m-%d_%H%M%S)".sql \
&& sudo -u postgres psql -c "DROP DATABASE ENTER_db_name_here WITH(FORCE);" \
&& sudo -u postgres psql -c "CREATE DATABASE ENTER_db_name_here;"
as separate commands:
sudo -u postgres -i pg_dump ENTER_db_name_here > /var/ENTER_db_name_here_"$(date +%Y-%m-%d_%H%M%S)".sql
sudo -u postgres psql -c "DROP DATABASE ENTER_db_name_here WITH(FORCE);"
sudo -u postgres psql -c "CREATE DATABASE ENTER_db_name_here;"
Linux server todo, first things, first 5 minutes on HTTP server
On Ubuntu 20 LTS
uname -a ; lsb_release -a
apt update && apt upgrade -y
apt install fail2ban unattended-upgrades apt-listchanges git zip software-properties-common
ufw allow 80
ufw allow 443
ufw allow 22
ufw enable
apt-get install unattended-upgrades
nano /etc/apt/apt.conf.d/10periodic
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
nano /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"Ubuntu lucid-security";
// "Ubuntu lucid-updates";
};
Unattended-Upgrade::Automatic-Reboot "true";
sudo dpkg-reconfigure -plow unattended-upgrades
sudo unattended-upgrades --dry-run
reboot
nginx
apt install nginx
sudo unlink /etc/nginx/sites-enabled/default
mkdir /var/www/TODO-ENTER-YOUR-DOMAIN.com
nano /etc/nginx/sites-available/TODO-ENTER-YOUR-DOMAIN.com
# paste and use nginx domain config bellow
ln -s /etc/nginx/sites-available/TODO-ENTER-YOUR-DOMAIN.com /etc/nginx/sites-enabled/
nginx -t
sudo systemctl reload nginx
nginx basic
server {
listen 80;
server_name TODO-ENTER-YOUR-DOMAIN.com;
root /var/www/TODO-ENTER-YOUR-DOMAIN.com/public;
index index.html index.htm index.php;
location ~ /\. {
deny all;
}
location ^~ /.well-known/ {
allow all;
}
location / {
index index.html index.php; ## Allow a static html file to be shown first
try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler
expires 30d; ## Assume all files are cachable
}
location @handler {
rewrite / /index.php;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
nginx with HTTP auth
generate .htpasswd
:
sudo apt install apache2-utils && sudo htpasswd -c /etc/apache2/.htpasswd user
nginx config with http auth
server {
listen 80;
server_name TODO-ENTER-YOUR-DOMAIN.com;
root /var/www/TODO-ENTER-YOUR-DOMAIN.com/public;
index index.html index.htm index.php;
location ~ /\. {
deny all;
}
location ^~ /.well-known/ {
allow all;
}
location / {
satisfy any;
allow 127.0.0.1;
deny all;
auth_basic "HTTP auth";
auth_basic_user_file /etc/apache2/.htpasswd;
index index.html index.php;
try_files $uri $uri/ @handler;
expires 30d;
}
location @handler {
rewrite / /index.php;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
HTTPS
apt install certbot python3-certbot-nginx
certbot --nginx -d TODO-ENTER-YOUR-DOMAIN.com
systemctl status certbot.timer
certbot renew --dry-run
PHP
sudo add-apt-repository ppa:ondrej/php -y
apt install php8.1 php8.1-fpm php8.1-common php8.1-pdo php8.1-pgsql php8.1-intl php8.1-mbstring php8.1-xml php8.1-dom php8.1-xml php8.1-curl php8.1-gd php8.1-imagick php8.1-cli php8.1-dev php8.1-imap php8.1-opcache php8.1-zip php8.1-redis php8.1-intl
composer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '906a84df04cea2aa72f40b5f787e49f22d4c2f19492ac310e8cba5b96ac8b64115ac402c8cd292b8a03482574915d1a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/local/bin/composer
Symfony
wget https://get.symfony.com/cli/installer -O - | bash
mv /root/.symfony/bin/symfony /usr/local/bin/symfony
symfony check:requirements
node
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
apt-get install -y nodejs
npm install
npm install --global yarn
PostgreSQL
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
apt update && apt upgrade
sudo apt install postgresql-14 postgresql-client-14
sudo -u postgres psql
CREATE DATABASE yourdbname;
CREATE USER youruser WITH ENCRYPTED PASSWORD 'yourpass';
GRANT ALL PRIVILEGES ON DATABASE yourdbname TO youruser;
exit
mySQL
CREATE DATABASE example_database;
CREATE USER 'example_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
GRANT ALL ON example_database.* TO 'example_user'@'%';
to install mysql 5.7: https://www.vultr.com/docs/how-to-install-mysql-5-7-on-ubuntu-20-04/
git global
git config --global user.name "YOUR-SERVER-DOMAIN.COM"
git config --global user.email "[email protected]"
deploy
ssh-keygen -t ed25519 -C "[email protected]"
cat /root/.ssh/id_ed25519.pub
# add public ssh key to your repo config, at least read only
cd /var/www/TODO-ENTER-YOUR-DOMAIN.com
git clone enterYourGitRepoAddress /var/www/TODO-ENTER-YOUR-DOMAIN.com
composer install --no-dev --classmap-authoritative --no-interaction
composer dump-env prod
php bin/console doctrine:database:create
php bin/console doctrine:migrations:migrate --all-or-nothing --no-interaction
php bin/console app:execute-one-time
npm install
yarn encore production
permissions
chmod -R 750 /var/www/YOUR-DOMAIN.COM/var
chown -R www-data:www-data /var/www/YOUR-DOMAIN.COM
chmod +x ./bin/console;
DB backup
sudo -u postgres -i pg_dump database_name > /var/zzzz_database_backup/database_name_"$(date +%Y-%m-%d_%H%M%S)".sql
Mailhog
sudo apt-get -y install golang-go git
go get github.com/mailhog/MailHog
sudo cp ~/go/bin/MailHog /usr/local/bin/Mailhog
Mailhog
sudo tee /etc/systemd/system/mailhog.service <<EOL
[Unit]
Description=Mailhog
After=network.target
[Service]
User=$USER
ExecStart=/usr/bin/env /usr/local/bin/Mailhog > /dev/null 2>&1 &
[Install]
WantedBy=multi-user.target
EOL
sudo systemctl start mailhog
sudo systemctl enable mailhog
# mailhog password
sudo tee /etc/systemd/system/mailhog.service <<EOL
[Unit]
Description=Mailhog
After=network.target
[Service]
User=$USER
ExecStart=/usr/bin/env /usr/local/bin/Mailhog -auth-file=/etc/mailhog-auth.txt > /dev/null 2>&1 &
[Install]
WantedBy=multi-user.target
EOL
# https://www.browserling.com/tools/bcrypt
sudo tee /etc/mailhog-auth.txt <<EOL
LOGIN_HERE:BCRYPT_PASSWORD_HERE
EOL
other
rm -r ./var/cache/prod
php bin/console cache:warmup --env=prod --no-interaction
composer install --optimize-autoloader --no-dev --no-interaction # for testing and fast updates, autoloader without cache
sudo lsof -i -P | grep LISTEN | grep :$PORT # check ports usage
check linux, ubuntu version
uname -a; lsb_release -a
Delete millions, large number of files on FTP / SFTP / FTPS server, like in hetzner storage box
of course better option than deleting millions of files would be to use rm -r
system command or unmount specific directory, but sometimes you don’t have such access, in that case you can use `lftp` command line in example bellow
it would be faster to use lftp rather than midnight commander or other GUI ftp client, because lftp executed via command line would be faster
nohup lftp -u ENTER_USERNAME_HERE,ENTER_PASS_HERE sftp://ENTER_USERNAME_HERE.your-storagebox.de:/home/ -p 23 -e "rm -r /home/ENTER_DIRECTORY_TO_DELETE_HERE" &
nohup is used so that process won’t stop when you log out or connection is closed, this is important because deleting millions of files, one by one using this method could take days
sometimes you can encounter problems with permissions, to fix this you can change invalid permissions using chmod:
nohup lftp -u ENTER_USERNAME_HERE,ENTER_PASS_HERE sftp://ENTER_USERNAME_HERE.your-storagebox.de:/home/ -p 23 -e "chmod -R 770 /home/ENTER_DIRECTORY_TO_DELETE_HERE" &
Javascript, iterate over key and value in JS
for (const [key, value] of Object.entries(valueList)) {
}
quick native JS test if CORS send and working
execute this in browser’s Js console:
POST request
fetch('//example.com/movies.json', {
method: 'POST',
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify({
"postDataHere_Key": "postDataValue",
})
})
.then(response => response.json())
.then(data => console.log(data));
GET request
fetch('//example.com/movies.json', {
method: 'GET',
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
})
.then(response => response.json())
.then(data => console.log(data));
and see if there’s response and no errors
to test if JavaScript request do not result in “Access to fetch at ‘http://example.com/movies.json’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.”
test, check microphone
find git ignored PHP files
to search for PHP files that are ignored by git
git check-ignore -v $(find . -type f -name '*.php' -print)
Leaflet custom icon from svg data
var svg = "<svg height=\"512pt\" viewBox=\"0 0 512 512\" width=\"512pt\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"m256 0c-141.164062 0-256 114.835938-256 256s114.835938 256 256 256 256-114.835938 256-256-114.835938-256-256-256zm0 0\" fill=\"#f44336\"/><path d=\"m341.332031 256c0 47.128906-38.203125 85.332031-85.332031 85.332031s-85.332031-38.203125-85.332031-85.332031 38.203125-85.332031 85.332031-85.332031 85.332031 38.203125 85.332031 85.332031zm0 0\" fill=\"#fafafa\"/><path d=\"m256 512c-141.164062 0-256-114.835938-256-256s114.835938-256 256-256 256 114.835938 256 256-114.835938 256-256 256zm0-480c-123.519531 0-224 100.480469-224 224s100.480469 224 224 224 224-100.480469 224-224-100.480469-224-224-224zm0 0\"/><path d=\"m256 362.667969c-58.816406 0-106.667969-47.851563-106.667969-106.667969s47.851563-106.667969 106.667969-106.667969 106.667969 47.851563 106.667969 106.667969-47.851563 106.667969-106.667969 106.667969zm0-181.335938c-41.171875 0-74.667969 33.496094-74.667969 74.667969s33.496094 74.667969 74.667969 74.667969 74.667969-33.496094 74.667969-74.667969-33.496094-74.667969-74.667969-74.667969zm0 0\"/></svg>";
var svgUrl = "data:image/svg+xml," + encodeURIComponent(svg);
var markerIcon = L.icon({
iconUrl: svgUrl,
iconSize: [22, 22],
iconAnchor: [11, 11],
popupAnchor: [0, -11],
shadowSize: false,
shadowAnchor: false,
});
new L.marker(new L.LatLng(52, 21), {icon: markerIcon})
.bindPopup(`popup`)
.addTo(map)
;