In this page, we will be installing the important steps that should be taken before using your Ubuntu Server in a production environment. This includes things like configuring security settings, creating backups, and optimizing performance. By following the guidelines outlined on this page, you can ensure that your Ubuntu Server is ready to handle the demands of a production environment and keep your data and applications secure. By the end of this page, you will have a solid understanding of what needs to be done to prepare your Ubuntu Server for production use. So, let's get started.
Set up SSH
sudo su
cd /etc/ssh
nano sshd_config
Locate the line that reads:
#PermitRootLogin prohibit-password
and modify it to:
PermitRootLogin yes
service sshd restart
If you are lazy then use the following command:
sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && sudo service sshd restart
Update the root password to use SSH with root
passwd
Update Ubuntu
sudo apt update
sudo apt full-upgrade
Upgrade Ubuntu to newest distro
sudo apt update
sudo apt-get upgrade -y
sudo apt-get dist-upgrade -y
sudo apt-get autoremove -y
sudo apt install update-manager-core
sudo do-release-upgrade -d
Install net-tools
sudo apt install net-tools -y
Set timezone
timedatectl list-timezones
sudo timedatectl set-timezone Europe/Amsterdam
timedatectl
Set NTP server (optional)
sudo nano /etc/systemd/timesyncd.conf
[Time]
NTP=YOUR.NTP.IP.HERE
FallbackNTP=ntp.ubuntu.com
sudo timedatectl set-ntp off
sudo timedatectl set-ntp on
systemctl status systemd-timesyncd
Set Static IP Address
Enable Cloud-init if you use:Cloud Environments: If you're using cloud infrastructure (AWS, Azure, Google Cloud, etc.), cloud-init can automate the initial configuration of instances, including setting static IPs.
Automated Configuration: It can handle more than just networking—like setting up users, SSH keys, and running initialization scripts, which can be beneficial for fully automating your server setup.
Consistency: Ensures that all instances are consistently configured according to predefined templates.
Disable Cloud-init if you use:
Bare-metal Servers: For physical servers or simple virtual machines where cloud-init features are not required, you can manually configure network settings. (set a static ip address)Minimal Configuration: If your setup is simple and doesn’t require the extensive initialization capabilities of cloud-init, you might opt to configure the static IP directly using traditional methods.
Disable cloud init
sudo mkdir -p /etc/cloud/cloud.cfg.d && echo "network: {config: disabled}" | sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
sudo rm -rf /etc/netplan/50-cloud-init.yaml && netplan apply
ip addr show NETWORKCARDNAME
Enable cloud-init
sudo rm -rf /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg && sudo reboot
Configure Static IP Address
ip a
sudo nano /etc/netplan/00-installer-config.yaml
network config below is to restore the defaults (disables static ip). Replace
ens33with your network card name
network:
version: 2
ethernets:
ens33:
dhcp4: true
dhcp6: true
Use network config below for static ip. Replace
ens33with your network card name
network:
version: 2
renderer: networkd # Uses systemd-networkd as the backend (standard for Ubuntu Server)
ethernets:
ens33: # The name of your physical network interface (check 'ip link' to find yours)
# Disable auto-configuration (DHCP) to ensure the IP never changes
dhcp4: no
dhcp6: no
accept-ra: no # Disable IPv6 Router Advertisements (we want full manual control)
addresses:
- "192.168.1.95/24" # Static IPv4 Address
- "2a02:f6e:c2ac:0:5a47:caff:fe76:9dd1/64" # Static IPv6 Address
nameservers:
addresses:
- 1.1.1.1 # Cloudflare DNS (IPv4)
- 1.0.0.1
- "2606:4700:4700::1111" # Cloudflare DNS (IPv6) - Recommended if using IPv6
- "2606:4700:4700::1001"
routes:
# IPv4 Default Gateway configuration
- to: default
via: 192.168.1.2
on-link: true # Forces the route to be accepted even if the gateway seems unreachable initially
# IPv6 Default Gateway configuration
# "::/0" is the IPv6 equivalent of "0.0.0.0/0" (The entire internet)
- to: "::/0"
via: "fe80::229a:7dff:fea6:116d" # The Link-Local address of your router (found via another device on the network)
on-link: true # CRITICAL: Required when the gateway is a Link-Local (fe80::) address
wakeonlan: true # Keeps the network card active for Wake-on-LAN packets
sudo chmod 600 /etc/netplan/00-installer-config.yaml
sudo netplan apply
Disable DHCP
nano /etc/dhcpcd.conf
denyinterfaces INSERTNETWORKCARDNAME
Wake-on-LAN WOL (optional)
Make sure you have Wake-on-LAN (WOL) enabled in your BIOS. This is because WoL is a hardware-level feature that must be enabled in the firmware before it can be utilized by the operating system.
- Install the ethtool utility by running the following command:
sudo apt install ethtool
- Check the current state of WOL for your network card:
sudo ethtool NETWORKCARDNAME
Replace NETWORKCARDNAME with the name of your network interface.
- Enable WOL for your network card:
sudo ethtool -s NETWORKCARDNAME wol g
Replace NETWORKCARDNAME with the name of your network interface.
- Configure the network card to start with WOL enabled after a reboot:
sudo nano /etc/netplan/00-installer-config.yaml
Add the following lines to the configuration file for your network interface:
wakeonlan: true
Example:
network:
version: 2
renderer: networkd # or NetworkManager
ethernets:
enp87s0:
dhcp4: false
dhcp6: false
addresses: [ "192.168.1.55/24" ]
nameservers:
# search: [sub.domain.tld, domain.tld]
addresses: [1.1.1.1, 1.0.0.1]
routes:
- to: default # or 0.0.0.0/0
via: 192.168.1.1
on-link: true
wakeonlan: true
- Apply the changes:
sudo netplan apply
Automaticly run Wake-on-LAN on start (optional)
sudo nano /etc/systemd/system/wol.service
[Unit]
Description=Enable Wake On Lan
[Service]
Type=oneshot
ExecStart = /sbin/ethtool --change NETWORKCARDNAME wol g
[Install]
WantedBy=basic.target
Replace NETWORKCARDNAME with the name of your network interface.
Fix LVM
sudo lvm
lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
exit
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
Oh My Zsh
sudo apt update
sudo apt install -y zsh
sudo apt install -y powerline fonts-powerline
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Y
But why?
Improved productivity: Oh My Zsh provides many useful commands and aliases to help you navigate and use the command line more efficiently.
Customization: Oh My Zsh allows you to customize your command line interface with various themes, plugins and settings.
Better organization: Oh My Zsh organizes your command line environment with sensible defaults and conventions, making it easier to manage your files and directories.
Improved security: Oh My Zsh includes a number of security features, such as password protection for sensitive files and directories.
Autocompletion: Oh My Zsh provides autocompletion for a wide range of tools and programming languages.
Syntax highlighting: Oh My Zsh provides syntax highlighting, making it easier to read and understand your command line input.
Improved error handling: Oh My Zsh can help you identify and correct errors more quickly and easily.
Better performance: Oh My Zsh is designed to be lightweight and fast, making it a good choice for users with limited system resources.
Community support: Oh My Zsh has a large and active community that provides support, troubleshooting and feature development.
Set Ram (optional)
Less chance of crash due to too little ram.
For 8GB RAM
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo nano /etc/fstab
/swapfile swap swap defaults 0 0
For 16GB RAM
sudo fallocate -l 16G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo nano /etc/fstab
/swapfile swap swap defaults 0 0
Usefull packages
Before getting packages, run sudo apt update
sudo apt update
sudo apt full-upgrade
Networking Utilities
sudo apt install net-tools -y
active/passive address reconnaissance
sudo apt install netdiscover -y
Disk Usage - advanced
sudo apt install ncdu -y
Disk Usage - basic
sudo apt install duf -y
System Info - fastfetch
sudo add-apt-repository ppa:zhangsongcui3371/fastfetch && sudo apt update && sudo apt install fastfetch
File Manager - vifm
sudo apt install vifm -y
LXD container
Please note that these steps are for Ubuntu 18.04 or later, for previous versions of Ubuntu the commands may differ.
- Install the LXD package:
sudo apt-add-repository ppa:ubuntu-lxc/lxd-stable
sudo apt-get update
sudo apt-get install lxd
- Initialize the LXD configuration:
sudo lxd init
-
Choose the storage pool you want to use, and configure it as necessary.
-
Create a new container:
sudo lxc launch ubuntu:18.04 mycontainer
- Start the container:
sudo lxc start mycontainer
Handy LXD container commands
- Connect to the container:
sudo lxc exec mycontainer bash
- To stop the container:
sudo lxc stop mycontainer
- To delete the container:
sudo lxc delete mycontainer
- List all the containers:
sudo lxc list
- Display detailed info about a container:
sudo lxc info
- List all the available images:
sudo image list
- export a container as an image.:
sudo lxc image export
GPU Passthrough on Linux and Docker
Check if you can see you're GPU
lshw -c video
qemu-guest-agent is optional if you are virtualizing this machine
sudo apt install qemu-guest-agent
build-essential is required for nvidia drivers to compile
sudo apt install build-essential
sudo apt install --no-install-recommends nvidia-cuda-toolkit nvidia-headless-535 nvidia-utils-535 libnvidia-encode-535
sudo apt install nvtop
run these commands only if you run Rancher/Kubernetes
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt update && sudo apt install -y nvidia-container-toolkit
sudo apt install nvidia-container-runtime
sudo apt install -y nvidia-docker2
N
reboot
If sudo apt update does not work visit this link: https://github.com/NVIDIA/nvidia-docker/issues/1626
To see the GPU UUID run this command
nvidia-smi --query-gpu=gpu_name,gpu_bus_id,vbios_version,uuid --format=csv
Kernel-based Virtual Machine (KVM)
- Check if your CPU supports hardware virtualization:
The command should return a non-zero value, indicating that your system supports hardware virtualization.
egrep -c '(vmx|svm)' /proc/cpuinfo
sudo kvm-ok
- Install the KVM and related packages:
sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils
- Add your user to the libvirtd group:
sudo adduser myusername kvm
-
Log out and log back in for the changes to take effect.
-
Verify that the installation was successful:
The command should return an empty list, indicating that no virtual machines are currently running.
virsh list --all
- To create a new virtual machine you can use the virt-install command, for example:
sudo virt-install --name=myVM --ram=1024 --vcpus=1 --disk path=/var/lib/libvirt/images/myVM.img,size=10 --cdrom /path/to/ubuntu.iso
Or you can install the GUI to create a new virtual machine
sudo apt install virt-manager
virt-manager
- To start the virtual machine use:
virsh start myVM
- To connect to the virtual machine use:
virsh console myVM
FusionPBX (Call Center)
FusionPBX - Ubuntu install
Install FusionPBX on Ubuntu 24.04 LTS. Higher versions are not support YET.
https://ubuntu.com/download/server#downloads
sudo su
wget -O - https://raw.githubusercontent.com/fusionpbx/fusionpbx-install.sh/master/ubuntu/pre-install.sh | sh;
Optional:
Before installing FusionPBX checkout the config file to make any changes for example the domain to use
cd /usr/src/fusionpbx-install.sh/ubuntu/resources/ && nano config.sh
cd /usr/src/fusionpbx-install.sh/ubuntu && ./install.sh
Before restarting the server note down the username password information that was displayed
reboot
FusionPBX - Debian install
Install FusionPBX on Debian 12 Higher versions are not support YET.
https://cdimage.debian.org/debian-cd/12.10.0/amd64/iso-dvd/debian-12.10.0-amd64-DVD-1.iso
sudo su
wget -O - https://raw.githubusercontent.com/fusionpbx/fusionpbx-install.sh/master/debian/pre-install.sh | sh;
Optional:
Before installing FusionPBX checkout the config file to make any changes for example the domain to use
cd /usr/src/fusionpbx-install.sh/debian/resources/ && nano config.sh
cd /usr/src/fusionpbx-install.sh/debian && ./install.sh
Before restarting the server note down the username password information that was displayed
reboot
Configure SIP Profile
SIP Profile configuration is typically not required for internal calls within the same network (e.g., FusionPBX and phones on 192.168.1.0/24). The default rtp-ip and sip-ip ($${local_ip_v4}, auto-detected as the FUSIONPBX_SERVER_IP) work for the internal profile.
Configure SIP Profiles only if:
- Phones are outside the local network (FusionPBX behind NAT).
- Using external gateways (e.g., for outbound calls) and FusionPBX is behind NAT.
- You experience issues like one-way audio, no audio, or call drops after 32 seconds.
otherwise skip this step and go to: ## Add SSL
For the external profile with NAT:
- Static Public IP: Set
external_rtp_ipandexternal_sip_iptoautonat:<public_ip>and forward SIP (5080) and RTP (16384-32768) ports. - Dynamic IP with UPnP: Set to
auto-nat, enable UPnP on your router, and remove-nonatfrom/etc/default/freeswitch.
See FusionPBX NAT Documentation for details.
If you experience call issues then follow the three steps below:
-
Go to: Advanced -> SIP Profiles
-
Open External:
rtp-ip $${local_ip_v4} (Replace this with the FusionPBX server IP)
sip-ip $${local_ip_v4} (Replace this with the FusionPBX server IP) -
Open Internal:
rtp-ip $${local_ip_v4} (Replace this with the FusionPBX server IP)
sip-ip $${local_ip_v4} (Replace this with the FusionPBX server IP)
Add SSL
cd /usr/src/fusionpbx-install.sh/ubuntu/resources && ./letsencrypt.sh
EXAMPLE
Domain Name: fpbx.arcadeparty.lan
Email Address: [email protected]
Create admin user
-
Go to Accounts > Users
-
Click on ADD
EXAMPLE
Username: pbxadmin
Password: P@ssWord!123
Confirm Password: P@ssWord!123
Email: [email protected]
Language: English - United States en-us
Time Zone: America/New_York
First Name: John
Last Name: Smith
Organization: arcadeparty
Groups: superadmin
Add Domain
-
Go to Advanced > Domains
-
Click on ADD
EXAMPLE
Name: fpbx.arcadeparty.lan
Description: Main domain
- Click on SAVE
Add Access Control
If configured INCORRECTLY it will result in
User has not been foundorUNALLOCATED_NUMBER
-
Go to Advanced > Access Controls
-
Open providers
For Nodes:
EXAMPLE
Type: allow
CIDR: 192.168.1.0/24
Description: VoIPin
- Click on SAVE
Add Gateway
-
Go to Accounts > Gateways
-
Click on ADD
EXAMPLE
Gateway: Primary GW
Username: 5596916644
Password: P@ssWord!123
From User:
From Domain:
Proxy: 64.136.174.30
Realm: 64.136.174.30
Expire Seconds: 800
Register: False
Retry Seconds: 30
Context: public
Profile: external
Description: primary gateway
Secondary gateway is optional
EXAMPLE
Gateway: Secondary GW
Username: 5596916644
Password: P@ssWord!123
From User:
From Domain:
Proxy: 64.136.173.22
Realm: 64.136.173.22
Expire Seconds: 800
Register: False
Retry Seconds: 30
Context: public
Profile: external
Description: Secondary gateway
Add IVR
-
Go to Applications > Recordings
-
Click on ADD and choose your WAV audio file
-
Click on UPLOAD
-
Go to Applications > IVR Menus
-
Click on ADD
EXAMPLE
Name: Generic IVR
Extension: 8000
Language: en-us callie
Greet Long: your WAV audio file
Greet Short:
Options:
Timeout: 3000
Exit Action: Hangup
Direct Dial: True
Ring Back:
Caller ID Name Prefix:
Context: fpbx.arcadeparty.lan
Description: generic ivr menu
Add Destination
-
Go to Dialplan > Destinations
-
Click on ADD
EXAMPLE
Type: Inbound
Country Code: country calling code. For example the Netherlands, 31 (without the + sign)
Destination: 5596916644
Caller ID Name:
Caller ID Number:
Context: Public
Conditions:
Actions: 8000 Generic IVR
User:
Group:
Caller ID Name Prefix:
Record:
Hold Music: your WAV audio file
Distinctive Ring:
Account Code:
Usage: Voice
Domain: fpbx.arcadeparty.lan
Order: 100
Description: DID01
Add Outbound Route
-
Go to Dialplan > Outbound Routes
-
Click on ADD
EXAMPLE
Gateway: Primary GW
Alternate 1: Secondary GW
Alternate 2: Tertiary GW
Dialplan Expression: your country region
Prefix: your country calling code
Limit:
Account Code:
Toll allow:
PIN Numbers: False
Order: 100
Enabled: True
Description: outbound route01
Add Extension
Import extension (faster)
-
Go to Accounts > Extensions
-
Click on IMPORT
-
For Data you can use the template below with your preferences
extension,password,effective_caller_id_name,effective_caller_id_number,outbound_caller_id_name,outbound_caller_id_number,hold_music,user_context,description,enabled
1000,1000,Dipper Pines,1000,arcadeparty,1234567890,default,192.168.1.126,"1000 ext",true
1001,1001,Mabel Pines,1001,arcadeparty,1234567890,default,192.168.1.126,"1001 ext",true
1002,1002,Wendy Corduroy,1002,arcadeparty,1234567890,default,192.168.1.126,"1002 ext",true
1003,1003,Stanley Pines,1003,arcadeparty,1234567890,default,192.168.1.126,"1003 ext",true
Add extension manually (slower)
-
Go to Accounts > Extensions
-
Click on ADD
EXAMPLE
Extension: 1000
Range: 1
Voicemail Password: 1000
Account Code:
Device Provisioning:
Effective Caller ID Name: Dipper Pines
Effective Caller ID Number: 1000
Outbound Caller ID Name: arcadeparty
Outbound Caller ID Number: 1234567890
Emergency Caller ID Name:
Emergency Caller ID Number:
Directory Full Name: Dipper Pines
Directory Visible: True
Directory Extension Visible: True
Max Registrations:
Limit Max: 5
Limit Destination:
Voicemail Enabled:
Voicemail Mail To :
Transcription Enabled: False
Voicemail File: Audio File Attachment
Voicemail Keep Local: True
Missed Call:
Toll Allow:
Call Timeout: 30
Call Group:
Call Screen: False
Record: Disabled
Hold Music: Default
Type: Default
Domain:
Context:
Description: ext 4000
Add custom bind action
-
Go to Dialplan > Dialplan Manager
-
In the searchbar, Search for bind
-
Select bind_digit_action
-
Click on COPY then click CONTINUE
-
Open the copy of bind_digit_action
EXAMPLE
Name: custom_bind_action
Number:
Hostname:
Context: global
Continue: True
Order: 085
Destination: False
Domain: Global
Enabled: True
Description: custom bind action
- On the second Data field below local paste the following:
local,*7,exec:execute_extension,park+7000 XML ${context},${bind_target},${bind_target}
-
Set Tag to Action
-
Set Type to bind_digit_action
-
Set Order to 52
Add custom park
-
Go to Dialplan > Dialplan Manager
-
In the searchbar, Search for park
-
for valet_park set it to False by clicking on True
-
Select valet_park_in and valet_park_out
-
Click on COPY then click CONTINUE
-
Open the copy of valet_park_in
EXAMPLE
Name: custom_park_in
Number: 7000
Hostname:
Context: global
Continue: False
Order: 470
Destination: False
Domain: Global
Enabled: True
Description: custom park in
- For destination_number under data paste the following:
^(park\+)?(7000)$
- For valet_park under data paste the following:
7000@${domain_name} auto in 7001 7099
-
for valet_announce_slot=disable under Enabled set it to False
-
Click on SAVE
-
Go to Dialplan > Dialplan Manager
-
In the searchbar, Search for park
-
Open the copy of valet_park_out
EXAMPLE
Name: custom_park_out
Number: 7001-7099
Hostname:
Context: global
Continue: False
Order: 475
Destination: False
Domain: Global
Enabled: True
Description: custom park out
- For destination_number under data paste the following:
^(?:park\+)?(70[0-9][0-9])$
- For valet_park under data paste the following:
7000@${domain_name} $1
- Click on SAVE
Add custom page
-
Go to Dialplan > Dialplan Manager
-
In the searchbar, Search for page
-
Select page-extension
-
Click on COPY then click CONTINUE
-
Open the copy of page-extension
EXAMPLE
Name: custom-page-extension
Number: 8ext
Hostname:
Context:
Continue: False
Order: 250
Destination: False
Domain:
Enabled: True
Description: custom page extension
- For Destination_number under data paste the following:
^\8(\d{2,7})$
-
for pin_number= under Enabled set it to False
-
Click on SAVE
-
Go to Dialplan > Dialplan Manager
-
In the searchbar, Search for page
-
For page-extension set it to False by clicking on True
Troubleshooting
Always check the logs
sudo tail -f /var/log/freeswitch/freeswitch.log
User has not been found
Error code: UNALLOCATED_NUMBER or User has not been found
-
Go to Advanced > Access Controls
-
Open providers
-
Remove the node
Reset admin password
cd /etc/fusionpbx
mv config.conf config1.conf
cat config1.conf | grep password
Reset SSL
Errors like ERR_CONNECTION_REFUSED can be fixed by reverting all SSL changes to default
rm -rf /usr/local/sbin/dehydrated && rm -rf /usr/src/dehydrated && rm -rf /etc/dehydrated && rm -rf /usr/src/dns-01-manual && rm -rf /var/www/dehydrated && rm -rf /etc/nginx/sites-available/fusionpbx && touch /etc/nginx/sites-available/fusionpbx
nano /etc/nginx/sites-available/fusionpbx
Copy paste the following fusionpbx nginx config file:
server {
listen 127.0.0.1:80;
server_name 127.0.0.1;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
client_max_body_size 80M;
client_body_buffer_size 128k;
location / {
root /var/www/fusionpbx;
index index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/fusionpbx$fastcgi_script_name;
}
# Allow the upgrade routines to run longer than normal
location = /core/upgrade/index.php {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/fusionpbx$fastcgi_script_name;
fastcgi_read_timeout 15m;
}
# Disable viewing .htaccess & .htpassword & .db & .git
location ~ .htaccess {
deny all;
}
location ~ .htpassword {
deny all;
}
location ~^.+.(db)$ {
deny all;
}
location ~ /.git/ {
deny all;
}
}
server {
listen 80;
server_name fusionpbx;
#redirect letsencrypt to dehydrated
location ^~ /.well-known/acme-challenge {
default_type "text/plain";
auth_basic "off";
alias /var/www/dehydrated;
}
#rewrite rule - send to https with an exception for provisioning
if ($uri !~* ^.*(provision|xml_cdr).*$) {
rewrite ^(.*) https://$host$1 permanent;
break;
}
#REST api
if ($uri ~* ^.*/api/.*$) {
rewrite ^(.*)/api/(.*)$ $1/api/index.php?rewrite_uri=$2 last;
break;
}
#algo
rewrite "^.*/provision/algom([A-Fa-f0-9]{12})\.conf" /app/provision/?mac=$1&file=algom%7b%24mac%7d.conf last;
#mitel
rewrite "^.*/provision/MN_([A-Fa-f0-9]{12})\.cfg" /app/provision/index.php?mac=$1&file=MN_%7b%24mac%7d.cfg last;
rewrite "^.*/provision/MN_Generic.cfg" /app/provision/index.php?mac=08000f000000&file=MN_Generic.cfg last;
#grandstream
rewrite "^.*/provision/cfg([A-Fa-f0-9]{12})(\.(xml|cfg))?$" /app/provision/?mac=$1;
rewrite "^.*/provision/pb/([A-Fa-f0-9]{12})/phonebook\.xml$" /app/provision/?mac=$1&file=phonebook.xml;
#grandstream-wave softphone by ext because Android doesn't pass MAC.
rewrite "^.*/provision/([0-9]{5})/cfg([A-Fa-f0-9]{12}).xml$" /app/provision/?ext=$1;
#aastra
rewrite "^.*/provision/aastra.cfg$" /app/provision/?mac=$1&file=aastra.cfg;
#rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.(cfg))?$" /app/provision/?mac=$1 last;
#yealink
#rewrite "^.*/provision/(y[0-9]{12})(\.cfg|\.boot)?$" /app/provision/index.php?file=$1$2;
rewrite "^.*/provision/(y[0-9]{12})(\.cfg)?$" /app/provision/index.php?file=$1.cfg;
rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.(xml|cfg))?$" /app/provision/index.php?mac=$1 last;
#polycom
rewrite "^.*/provision/000000000000.cfg$" "/app/provision/?mac=$1&file={%24mac}.cfg";
#rewrite "^.*/provision/sip_330(\.(ld))$" /includes/firmware/sip_330.$2;
rewrite "^.*/provision/features.cfg$" /app/provision/?mac=$1&file=features.cfg;
rewrite "^.*/provision/([A-Fa-f0-9]{12})-sip.cfg$" /app/provision/?mac=$1&file=sip.cfg;
rewrite "^.*/provision/([A-Fa-f0-9]{12})-phone.cfg$" /app/provision/?mac=$1;
rewrite "^.*/provision/([A-Fa-f0-9]{12})-registration.cfg$" "/app/provision/?mac=$1&file={%24mac}-registration.cfg";
rewrite "^.*/provision/([A-Fa-f0-9]{12})-directory.xml$" "/app/provision/?mac=$1&file={%24mac}-directory.xml";
#cisco
rewrite "^.*/provision/file/(.*\.(xml|cfg))" /app/provision/?file=$1 last;
#Escene
rewrite "^.*/provision/([0-9]{1,11})_Extern.xml$" "/app/provision/?ext=$1&file={%24mac}_extern.xml" last;
rewrite "^.*/provision/([0-9]{1,11})_Phonebook.xml$" "/app/provision/?ext=$1&file={%24mac}_phonebook.xml" last;
#Vtech
rewrite "^.*/provision/VCS754_([A-Fa-f0-9]{12})\.cfg$" /app/provision/?mac=$1;
rewrite "^.*/provision/pb([A-Fa-f0-9-]{12,17})/directory\.xml$" /app/provision/?mac=$1&file=directory.xml;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
client_max_body_size 80M;
client_body_buffer_size 128k;
location / {
root /var/www/fusionpbx;
index index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/fusionpbx$fastcgi_script_name;
}
# Allow the upgrade routines to run longer than normal
location = /core/upgrade/index.php {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/fusionpbx$fastcgi_script_name;
fastcgi_read_timeout 15m;
}
# Disable viewing .htaccess & .htpassword & .db & .git
location ~ .htaccess {
deny all;
}
location ~ .htpassword {
deny all;
}
location ~^.+.(db)$ {
deny all;
}
location ~ /.git/ {
deny all;
}
}
server {
listen 443 ssl;
server_name fusionpbx;
ssl_certificate /etc/ssl/certs/nginx.crt;
ssl_certificate_key /etc/ssl/private/nginx.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!ADH:!MD5:!aNULL;
#ssl_dhparam
#redirect letsencrypt to dehydrated
location ^~ /.well-known/acme-challenge {
default_type "text/plain";
auth_basic "off";
alias /var/www/dehydrated;
}
#REST api
if ($uri ~* ^.*/api/.*$) {
rewrite ^(.*)/api/(.*)$ $1/api/index.php?rewrite_uri=$2 last;
break;
}
#message media
rewrite "^/app/messages/media/(.*)/(.*)" /app/messages/message_media.php?id=$1&action=download last;
#algo
rewrite "^.*/provision/algom([A-Fa-f0-9]{12})\.conf" /app/provision/?mac=$1&file=algom%7b%24mac%7d.conf last;
#mitel
rewrite "^.*/provision/MN_([A-Fa-f0-9]{12})\.cfg" /app/provision/index.php?mac=$1&file=MN_%7b%24mac%7d.cfg last;
rewrite "^.*/provision/MN_Generic.cfg" /app/provision/index.php?mac=08000f000000&file=MN_Generic.cfg last;
#grandstream
rewrite "^.*/provision/cfg([A-Fa-f0-9]{12})(\.(xml|cfg))?$" /app/provision/?mac=$1;
rewrite "^.*/provision/pb/([A-Fa-f0-9]{12})/phonebook\.xml$" /app/provision/?mac=$1&file=phonebook.xml;
#grandstream-wave softphone by ext because Android doesn't pass MAC.
rewrite "^.*/provision/([0-9]{5})/cfg([A-Fa-f0-9]{12}).xml$" /app/provision/?ext=$1;
#aastra
rewrite "^.*/provision/aastra.cfg$" /app/provision/?mac=$1&file=aastra.cfg;
#rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.(cfg))?$" /app/provision/?mac=$1 last;
#yealink
#rewrite "^.*/provision/(y[0-9]{12})(\.cfg|\.boot)?$" /app/provision/index.php?file=$1$2;
rewrite "^.*/provision/(y[0-9]{12})(\.cfg)?$" /app/provision/index.php?file=$1.cfg;
rewrite "^.*/provision/([A-Fa-f0-9]{12})(\.(xml|cfg))?$" /app/provision/index.php?mac=$1 last;
#polycom
rewrite "^.*/provision/000000000000.cfg$" "/app/provision/?mac=$1&file={%24mac}.cfg";
#rewrite "^.*/provision/sip_330(\.(ld))$" /includes/firmware/sip_330.$2;
rewrite "^.*/provision/features.cfg$" /app/provision/?mac=$1&file=features.cfg;
rewrite "^.*/provision/([A-Fa-f0-9]{12})-sip.cfg$" /app/provision/?mac=$1&file=sip.cfg;
rewrite "^.*/provision/([A-Fa-f0-9]{12})-phone.cfg$" /app/provision/?mac=$1;
rewrite "^.*/provision/([A-Fa-f0-9]{12})-registration.cfg$" "/app/provision/?mac=$1&file={%24mac}-registration.cfg";
rewrite "^.*/provision/([A-Fa-f0-9]{12})-directory.xml$" "/app/provision/?mac=$1&file={%24mac}-directory.xml";
#cisco
rewrite "^.*/provision/file/(.*\.(xml|cfg))" /app/provision/?file=$1 last;
#Escene
rewrite "^.*/provision/([0-9]{1,11})_Extern.xml$" "/app/provision/?ext=$1&file={%24mac}_extern.xml" last;
rewrite "^.*/provision/([0-9]{1,11})_Phonebook.xml$" "/app/provision/?ext=$1&file={%24mac}_phonebook.xml" last;
#Vtech
rewrite "^.*/provision/VCS754_([A-Fa-f0-9]{12})\.cfg$" /app/provision/?mac=$1;
rewrite "^.*/provision/pb([A-Fa-f0-9-]{12,17})/directory\.xml$" /app/provision/?mac=$1&file=directory.xml;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
client_max_body_size 80M;
client_body_buffer_size 128k;
location / {
root /var/www/fusionpbx;
index index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/fusionpbx$fastcgi_script_name;
}
# Allow the upgrade routines to run longer than normal
location = /core/upgrade/index.php {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/fusionpbx$fastcgi_script_name;
fastcgi_read_timeout 15m;
}
# Disable viewing .htaccess & .htpassword & .db & .git
location ~ .htaccess {
deny all;
}
location ~ .htpassword {
deny all;
}
location ~^.+.(db)$ {
deny all;
}
location ~ /.git/ {
deny all;
}
}
sudo systemctl restart nginx
Still not working? try install script (there should be no data loss when reinstalling)
cd /usr/src/fusionpbx-install.sh/ubuntu && ./install.sh
Connect a phone to FusionPBX
Android client - Linphone
-
Install Linephone:
https://play.google.com/store/apps/details?id=org.linphone&hl=en -
Add an account, select: Use a third party SIP account
-
Below is a example account that can be used if you followed the extension import then click on login
Username: 1000
Password: 1000
Domain: 192.168.1.126
Display Name: Dipper Pines
Transport: UDP
iOS client - Linphone
-
Install Linephone:
https://apps.apple.com/us/app/linphone/id360065638 -
click on Assistant and select: USE SIP ACCOUNT
-
Below is a example account that can be used if you followed the extension import then click on login
Username: 1003
Password: 1003
Domain: 192.168.1.126
Display Name: Stanley Pines
Transport: UDP
Why FusionPBX?
-
Open-source: FusionPBX is open-source software, which means it is free to use and can be modified to suit specific needs.
-
Scalable: FusionPBX can be used to build small PBX systems or large enterprise-level solutions, making it a versatile option for businesses of all sizes.
-
Feature-rich: FusionPBX provides a wide range of features, including call routing, voicemail, IVR, and call recording, as well as support for various telephony protocols such as SIP, IAX, and WebRTC.
-
Web-based interface: FusionPBX provides a web-based graphical user interface (GUI) that makes it easy to manage and configure the system, even for users with little or no technical knowledge.
-
Add-ons and Plugins: FusionPBX has an extensive set of add-ons and plugins which enables to add more features and capabilities to the PBX, such as call center features, faxing, conferencing, and others.
-
Easy to install and maintain: The installation process of FusionPBX is straightforward and well-documented, and the system is designed to be easy to maintain and update.
-
Cost-effective: Because FusionPBX is open-source and free to use, it can be a cost-effective option for businesses, organizations, and individuals who want to set up a feature-rich telephony system without the need for a proprietary, expensive solution.
-
Security: FusionPBX is built on top of FreeSWITCH and it has the same security features and practices, which is a robust and secure telephony platform.
-
Flexible: FusionPBX allows you to customize your system to your needs by providing a wide range of settings, options, and configurations.
-
Community Support: FusionPBX has a large and active community that provides support and shares knowledge, which can be a great help if you encounter any issues or have questions about the software.
Ansible
Install Ansible default
sudo apt-add-repository ppa:ansible/ansible
sudo apt update && sudo apt install ansible
cd /etc/ansible/
nano ansible.cfg
[defaults]
inventory=hosts
host_key_checking=false
sudo nano /etc/ansible/hosts
[master]
192.168.x.x # or hostname
[nodes]
192.168.x.x # or hostname
[master:vars]
ansible_ssh_user=master
ansible_ssh_pass=master
[nodes:vars]
ansible_ssh_user=myusername
ansible_ssh_pass=MysuporS3cretP@ass
Test the connection
ansible all -m ping
Configure Ansible
cd /etc/ansible/
mkdir playbooks && cd "$_"
nano apt-update.yml
- name: Perform apt update
hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
register: apt_update_result
- name: Display apt update result
debug:
var: apt_update_result
The following apt-update.yml is a example that will send a webhook message to discord
- name: Perform apt update
hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
register: apt_update_result
- name: Display apt update result
debug:
var: apt_update_result
- name: Get current timestamp
set_fact:
timestamp: "{{ ansible_date_time.iso8601 }}"
- name: Send message to Discord channel
community.general.discord:
webhook_id: "12345678901234567890"
webhook_token: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
username: Ansible
avatar_url: "https://i.imgflip.com/5o55va.png"
embeds:
- title: "APT Update Completed"
description: "At server: {{ inventory_hostname }}"
color: 0x0dc300
footer:
text: "Author: Ansible"
image:
url: "https://media.tenor.com/7kYaaqzfDG0AAAAd/yes-guy.gif"
timestamp: "{{ ansible_date_time.iso8601 }}"
when: apt_update_result.changed
ansible-playbook apt-update.yml
Install Ansible with python
Make sure you have python3 and pip installed
sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt install python3.10
sudo apt install python3-pip
python3 -m pip install --user ansible
python3 -m pip install --upgrade --user ansible
Configure Ansible with python
cd /home/myusername/
mkdir ansible && cd "$_"
nano ansible.cfg
[defaults]
inventory=hosts
host_key_checking=false
nano hosts
[master]
192.168.x.x # or hostname
[nodes]
192.168.x.x # or hostname
[master:vars]
ansible_ssh_user=master
ansible_ssh_pass=master
[nodes:vars]
ansible_ssh_user=myusername
ansible_ssh_pass=MysuporS3cretP@ass
Test the connection
ansible all -m ping
Terraform
sudo apt install unzip
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
Configure Terraform
This is a example container just so you can see how powerfull and easy terraform is
cd /home/myusername/terraform
mkdir homepage && cd "$_"
nano homepage.tf
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "3.0.2"
}
}
}
provider "docker" {}
resource "docker_container" "homepage" {
image = "ghcr.io/benphelps/homepage:latest"
name = "hpage"
ports {
internal = 3000
external = 8101
}
restart = "unless-stopped"
volumes {
container_path = "/app/config"
host_path = "/home/myusername/terraform/homepage/config"
}
volumes {
container_path = "/app/public/icons"
host_path = "/home/myusername/terraform/homepage/icons"
}
volumes {
container_path = "/app/public/images"
host_path = "/home/myusername/terraform/homepage/images"
}
volumes {
container_path = "/var/run/docker.sock"
host_path = "/var/run/docker.sock"
read_only = true
}
}
terraform init
terraform apply
Webmin
curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh
sh setup-repos.sh
Configure Webmin
Change port
Replace NEW_PORT_NUMBER with any port you like
sudo sed -i 's/^port=.*/port=NEW_PORT_NUMBER/' /etc/webmin/miniserv.conf && sudo systemctl restart webmin