The vidhukant.com Cheatsheet
| ~4 minute read
I'm assuming the domain(s) already point to the server, and the software is up-to-date, and you've logged into the root user with SSH.
Securing the server
SSH setup
Add the following lines (or edit if they already exist) to /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
Now before restarting the SSH service, I'll create a new user which holds my public key for login. I'll assume the username "vidhukant".
useradd vidhukant
usermod -g sudo vidhukant
Then on the client machine I can run:
ssh-copy-id vidhukant.com # or vidhukant@vidhukant.com if the client username is different
On the server, run this (as root) and check the SSH connection in another terminal.
ssh vidhukant.com # or vidhukant@vidhukant.com if the client username is different
Everything should be set up now. Its now not possible to log in without an SSH key pair,
and the root user won't allow to be logged in whatsoever. (su
and sudo
are our friends now)
Firewall setup
I'll be using UFW. You need to be root.
ufw default deny incoming
ufw default allow outgoing
ufw allow 22 # SSH
ufw allow 25 # SMTP
ufw allow 80 # HTTP
ufw allow 443 # HTTPS
ufw allow 587 # StartTLS
ufw allow 993 # IMAPS
ufw enable
Hosts and Hostname setup
Hostname
Edit /etc/hostname
and populate it with the desired hostname (vidhukant-vps
in my case)
Hosts file
This is what my /etc/hosts
looks like
# /etc/hosts
127.0.0.1 localhost
127.0.0.1 localhost.localdomain localhost
172.105.59.60 vidhukant.com vidhukant-vps
172.105.59.60 mail.vidhukant.com mail
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
2400:8904::f03c:93ff:feac:ca67 vidhukant.com vidhukant-vps
Setting up all the services
Website setup
Required packages: nginx
, python3-certbot-nginx
and rsync
The way I configure a static website
Save and edit this config accordingly. I'm placing this as "vidhukant" at
/etc/nginx/sites-available/vidhukant
# tor mirror (optional)
server {
listen 127.0.0.1:80;
root /var/www/vidhukant;
index index.html;
server_name <your_onion_url_here>.onion;
}
server {
server_name vidhukant.com;
root /var/www/vidhukant;
index index.html;
error_page 404 /404.html;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_types text/plain application/x-javascript text/xml text/css;
gzip_vary on;
# make cgit work with go get (optional)
if ($arg_go-get = 1) {
return 200 '<meta name="go-import" content="$host$uri git $scheme://git.vidhukant.com$uri">\n';
}
location / {
add_header Onion-Location http://<your_onion_url_here>.onion$request_uri; # optional
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'self'; style-src 'self' 'unsafe-inline'";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header 'Referrer-Policy' 'same-origin';
try_files $uri $uri/ =404;
}
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|svg|webp|woff2)$ {
add_header Onion-Location http://<your_onion_url_here>.onion$request_uri; # optional
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'self'";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header 'Referrer-Policy' 'same-origin';
add_header Cache-Control "max-age=7776000, public";
expires 1M;
access_log off;
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
add_header Onion-Location http://<your_onion_url_here>.onion$request_uri; # optional
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "frame-ancestors 'none'; default-src 'self'";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header 'Referrer-Policy' 'same-origin';
add_header Cache-Control "max-age=31556952, public";
expires 1M;
access_log off;
}
listen [::]:80;
listen 80;
}
After that, I need to "enable" this virtual with
ln -sf /etc/nginx/sites-available/vidhukant /etc/nginx/sites-enabled
and use certbot --nginx
to set up HTTPS.
After that, create a directory named "vidhukant" (or whatever you specified inside the
virtual host) in /var/www
and change its owner so it can be accessed with rsync.
mkdir /var/www/vidhukant
chown vidhukant:vidhukant /var/www/vidhukant
On the client machine, assuming the HTML is stored inside "public", run this command:
rsync -rtvzP public/ vidhukant.com:/var/www/vidhukant # or vidhukant@vidhukant.com if the client username is different
With this, vidhukant.com is online! Go ahead and check!
MariaDB Setup
Run the following as root:
apt install mariadb-server
mysql_secure_installation
mariadb
Now inside the MariaDB shell:
CREATE USER 'vidhukant'@'localhost' IDENTIFIED BY 'password123';
CREATE DATABASE some_db;
GRANT ALL PRIVILEGES ON some_db.* TO 'vidhukant'@'localhost';
FLUSH PRIVILEGES;
quit
This is where I'd create a new user and a database for Postfix and Dovecot.
At this point, the MariaDB service should be enabled by default.
Do a systemctl status mariadb
to check.
E-mail setup
Required packages: postfix
, postfix-mysql
, dovecot-core
, dovecot-lmtpd
,
dovecot-imapd
, dovecot-mysql
, opendkim
, opendkim-tools
, spamassassin
, spamc
Note: During Postfix installation, select Internet Site
-> vidhukant.com
I set up Postfix, Dovecot, etc with this guide. And I'm just gonna restore the config files mostly.
Setting up the Database and adding users
Create a new user and database for email purposes, and create these tables:
Creating the tables
CREATE TABLE `virtual_domains` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `virtual_users` (
`id` int(11) NOT NULL auto_increment,
`domain_id` int(11) NOT NULL,
`password` varchar(106) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `virtual_aliases` (
`id` int(11) NOT NULL auto_increment,
`domain_id` int(11) NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Populating data
Adding domains
Add an entry into virtual_domains
table for each domain that receives email.
INSERT INTO virtual_domains (name) VALUES ('vidhukant.com');
Adding users
Generate the password hash with:
doveadm pw -s SHA512-CRYPT | sed 's/{SHA512-CRYPT}//'
And use this SQL Command:
INSERT INTO virtual_users (domain_id, password , email) VALUES ('1', 'password_hash_here', 'vidhukant@vidhukant.com');
Adding aliases
INSERT INTO virtual_aliases (domain_id, source, destination) VALUES ('1', 'vidhu@vidhukant.com', 'vidhukant@vidhukant.com');
Steps to get the Postfix and Dovecot config files up and running:
List of config files I'm gonna copy over:
/etc/postfix/main.cf
/etc/postfix/master.cf
/etc/postfix/mysql-virtual-alias-maps.cf
/etc/postfix/mysql-virtual-email2email.cf
/etc/postfix/mysql-virtual-mailbox-domains.cf
/etc/postfix/mysql-virtual-mailbox-maps.cf
/etc/dovecot/dovecot.conf
/etc/dovecot/dovecot-sql.conf.ext
/etc/dovecot/conf.d/auth-sql.conf.ext
/etc/dovecot/conf.d/10-mail.conf
/etc/dovecot/conf.d/10-auth.conf
/etc/dovecot/conf.d/10-master.conf
/etc/dovecot/conf.d/10-ssl.conf
Getting an SSL certificate
certbot certonly -d mail.vidhukant.com
If the path to the SSL certificate has changed, then
A add/edit this in /etc/postfix/main.cf
:
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.vidhukant.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.vidhukant.com/privkey.pem
And these lines in /etc/dovecot/conf.d/10-ssl.conf
:
ssl_cert = </etc/letsencrypt/live/mail.vidhukant.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.vidhukant.com/privkey.pem
Hooking these up with MariaDB
If the MariaDB credentials have changed,
In /etc/postfix
edit these files accordingly (self explanatory):
mysql-virtual-alias-maps.cf
mysql-virtual-email2email.cf
mysql-virtual-mailbox-domains.cf
mysql-virtual-mailbox-maps.cf
Open /etc/dovecot/dovecot-sql.conf.ext
and look for and edit this line:
connect = host=127.0.0.1 dbname= user= password=
Wrapping Up
Add a vmail
group and a directory to store the messages.
mkdir -p /var/mail/vhosts/vidhukant.com
groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/mail
chown -R vmail:vmail /var/mail
Set appropriate permissions for the config files:
chmod -R o-rwx /etc/postfix
chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
Restart the services:
systemctl restart postfix
systemctl restart dovecot
Setting up OpenDKIM
I'll just follow my own guide here.
Hiring a hitman for spammers (Spamassassin)
Adding the user:
Just keep pressing enter since the details it asks for don't really matter much.
adduser spamd --disabled-login
Add/edit these lines in /etc/default/spamassassin
:
HOMEDIR="/home/spamd/"
OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir ${HOMEDIR} -s ${HOMEDIR}spamd.log"
PIDFILE="${HOMEDIR}spamd.pid"
CRON=1
Start and enable Spamassassin: (and restart postfix but I'd just reboot my server at this point)
systemctl enable --now spamassassin
This is post 17 of #100DaysToOffload