How to Install and Configure FusionPBX

Start with a fresh install of Debian Linux. Then run the following commands as root to install Fusion PBX:

# apt update
# apt install libflite1 flite-dev
# wget -O - https://raw.githubusercontent.com/fusionpbx/fusionpbx-install.sh/master/debian/pre-install.sh | sh;
# cd /usr/src/fusionpbx-install.sh/debian && ./install.sh

Once the install finishes, make note of the password and reboot the system. Then log in as admin for the username and the password that you were just given. Once logged in, you can change the username and password if you’d like. Now let’s install an SSL certificate from Let’s Encrypt.

# cd /usr/src/fusionpbx-install.sh/debian/resources/
# ./letsencrypt.sh

It can take a couple of minutes for the TXT record to update so please be patient. Now let’s set up the flite text-to-speech module.

# cd /usr/src/freeswitch-1.10.11
# nano modules.conf

Uncomment the line,

asr_tts/mod_flite

(also make sure that you have mod_cepstral commented out as you can’t use flite and cepstral at the same time. Cepstral is licensed, albeit not very expensive – about 30 dollars per voice – and you can test with their TTS voices though the TTS engine will periodically insert nag messages.)

Now do a make on Freeswitch. This will see that you have enabled the mod_flite and it will download the flite package from http://files.freeswitch.org/downloads/libs (about 14 Megabytes).

Note that if you break the download then you must cd to /usr/local/src/freeswitch/libs and sudo rm -R flite-1.5.1-current* or similar to clean up the broken download and then run make again.

After the make then do a make install.

Once that has done (or perhaps you had already had that uncommented) then you must make sure that the module is autoloaded. To check this go to the runtime program path which is usually /usr/local/freeswitch) e.g.

# cd /usr/local/freeswitch/conf/autoload_configs

and edit the modules.conf.xml and again uncomment the mod_flite line so it is the only one uncommented,

  <!-- ASR /TTS -->
    <load module="mod_flite"/> <!-- -->
    <!-- <load module="mod_pocketsphinx"/> -->
    <!-- <load module="mod_cepstral"/> -->
    <!-- <load module="mod_tts_commandline"/> -->
    <!-- <load module="mod_rss"/> -->

now restart freeswitch. Your feature code text to speech should now work.

Truthfully though the Flite TTS is synthetic (e.g. the rms voice) and will never be as good as a human spoken voice but it does allow you to quickly setup what option codes to use and test your options before you get a human speaker to say a script.

Resource

No text-to-speech with Flite on Freeswitch/Blue.box IVR

How to install Virtualmin on a Raspberry pi 4

You can install Virtualmin in Raspberry Pi with just a simple modification on to the install script.

I have my Raspberry Pi 4 installed with Pi OS Bookworm and it is based on Debian Linux 12 using the install script.

What you need to do is

1. wget http://software.virtualmin.com/gpl/scripts/install.sh
2. sudo nano install.sh
3. Find the text “get_distro”
4. Add in os_type=”debian” after get_distro

get_distro
os_type=”debian”
log_debug “Operating system name: $os_real”
log_debug “Operating system version: $os_version”
log_debug “Operating system type: $os_type”
log_debug “Operating system major: $os_major_version”

What this does is, it will force the script to recognize the host as a debian operating type.

Execute the script … It should install without any issues.

Reference

https://forums.raspberrypi.com/viewtopic.php?t=254307

How to Use CloudFront to do WordPress Page Caching

Previously, we looked at WordPress page caching using a content delivery network (CDN). This is an essential tool for speeding up a WordPress site at a global scale. That said, it’s still not commonly used by a lot of WordPress hosts.

With Ymir, you get a CloudFront (Amazon’s CDN) distribution set up to do page caching on production environments by default. This is a great feature of the product. But what if you want to configure CloudFront to do page caching yourself?

Well, this isn’t talked a lot about. In my research, the only article I found was this one on an AWS blog. This article will use that article as a baseline, but will discuss in more detail how to set up CloudFront. Continue reading

Optimal Virtualmin Template Settings

