Making my own home LAMP server…cost free

We live in a day where everything is online. We are connected now more than ever. You can learn so much about someone online without even knowing or meeting them. It’s a scary trend but now with COViD-19 happening, even school and church is online as well.

Websites, which were before a hobby or something to show off to someone for fun, are the new digital resumes and portfolios, especially in the IT field. It’s the perfect place to showcase all of your skills, passions, and achievements. For the longest time, I had been meaning to build one but wanted to do it right. That means no That means building my own full-fledged web server. Why not learn some cool new skills while I was at it?

I had the hardware; an old i7 inherited from work. I also am cheap, so it had to be low overhead. From researching, the best alternative was creating an Apache server, and if I wanted a GOOD website that could support different plug-ins and features, I needed this:

Once that was done, I throw WordPress on there and boom I am done the server part. Where to start? I needed to pick my distro properly. I wanted something as minimalist as possible. Terminal-only would be cool, letting me really test my Linux skills. After much research and discovering how many Linux distros there are, I narrowed it down to Ubuntu Server, Ubuntu Desktop, Arch Linux, CentOS, or Mint. Here was my pros list:

Ubuntu Server-terminal only
-low overhead
Ubuntu Desktop-more applications
-more user-friendly
-better support
-GUI (also a con)
Mint-comes with Samba already
CentOS-most stable/reliable

I decided to go with Ubuntu Server. I like the built-in packages and support. I created a boot USB with the .iso and wiped the drive. Ran through the install without any issues. I also set it up on a laptop too so I could eventually just SSH into the server and work from anywhere.

What I learned is that terminal-only literally means terminal only. For example, on the laptop auto-connecting to my standard WPA2 Wifi was a HUGE pain in the butt. Here is what I had to do:

Connect to WPA Net from CLI

Sudo apt-get install wpasupplicant
Wpa_passphrase [SSID]>wpa.conf (then enter psk; it will be hashed in f)
#you can put psk before > but then it shows in cmd history
Wpa_supplicant –D[driver]-I[dev]-c[p2conf]-B
#no spaces after options. If unsure about driver use –h or wext
Dhclient –r && dhclient [if]
#make sure WLAN if is up, use iwconfig to check wifi devices
#you might need “sudo iwconfig [if] essid [SSID] to associate
#check wlan dev status with rfkill and unblock if necessary
#stop and disable NetworkManager
#if SSID is hidden, add scan_ssid = 1 to .conf
#to have net auto-connect at startup, edit /lib/systemd/service/wpa_supplicant.service or add AP info to netplan
Sudo cp /lib/systemd/system/wpa_supplicant.service /etc/systemd/system/wpa_supplicant.service
#change ExecStart -> ExecStart = /sbin/wpa_supplicant –u –s –c [p2wpa.conf] -I [if]
Sudo systemctl enable wpa_supplicant.service
#create /etc/systemd/system/dhclient.service and enable so it starts at boot (see other HowTo)
#for wpa_supplicant errs, try recompiling pkg/disabling eth

What about simply mounting a drive? Try this:

Create Persistant Mount

Sudo blkid /dev/[device]
#note UUID then add below to /etc/fstab
UUID = [UUID] [mnt_dp] ext4 defaults 0 0

Even DHCP wasn’t default….I had to create a unique service for that to start up automatically:

Create dhclient.service and Enable on Boot

#with this, dhclient will try to obtain IP from known nets upon boot
Sudo nano /etc/systemd/system/dhclient.service
#edit as follows:
[Unit] [Service] [Install]
Description = DHCP Client Type = simple WantedBy =
Before = ExecStart = /sbin/dhclient [if]
Sudo systemctl enable dhclient.service

But I was determined to do it all from scratch. And I learned a lot from it and all the problems that happened. Eventually I discovered Netplan and that made it easy. From installing it and editing one file, I could configure all my network settings. It was pretty amazing, this simple text file was more powerful than a lot of Windows network applications. Definitely worth checking out.

From there on, once I had my basic network set up, I could go to the next steps of securing everything. I went on my router and static-ed my server and my “server controller” laptop. The server was flawless so far, so I put on a bunch more services:

Install and Configure Samba

