Tag Archives: ssl

Virtualhost and Letsencrypt

Quick guideline about how to install multiple sites on a single server using Virtualhosting, and have the SSL certificate installed and automatically renewed using Letsencrypt.

There are plenty of how to online, but I wanted to have a quick reference page for myself 🙂

Firstly, this has been tested on Debian 12, but it should work on previous Debian versions and Ubuntu too.

Apache setup and virtualhosts

Firstly, install Apache and other packages that you will mostly likely need, especially if you run WordPress or any php based framework:

apt-get install apache2 php php-mysql libapache2-mod-php php-gd php-curl net-tools telnet dos2unix

Now, you should create the folder structure to host your sites. I used /var/www/virtualhosts/<site>/public_html

I made sure permissions were set correctly too:

chown -R www-data:www-data /var/www/
find /var/www -type -d -exec chmod 775 {} \;

Now, create a virtualhost file for each site. In the following example we are going to create the conf file for site1.

Create /etc/apache2/sites-available/site1.conf

<VirtualHost *:80>
    ServerName site1.com
    ServerAlias www.site1.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/virtualhosts/site1/public_html

    <Directory /var/www/virtualhosts/site1/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/site1-error.log
    CustomLog ${APACHE_LOG_DIR}/site1-access.log combined
</VirtualHost>

Do the same for all the sites you have.

Once done, upload the content of your sites in public_html folder.

Disable all the default Apache sites and enable the ones you have created. You can use the commands a2dissite and a2ensite or manually create symbolic links into /etc/apache2/sites-enabled/

Check that all the virtualhosts are properly loaded:

source /etc/apache2/envvars
apache2 -S

You should see all your sites under *80 section.
Right now we have enabled only Apache on port 80 to return the sites we have hosted. No 443 yet.

Now, you can use curl to do some tests to see if the virtual hosts are responding correctly.

~ curl -IH'Host: site1.com' http://<server_IP>  # to get the header of site1.com
~ curl -H'Host: site1.com' http://<server_IP>  # to get the full page of site1.com

Hopefully all works (if not, troubleshoot it heheh), let’s point our DNS to our server, and test directly using the domain names.

All good? Cool!

Make sure now that your firewall allows port 80 and port 443. Even if you’re considering to serve your site ONLY over SSL (port 443), the certbot tool that does the auto-renewal of the certificate needs port 80 open.

Installation and configuration of certbot – Letsencrypt

As root, issue the below commands:

apt-get install snapd
snap install core
snap refresh core
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot

You have now the certbot tool installed.

Following the above example of site1.com, we are going now to get the SSL certificate for that site (even the www.site1.com one), and let the tool install and configure everything automatically.

certbot --apache -d site1.com -d www.site1.com

Hopefully all goes well 🙂 Repeat for each of your sites accordingly.

Once done with all the sites, just to make sure the auto-renewal works, you can also issue a dry-run check:

certbot renew --dry-run

Letsencrypt certificates last 90 days (afaik), but the certbot tool installed in this way does the auto-renewal in an automatic fashion.
If you’re curios where this is written (you might think about cron but unable to find anything – like it happend to me).
If this is the case, you can try to run this command, and you may find the certbot listed:

systemctl list-timers

More information are available on the official website at this address.

You can now test using curl again, but hitting https instead of http:

~ curl -IH'Host: site1.com' https://<server_IP>  # to get the header of site1.com
~ curl -H'Host: site1.com' https://<server_IP>  # to get the full page of site1.com

Oh, one note.
By default, at least at the time when I’m writing this article, once you install the certificate, the *80 virtualhost of your site will be modified, adding the following lines, which force a 302 redirect from http to https.

RewriteEngine on
RewriteCond %{SERVER_NAME} =www.site1.com [OR]
RewriteCond %{SERVER_NAME} =site1.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

If it’s what you want – cool.
If you still want to serve your site on http AND https, comment out (or delete) those new lines.

Happy virtualhosting and ssl’ing! 🙂