Create a file in /etc/skel/public_html/index.html with the following:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Under Construction</title>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400" rel="stylesheet">
<style media="screen" type="text/css">
html {
height:100%;
}
body {
color: #fff; 
margin: 0;
font-family: "Montserrat", sans-serif;
font-style: normal;
font-size: 14px;
line-height: 22px;
height: 100%; 
background-color: #fff;
}
h1 {
margin-top: 20px;
font-size: 50px;
opacity: 1;
}
@media all and (max-width: 980px) {
h1 {
font-size: 35px;
}
.under-construction p {
font-size: 20px;
}
}
@media all and (max-width: 767px) {
h1 {
font-size: 28px;
}
.under-construction p {
font-size: 16px;
}
}
h2 {
font-style: normal;
font-size: 14px;
line-height: 22px;
margin: 0;
}
.wrap {
height: auto; 
min-height: 100%; 
background-color: #3B4251;
}
.domain {
position: absolute; 
text-align: center; 
width: 100%; 
margin-left: -50%; 
top: 42.5%;
left: 50%;
}

.footer {
text-align: center;
color:#DCDCDC; 
margin:auto;
padding:15px 20px 18px 20px;
position:relative;
clear:both;
height:40px;
margin-top:-73px;
background-color:#444;
font-size: 12px;
line-height: 22px;
}
p {
margin: 0;
}

.footer a {
color:#DCDCDC; 
}
p.description {
padding-top: 10px;
font-size: 18px;
}
.uh-logo {
margin: 20px;
max-width: 40px;
}
.under-construction {
position: absolute; 
text-align: center; 
width: 100%; 
bottom: 5%;
font-size: 24px;
line-height: 1; 
font-weight: 300;
}
img {
filter: brightness(0) invert(1);
}


</style>
</head>
<body>
<div class="wrap">
<a href="https://uniquehosting.net/"><img class="uh-logo" src="https://uniquehosting.net/wp-content/uploads/2024/06/cropped-Unique-Hosting-Logo-32x32.png" alt="uniquehosting.net logo"></a>
<div class="domain">
<h1 id="site_domain">mydomain.com</h1>
</div>
<div class="under-construction">
<p>We're just getting ready... Check back soon!</p>
</div>
</div>
<script>
document.getElementById("site_domain").innerHTML = window.location.hostname;
</script>
</body>
</html>

Go to System Settings -> Server Templates -> Default Settings -> Website for Domain and paste the above in the text field labeled ‘Disabled Website HTML’. Then check the box labeled ‘Redirect all HTTP requests to HTTPS’ and click on the ‘Save’ button.

Now go to System Settings -> Server Templates -> Default Settings -> PHP Options

In the section labeled ‘PHP configuration variables for scripts’, add the following:

memory_limit at least 128M
post_max_size at least 256M
upload_max_filesize at least 256M

How to Set Inotify Limit PERMANENTLY on a Synology Diskstation

Go to Control Panel -> Task Scheduler. Create a New Task -> Triggered Task -> User-defined script.

In General Settings tab: give it a name (e.g. “Syncthing Sysctl Inotify Fix”) and Event = Boot-up.

In the Task Settings tab: enter this in the Run Command box:

sh -c '(sleep 90 && echo 204800 > /proc/sys/fs/inotify/max_user_watches)&'

The sleep is to delay the setting to (hopefully) skip past any initialization that Synology does at boot time.

Click OK to close the task dialog, then enable the task and hit the Save button.

Reference

https://forum.syncthing.net/t/setting-inotify-limit-permanently-on-synology-diskstation/12221/3

How To Resize a Cloud Server File System

This guide explains how to expand the file system on a Vultr cloud server instance. If you have upgraded your cloud server to a plan with a larger disk or need to expand a partition while preserving data, follow these steps. A cloud server instance is sometimes called a Virtual Private Server or VPS.

This guide uses Ubuntu 20.04 as an example but applies to any Linux distribution with the fdisk and resize2fs tools. The example server has a 10 GB virtual disk with two partitions:

The virtual disk vda is 10 GB.

The first partition vda1 is 6 GB.

The second partition vda2 is 4 GB.

# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 252:0 0 10G 0 disk
├─vda1 252:1 0 6G 0 part /
└─vda2 252:2 0 4G 0 part

As an example, this guide will remove the second partition (vda2), then expand the first partition (vda1) to fill the virtual disk. This will preserve all data on vda1 and delete all data on vda2.
Use this example as a general guide for your particular situation. Continue reading

How to Install Nextcloud on a Synology the Easy Way