#install pkg samba; nmbd service will then start
#allow in firewall (ie. Ufw)
#backup conf f located /etc/samba/smb.conf
#run testparm to check for errors; if none, you see “Loaded services file OK”
#restart service after conf update
#create samba F share and set group ownership to sambashare
#create user and add to sambashare group
#add setgid (“sticky”, child files inherit parent permissions) and sticky bit
#add user to samba db and create samba pw with sudo smbpasswd –a [u]
#enable Samba user with sudo smbpasswd –e [u]
#add to /etc/samba/smb.conf
[name of share you will use when logging in]
Path = [F]
Browseable = yes/no (whether it’s listed in available shares)
Read only = yes/no
Force create mode = [permission octal #] (newly created f permissions)
Force directory mode = [octal #] (newly created dir permissions)
Valid users = [user/group] (@ prefixes group)
#restart service
#other parameters to add in smb.conf:
Comment, guest ok (can connect without pw), create mask (default file permissions)
#to support netbios (ie. Connecting with server name) put line netbios name = [name] after workgroup

Installing and Using OpenSSH

#install pkg openssh-server
#config is at /etc/ssh/sshd_config
#hardening: change TCP listening po, set up public key login:
Ssh-keygen –t rsa (creates keys in ~/.ssh/
Ssh-copy-id [u]@[rhost] (copies to remotehost in ~/.ssh/authorized_keys)
Sudo chmod 600 .ssh/authorized_keys (only authenticated users can access keys)
Ssh –p 2222 –2 –c blowfish [u]@[rh] (creates tunnel with v2 on po 2222
#add allowusers [u] to config to allow pw access
#if accessing PAN from outside, make sure po’s are forwarded
#”host*” in config sets def settings for all connections
#edit ./.ssh/config to present connection cmds

VNC Setup and Connecting

#need GUI on both machines for this to work; use xfce4 if needed
Sudo apt install tightvncserver
Vncserver (set pws)
#/home/*/.vnc/xstartup (conf f, uses display po 5901)
Vncserver –kill :1 (needed to edit conf)
#backup conf, then add below script to conf to make vncserver start up on Desktop:
#Xrdb $HOME/.Xresources
#Startxfce4 &
Sudo chmod +x ~/.vnc/startup (makes conf into .exe)
Vncserver (restart after conf changes)
#you can connect via vnc but it is not secure, so use ssh to forward rh vnc po traffic to lp, then connect to lp with VNC client
Ssh –L [lp]: –C –N –l [u] [rh]
#if you connect with VNCviewer, use [h]:[display#] and start vncserver

Configure PostFix Mail Server

#if po 25 on DG is not open, forward it on rtr to svr
Sudo DEBIAN_PRIORITY = low apt-get install postfix
#above cmd allows to configure more options
#configure; note:
#SystemMailName = Domain Name
#Root and Postmaster mail recipient – Linux user in From: field
#Other destinations to accept mail for = other DomainNames
#Local networks = default
#Lcaol address extension character = +
#Myhostname = [FQDN]
#Mydomain = [Domain Name]
Sudo postconf –e ‘home_mailbox = Maildir/ ‘ (creates mail F, do it in /home)
#set virtual_alias_maps table location, which maps emails to Linux accounts:
Sudo postconf –e ‘virtual_alias_maps = hash:/etc/postfix/virtual’
#conf /etc/postfix/virtual; [email_add] [uname]
Sudo postmap /etc/postfix/virtual (aplies email/uname mappings)
Sudo systemctl restart postfix (restart to apply changes)
Sudo ufw allow Postfix (update fw)
#update MAIL environmental variable:
Echo ‘export MAIL=~/Maildir ‘ | sudo tee –a /etc/bash.bashrc | sudo tee –a /etc/profile.d/
#you can then source variable into current session (/etc/profile.d/
Sudo apt-get install s-nail (mail client)
Sudo nano /etc/s-nail.rc (conf f, update as below)
#set emptystart (mail client opens even with empty Inbox)
#set folder = Maildir (assigns folder variable to mail F)
#set record = + sent (creates sent inbox f)
#send email to create mail F structure:
Echo ‘init’ | s-nail –s ‘init’ -Snorecord [recipient (eg. U)]
#confirm F is created
Cat [f.txt] | s-nail –s ‘[subject]’ -r [from field]
#ISPs block po 25 so outbound needs to be relayed via external server
#mx record on; make A record pointing to MX record
#may need to restart session for s-nail to detect mailbox

Configure Simple VPN

#make sure 1194/UDP is open and forwarded if necessary
Sudo apt install openvpn (on server)
Openvpn –genkey –secret [key_name].key
Sudo openvpn –dev tun –ifconfig -cipher AES-256-CBC –secret [key_location] & (starts svr)
#confrm new if and 1194/UDP listening
#install openvpn on client and copy over key
Sudo openvpn –remote [svr_name/IP] –dev tun –ifconfig (if IP/name) (d) –cipher AES-256-CBC –secret [p2key] & (starts VPN)
#test by pinging internal IP
#use tun ips to use VPN and killall to close conn
#you can use this without security by omitting cipher and secret
#you may need to update RP filtering, IP forwarding in /etc/sysctl.conf
#if unable to reach rh, you may need to configure static rt on h to find It’s way back to VPN
#NAT client traffic: iptables –t nat –A POSTROUTING –s [VPN nat] % -o [if] -j MASQUERADE

It was addicting. Once I put on a service or feature, there were other things I decided I wanted to do with the server. And performance was still flawless! No wonder so many people stick with Linux.

To make sure that I could access my server externally, I had to do some more work on the router. Using just the default ports is a big security hazard and could conflict with other devices and services in the LAN. I jumped back on the router and made some changes:

Now, I could connect with my own VPN or SSH from anywhere in the world with Internet. Plus my web and mail servers should now be accessible publicly.

The last thing to finish laying down the strong foundation was properly configuring the DNS. I went over to Freedns and registered and some useful subdomains to my account. I pointed the domains to my public IP and sure enough, when I browsed to the domain I could see my router. Foundation laid.

One issue I came across was a week later when it stopped forwarding to my public IP. After some troubleshooting, I realized my public IP had changed and from checking on my ISP’s website, I realized that our public IP was dynamic and could change on a moment’s notice. I definitely did not want to be logging onto Freedns regularly to update the IP. I researched options, and discovered DDNS. Checked my router and sure enough they supported it and my domain registrar!

Unfortunately, it never worked properly. Despite everything being filled out correctly, and saying that the test passed, it never updated properly. I tried putting the wrong IP in FreeDNS and it never updated it to the correct one. I never figured out that issue, because I discovered something better: the Cronjob. I read about it right on FreeDNS and used their instructions to set up a script to auto-update the DNS settings on FreeDNS once a week:

Finally, it was time to install the LAMP stack and WordPress. After doing some research and testing, I found some good articles and crafted my own instructions. In the end, this is what worked for me:

LAMP Server Setup

#install and configure Apache svr (see How To in below block)
Sudo apt instsall mysql-server
Sudo mysql_secure_installation
#make sure to change authtype; see (How To)
Sudo apt install php libapache2-mod-php php-mysql
#prioritize index.php by taking index.html out of wp folder
Sudo touch /var/www/html/phpinfo.php
#edit ‘phpinfo.php’ with “” so localhost/phpinfo.php shows info
Sudo touch /var/www/html/phpmysql.php
#edit ‘phpmysql.php’ to create page for testing mysql conn status #install and run tasksel for quick LAMP setup

Install WordPress

#find WP download link; after install, access via IP to configure
Wget [dl link] (download wp into tmp folder)
#unzip f
Sudo cp -r wordpress /var/www/html/ (or wherever you want to save it)
Sudo my sql
> create database wordpress;
> create user ‘[u]’@’hname’ identified by ‘[pw]’;
> grant all privileges on wordpress.* to ‘[u]’@'[hname]’ identified by ‘[pw]’;
> flush privileges; exit
#update URL in wp_options table
Sudo cp wp-config-sample.php wp-config.php (generate conf, within WP F)
#update db name, u, and pw lines in conf
#update DocumentRoot to wp F location in /etc/apache2/sites-available/000-default.conf
A2ensite 000-default.conf
Sudo systemctl restart apache2

Install and Configure Apache

Sudo apt install apache2 apache2-utils
#test with localhost, eth if
#update html in /var/www/html
#manage svc via sudo service apache2 (stop/start/restart/status)
#never edit /etc/apache2/sites-enabled; this is managed by Apache
#confugire virtual hosting in /etc/apache2/sites-available/000-default.conf
#update 000-default.conf lines ServerName, DocumentRoot
#configure DNS and enter info of public domain into virtual hosting conf
#update permissions (eg. 755) of html F
#update DirectoryIndex priority by putting highest 1st in /etc/apache2/mods-enabled/dir-conf
#update ports.conf to change listening po

It was pretty straightforward. I had some issues setting up the SQL database with the proper accounts and permissions, and had a few database errors but was able to work through it. I installed phpmyadmin as well. As fun as it was manually editing the database in SQL, practically phpmyadmin just made a lot more sense.

Install and Secure phpmyadmin

Sudo apt-get install –y phpmyadmin
#follow prompts, conf is here: /etc/apache2/conf-enabled/phpmyadmin.conf
#browse to http://server/phpmyadmin to access
#use .htaccess to secure if:
Sudo vim /etc/apache2/conf-available/phpmyadmin.conf
#add “AllowOverride ALL” below DirectoryIndex
#restart apache
Sudo vim /usr/share/phpmyadmin/.htaccess
#AuthType Basic
#AuthName “phpMyAdmin Users Only”
#AuthUserFile /etc/phpmyadmin/.htpasswd
#Require valid-user
Sudo apt-get install apache2-utils
Sudo htpasswd –c /etc/phpmyadmin/.htpasswd [phpmyadmin u]
#then enter pw; this creates u to access if, can create additional

I figured I might have multiple sites that I wanted to host from this server. I did some research and discovered nginx. Versatile, effective, and easy-to-use:

Configure Reverse Proxy Server

Sudo apt-get install nginx
#create proxy.conf in /etc/nginx/sites-enabled
#sample content:
Server {
listen [po];
Root [root_nginx_dir];
Index [index f if URL not listed];
Location / [proxy_pass “[dp/URL]”;}
Sudo nginx –t (checks conf for errors)
Sudo nginx –s reload
#parameters: server_name [FQDN] (points to proxy_pass localhost:%);
#use localhost:% for different apps, update hostnames in /etc/hosts

Time to test…big moment…browsed to

Success! Now on to setting up my website.