Apache loop with WordPress and SSL cert installed on a Cloud Load Balancer

  • Terminate SSL onto the CLB
  • Change the main site URL to use HTTPS in the WordPress configuration
  • Add “SetEnvIf x-forwarded-proto https HTTPS=on” in the vhost configuration
  • add these in wp-config: [OPTIONAL]
    define(‘FORCE_SSL_ADMIN’, false);define(‘FORCE_SSL_LOGIN’, false);
    if (strpos($_SERVER[‘HTTP_X_FORWARDED_PROTO’], ‘https’) !== false)
    $_SERVER[‘HTTPS’]=’on’;


  • a good test to make sure PHP is receiving HTTPS are these lines in a test.php file. If should return “on” if PHP is getting HTTPS properly, or if it returns no value, PHP is not aware it’s being called over HTTPS.
    <?php
    printf($_SERVER['HTTPS'])
    ?>

     

Letsencrypt Free SSL Certificate

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto

If this command doesn’t work, you can try the following manual way

./letsencrypt-auto certonly --email [email protected] --webroot -w /var/www/vhosts/yourdomain.com -d yourdomain.com -d www.yourdomain.com

You can add multiple domains under the same certificate

./letsencrypt-auto certonly --email [email protected] --webroot -w /var/www/vhosts/yourdomain.com -d yourdomain.com -d www.yourdomain.com -w /var/www/vhosts/yourdomain2.com -d yourdomain2.com -d www.yourdomain2.com

Update your Apache configuration to use the new certificate:

SSLEngine on
SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem

Check domain:
https://crt.sh/?q=%25yourdomain.com

Renew the certificate with a script set in a cron (set every 2 months – certificate expires every 3)

# run on the 1st of Odd Months at midnight | Renew certificates
0 0 1 1-11/2 * root /root/letsencrypt/renew.sh >/dev/null 2>&1

renew.sh script:

#!/bin/bash

[email protected]

LOG=/var/log/letsencrypt/renew.log
SENDMAIL=/usr/sbin/sendmail
CMD="renew"

/root/letsencrypt/letsencrypt-auto $CMD > $LOG 2>&1

if [ $? -eq 0 ] ; then
    service httpd graceful
else
    echo -e "Subject: [letsencrypt] SSL automatic renewal FAILED\n$(cat $LOG)" | $SENDMAIL $MAIL
    exit 1
fi

Sources:
https://letsencrypt.org/getting-started/
https://www.a2hosting.com/kb/security/ssl/securing-your-site-with-a-lets-encrypt-ssl-certificate

SSL PASSIVE FTP with virtual users on Raspberry Pi

I found this handy plugin to backup my blog: BackWPup
It has also an interesting feature which is the ability to backup remotely, for example on a FTP server.

So… here we go! 🙂

Few notes:

  • This uses vsftpd software
  • It will work ONLY over SSL
  • Due to SSL encryption, the FTP will also work ONLY in PASSIVE mode (ACTIVE mode is disabled)
  • This configuration has been made based of the fact that this raspberry pi is behind a router
  • This will use ONLY virtual users, chroot’ed, to increase the security (vsftpd will use a custom PAM auth file, which won’t lookup in /etc/passwd files – for this reason, any local user attempts to login will fail)
  • Virtual users usernames and credentials will be stored in a file
  • There is a workaround in place to avoid some common issues like “500 OOPS: Vsftpd: Refusing to Run With Writable Root Inside Chroot ()” – FYI, allow_writeable_chroot=yes does NOT work on vsftpd version 2.3.5.

Install required packets:

apt-get install vsftpd apache2-utils libpam-pwdfile

Create SSL certificate:

openssl req -x509 -nodes -days 7300 -newkey rsa:2048 -keyout /etc/ssl/certs/vsftpd.pem -out /etc/ssl/certs/vsftpd.pem
chmod 600 /etc/ssl/certs/vsftpd.pem

Add a local user with limited access (like no console) that vsfpd will use to run virtual users:

useradd --home /home/vsftpd --gid nogroup -m --shell /bin/false vsftpd

Create directory structures for the virtual users:

mkdir -p /space/ftpusers/
chmod a-w /space/ftpusers/
mkdir -p /space/ftpusers/ftp01/rw
chmod a-w /space/ftpusers/ftp01
chown -R vsftpd:nogroup /space/ftpusers/ftp01

Please note that all new virtual users added need its home directory manually created as per above. Also, due to the chroot option and the current limitation on vsftpd, if you want a user to be able to write in its home directory, you need to create an extra folder. Its root home folder has to be -w. This is a workaround that works 🙂

Setup PAM authentication

Create a new file /etc/pam.d/vsftpd.virtual and add the following:

auth required pam_pwdfile.so pwdfile /etc/vsftpd/vsftpd.users
account required pam_permit.so

Now, let’s reorder a bit vsftp files in a directory:

mkdir -p /etc/vsftpd
cd /etc/
mv vsftpd.conf vsftpd
ln -s /etc/vsftpd/vsftpd.conf .

Add new users (password max 8 characters):

htpasswd -c -d -b /etc/vsftpd/vsftpd.users ftp01 ftp01password

Use the flag -c only the first time to create the file. If you re-use it, the file will be overwritten!
Also the -d flag is required because vsftpd is unable to read MD5 hashed password (default if -d is not used). The downside of this is a password limited to 8 characters.
Openssl could be used to produce a MD5 based BSD password with algorithm 1 using # openssl passwd -1 (not tested)

Let’s configure vsftpd

vi /etc/vsftpd.conf

# Main Settings
listen=YES
listen_port=21
connect_from_port_20=NO
ftpd_banner=Welcome to my FTP :-)
use_localtime=YES
force_dot_files=YES

# FTP Passive settings
pasv_enable=YES
pasv_min_port=1100
pasv_max_port=1150
pasv_addr_resolve=YES
pasv_enable=YES
pasv_addr_resolve=YES
pasv_address=<span style="color: #ff0000;"><EXTERNAL IP or DYN DNS></span>

# Virtual user settings
local_enable=YES
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
virtual_use_local_privs=YES
guest_enable=YES
guest_username=vsftpd
pam_service_name=vsftpd.virtual
user_sub_token=$USER
local_root=/space/ftpusers/$USER
hide_ids=YES

# Anonymous settings
anonymous_enable=NO
anon_upload_enable=NO
no_anon_password=NO
anon_other_write_enable=NO
anon_mkdir_write_enable=NO

# Write permissions
write_enable=YES
local_umask=022
async_abor_enable=YES

# SSL
ssl_enable=YES
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
ssl_ciphers=HIGH
rsa_cert_file=/etc/ssl/certs/vsftpd.pem

# Logging
xferlog_enable=YES
log_ftp_protocol=NO
syslog_enable=NO
vsftpd_log_file=/var/log/vsftpd.log

Now, on your router, make sure that the module ip_conntrack_ftp is loaded using lsmod command.
This is required for FTP PASSIVE mode to work.
I’ve realised that this can be called also nf_conntrack_ftp.
A good way to check all the alias associated to that netfilter module is using the following command:

# modinfo nf_conntrack_ftp
filename: /lib/modules/3.3.7/kernel/net/netfilter/nf_conntrack_ftp.ko
alias: nfct-helper-ftp
alias: <span style="color: #ff0000;">ip_conntrack_ftp</span>
description: ftp connection tracking helper
author: Rusty Russell <[email protected]>
license: GPL
depends: nf_conntrack
intree: Y
vermagic: 3.3.7 mod_unload MIPS32_R1 32BIT
parm: ports:array of ushort
parm: loose:bool

Also, make sure to setup a port forwarding like as below:

$IPT -t nat -A PREROUTING -p tcp -i $EXTIF -d $EXTIP --dport 21 -j DNAT --to $FTPIP:21 # FTP connection port
$IPT -t nat -A PREROUTING -d $EXTIP -p tcp -m tcp --dport 1100:1150 -j DNAT --to-destination $FTPI # FTP PASS ports
$IPT -A FORWARD -i $EXTIF -d $FTPI -p tcp --dport 21 -j ACCEPT
$IPT -A FORWARD -i $EXTIF -d $FTPI -p tcp --dport 1100:1150 -j ACCEPT