Begin by installing a package called “Container Manager”. This should have created a new folder in your drive volume called ‘docker’. Create a new folder within this folder called “nextcloud”. Then create 7 new folders inside the nextcloud folder called “config”, “db”, “custom_apps”, “themes”, “html”, “redis”, and “data”. Now right click on the nextcloud folder that you have just created and click Properties. Go to the Permission tab then click Advanced options. From the drop-down menu choose “Make inherited permissions explicit“. Select Everyone then click the Edit tab. Check all Read and Write Permissions and click on Done. After you click Done check “Apply to this folder, sub-folders and files“ then click on Save. Now open up the “Container Manager” package and click on “Project”. Name it “nextcloud” and select “/docker/nextcloud” for the project path. Choose “Create docker-compose.yml” for source and add the following:

version: '3.9'
services:
  mariadb:
    image: mariadb:latest
    container_name: Nextcloud-DB
    security_opt:
      - no-new-privileges:true
    user: 1026:100
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-read-only-compressed=OFF
    volumes:
      - ./db:/var/lib/mysql:rw
      - ./db:/etc/mysql/conf.d:rw
    environment:
      - MYSQL_ROOT_PASSWORD=[PASSWORD]
      - MYSQL_PASSWORD=[PASSWORD]
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - TZ=America/Los_Angeles
    restart: on-failure:5
      
  redis:
    image: redis:latest
    container_name: Nextcloud-REDIS
    hostname: nextcloudredis
    user: 1026:100
    healthcheck:
     test: ["CMD-SHELL", "redis-cli ping || exit 1"]
    volumes:
      - ./redis:/data:rw
    environment:
      TZ: America/Los_Angeles
    restart: on-failure:5
      
  nextcloud:
    image: nextcloud:latest
    container_name: Nextcloud
    ports:
      - 9333:80
    depends_on:
      mariadb:
       condition: service_started
      redis:
       condition: service_healthy
    environment:
      - REDIS_HOST=nextcloudredis
      - NEXTCLOUD_TRUSTED_DOMAINS=[DOMAIN] 10.0.1.11
      - TRUSTED_PROXIES=[DOMAIN] 10.0.1.11
      - OVERWRITEHOST=[DOMAIN]
      - OVERWRITEPROTOCOL=https
      - MYSQL_PASSWORD=[PASSWORD]
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=mariadb
    healthcheck:
     test: curl -f http://localhost:80/ || exit 1
    volumes:
      - ./html:/var/www/html:rw
      - ./custom_apps:/var/www/html/custom_apps:rw
      - ./config:/var/www/html/config:rw
      - ./data:/var/www/html/data:rw
      - ./themes:/var/www/html/themes:rw
    restart: on-failure:5
    
  cron:
   image: nextcloud:apache
   container_name: Nextcloud-CRON
   restart: always
   volumes:
     - ./config:/var/www/html/config:rw
     - ./html:/var/www/html:rw
     - ./custom_apps:/var/www/html/custom_apps:rw
     - ./data:/var/www/html/data:rw
   entrypoint: /cron.sh
   depends_on:
    mariadb:
       condition: service_started
    redis:
       condition: service_started

Replace [PASSWORD] with unique strong passwords and [DOMAIN] with your own domain name. Continue to build the project. Once completed, you should be able to access the Nextcloud UI by typing “https://[SYNOLOGY_IP]:9333” in your web browser. Go ahead and create an admin user. Once installed, you will be logged in. If you are using LDAP you can enable the “LDAP user and group backend” app and configure it with uid=root,cn=users,dc=[SUBDOMAIN],dc=[DOMAIN],dc=[DOMAINSUFFIX] for the User DN. Now we just need to create a reverse proxy so that we don’t have to access Nextcloud with an IP address and port number. This can be done by going to Control Panel -> Login Portal -> Advanced in your Synology and clicking on the “Reverse Proxy” button. Enter your domain name for source and the IP address of your Synology for the destination. Be sure to specify port 9333 for the destination. Last, there is a file that needs to be modified. This might be fixed in a future version, but for now open up the .htaccess file in the html folder and look for the following lines:

RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]

Change it to the following replacing [DOMAIN] with your own domain name:

RewriteRule ^\.well-known/carddav https://[DOMAIN]/remote.php/dav/ [R=301,L]
RewriteRule ^\.well-known/caldav https://[DOMAIN]/remote.php/dav/ [R=301,L]

Also, add the following line in the <IfModule mod_headers.c> section:

Header always set Strict-Transport-Security "max-age=15552000"

That’s it! Now you should be able to access Nextcloud with your domain name. If you need to run any commands as the web server user, go into Container Manager and click on ‘Container’, then right click on ‘Nextcloud’ and select ‘Open Terminal’. Then run the command like so:

# su - www-data -s /bin/bash -c 'php /var/www/html/occ db:add-missing-indices'

Reference

https://mariushosting.com/synology-how-to-install-nextcloud-using-docker/

How to create a 3-in-1 bootable usb drive on Linux

A usb drive with only 1 partition to load grub2 on usb-bootable machines with Legacy BIOS, 64bit UEFI or 32bit UEFI.

Note: due to the maximum size of a file inside an EFI system partition, files (such as ISO disk images) of 4 GiB or larger must be placed on another partition. That second partition can be of type ext4, for instance.

Partition the drive and install grub2

Warning: the usb drive will be formatted, save your data before proceeding!

First of all, on you current installation, check if the folder /usr/lib/grub/ exists and is not empty. If it is empty or does not exist, make sure the package grub-common (or equivalent for your distribution) version 2 or higher is installed. Depending on the system, /usr/lib/grub/ will contain one or more of the following folders: x86_64-efi, x86_64-efi-signed, i386-pc, i386-efi, …

The x86_64-efi, i386-pc and i386-efi folders need to be present in order to install the corresponding bootloader on the usb drive.

Install them using the package manager, for instance on Ubuntu :

sudo apt install grub-pc-bin grub-efi-ia32-bin grub-efi-amd64-bin

Now, find the device file for your usb drive. Here, the file is /dev/sdX. Replace X with the appropriate lower case letter(s) in the commands.

Make sure it’s the right drive! (check the capacity and the partitions) :

sudo fdisk -l /dev/sdX

Open fdisk :

sudo fdisk /dev/sdX

Press the following keys (THIS WILL ERASE ALL DATA FROM THE SELECTED DRIVE!) :

o <enter> # Create a new empty DOS partition table

n <enter> # Create a new partition

p <enter> # Select primary partition type

1 <enter> # Set partition number to 1

<enter> # Start partition at the first possible sector (default)

<enter> # Set partition end to the last possible sector (default)

Note: if fdisk (newer versions only) asks whether the partition signature should be deleted, then answer yes.

t <enter> # Change partition type

e f <enter> # Set partition type to EFI (FAT-12/16/32)

a <enter> # Enable the bootable flag on partition 1

w <enter> # Write the partition table

Create a fresh filesystem in the newly created partition :

sudo mkfs.fat -F32 /dev/sdX1

Mount the filesystem :

sudo mount -o umask=000 /dev/sdX1 /mnt

Write the MBR and install the grub files required for legacy BIOS boot on the drive :

sudo grub-install --no-floppy --boot-directory=/mnt/boot --target=i386-pc /dev/sdX

Install /EFI/BOOT/BOOTX64.EFI and other grub files required to load grub from a 64-bit UEFI firmware :

sudo grub-install --removable --boot-directory=/mnt/boot --efi-directory=/mnt --target=x86_64-efi /dev/sdX

Install /EFI/BOOT/BOOTIA32.EFI and other grub files required for 32-bit UEFI :

sudo grub-install --removable --boot-directory=/mnt/boot --efi-directory=/mnt --target=i386-efi /dev/sdX

Create a grub.cfg file :

touch /mnt/boot/grub/grub.cfg

Example grub.cfg with Xubuntu 22.04 Live

Notes :

  • Skip this part if you already have a working grub.cfg for the usb drive.
  • Other examples can be found in this repository’s grub.cfg file.
Create a folder for cd images :

mkdir /mnt/isos

Download an Ubuntu CD image (for example: Xubuntu 22.04 64-bit) :

Note: make sure there is enough space on the usb drive.

wget --directory-prefix=/mnt/isos http://cdimages.ubuntu.com/xubuntu/releases/jammy/release/xubuntu-22.04.3-desktop-amd64.iso

Edit grub.cfg :

nano /mnt/boot/grub/grub.cfg

Write or paste something like this :
menuentry 'Xubuntu 22.04 amd64' {
	#rmmod tpm #uncomment if grub version is >=2.04 in UEFI mode (see https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1851311)
	set isofile="/isos/xubuntu-22.04.3-desktop-amd64.iso"
	#search --set=root --file $isofile #uncomment if the bootloader and OS files are on different partitions
	loopback isoloop $isofile
	linux (isoloop)/casper/vmlinuz locale=fr_FR console-setup/layoutcode=fr boot=casper iso-scan/filename=$isofile quiet --
	initrd (isoloop)/casper/initrd
}
Or something like this :
menuentry 'LMDE 6 Cinnamon 64bit (Live)' {
	set isofile="/isos/lmde-6-cinnamon-64bit.iso"
	loopback loop (hd0,1)$isofile
	linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile noprompt noeject
	initrd (loop)/casper/initrd.lz
}

Notes :

  • Remove or change the value of the locale parameter to set the language of the live system.
  • Remove or change the value of the console-setup/layoutcode parameter to change the keyboard layout.
Save grub.cfg (in nano) and exit :

CTRL+O

<enter>

CTRL+X

Finish

Unmount the filesystem :

sudo umount /mnt

Reference
https://github.com/ndeineko/grub2-bios-uefi-usb

Raspberry Pi PXE Boot – Network booting a Pi 4 without an SD card

Install Raspbian on an SD card and install needed tools

Let’s start configuring your client system for netboot. This is the Raspberry Pi that will eventually boot without a micro SD card installed.

  • Download PiOS Lite. For this tutorial I used the Bullseye release.
  • Copy the Bullseye image onto an SD card. I suggest using the PiOS Imager. Warning! This will overwrite data on the device specified. Triple check you are writing to the SD card and not your laptop drive!
  • Put the SD card in your client Raspberry Pi 4 and boot it. Using the lite version of raspbian give you a text console only. If you want a graphical console you can use the full version and it should work. I have not tested this workflow with the full version.
  • Log in via the console using the login you created with the Imager.
  • Connect your Raspberry Pi to the internet via an ethernet cable.
  • Update PiOS via apt-get and install the rpi-config program:

Continue reading

How to Backup IMAP Mailboxes and Nextcloud Calendars, Contacts, and Notes

To backup all IMAP mailboxes for a user account, first download Rick Sander’s IMAP tools and save them somewhere on your system. Next, create a cron job and have it execute the following command:

mkdir -p /tmp/IMAP_$(date +%Y-%m-%d) && /path/to/imapdump/imapdump.pl -S example.com:993/user/password -f /tmp/IMAP_$(date +%Y-%m-%d) && cd /tmp/IMAP_$(date +%Y-%m-%d) && zip -r /backup/path/user@example.com_$(date +'%m-%d-%Y').zip user@example.com && chown user:user /backup/path/user@example.com_$(date +'%m-%d-%Y').zip && rm -Rf /tmp/IMAP_$(date +%Y-%m-%d)/user@example.com && find /backup/path -type f -mtime +90 -delete

To backup Nextcloud calendars and contacts, create a cron job running as root and have it execute the following command:

wget --directory-prefix=/tmp/nc-backup --user=ncuser --password=ncpassword --timestamping https://example.com/remote.php/dav/calendars/k4hjd9n3-k3ns-9385-9k2n-l3kjs9fk4b9z/personal-1?export https://example.com/remote.php/dav/addressbooks/users/k4hjd9n3-k3ns-9385-9k2n-l3kjs9fk4b9z/contacts?export && mv /tmp/nc-backup/personal-1?export /backup/path/calendar_$(date +'%m-%d-%Y').ics && mv /tmp/nc-backup/contacts?export /backup/path/contacts_$(date +'%m-%d-%Y').vcf && find /backup/path -type f -mtime +90 -delete

For Notes, do the same thing as above but execute the following instead:

mkdir -p /tmp/nc-backup && cd /nextcloud/path/k4hjd9n3-k3ns-9385-9k2n-l3kjs9fk4b9z/files && zip -r /tmp/nc-backup/notes_$(date +'%m-%d-%Y').zip Notes && chown user:user /tmp/nc-backup/notes_$(date +'%m-%d-%Y').zip && mv /tmp/nc-backup/notes_$(date +'%m-%d-%Y').zip /backup/path