There could be many reasons, in my case it was node_exporter added incorrectly to shellcmd, that caused PfSense to stuck at boot at configuring firewall in the console view.

The correct node_exporter syntax for shell cmd is:

bash -c "nohup node_exporter >/dev/null 2>&1 &"

What is shellcmd?

Shellcmd is a system utility used to manage commands on a system startup.
You can install it by going to System -> Package manager -> Available Packages -> Shellcmd
Access is at Services -> Shellcmd

Find node_exporter package at: http://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/

At the time of writing this post: http://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/node_exporter-0.18.1.txz

SSH to PfSense

pkg add http://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/node_exporter-0.18.1.txz
rehash
service node_exporter onestart

EDIT:
How to start node_exporter in PfSense at boot:
https://s55ma.radioamater.si/2019/09/08/pfsense-stuck-at-boot-at-configuring-firewall/

What is node_exporter?
https://prometheus.io/docs/guides/node-exporter/

 

1. Login to the Proxmox webGUI, select desired node and click on disks. In my case, my new hard drive device is labeled as /dev/sdc.

2. Open Proxmox console and create disk partitions:

fdisk /dev/sdc

Create new partition: n
Select primary partition type: p
Leave the first and the last sectors default (press enter twice).
press w
Your new partition is now labeled the same as  the hard drive device with an added number 1 (/dev/sdc1).

3. Create physical volume:

pvcreate /dev/sdc1

4. Create volume group:

vgcreate Hitachi500G /dev/sdc1

You can name volume group whatever you want, I named mine Hitachi500G.

5. Go back to Proxmox webGUI
Select Datacenter -> Storage -> Add -> LVM

ID: custom name
Volume group: select the volume group you created in the step 4 and click Add.

Your new drive is now ready.

6. Create a shared directory on the proxmox host node (mount point)
Go to webGUI, click Datacenter -> Storage -> Add  Directory

ID: custom name
Directory: enter your mount point
Content: Disk image, Container
Click Add

You should now see your new directory mounted on the proxmox host. You can now share
this mount point with multiple LXC containers.

7. Select your LXC container and shut it down. While your LXC container is selected, go to Resources and click Add -> Mount point

Mount point ID: 0
Storage: Select storage you created in step 4
Disk size: You can define a custom size for any mount point
Path: This is the directory you created in step 6
Click Create

8. Start your container and check the new mount point.

References: https://www.hostfav.com/blog/index.php/2017/02/01/add-a-new-physical-hard-drive-to-proxmox-ve-4x-5x/

The problem:
apt-get dist-upgrade 
E: Failed to fetch https://enterprise.proxmox.com/debian/pve/dists/buster/InRelease 401 Unauthorized [IP: 66.70.154.81 443]
E: The repository ‘https://enterprise.proxmox.com/debian/pve buster InRelease’ is not signed.
N: Updating from such a repository can’t be done securely, and is therefore disabled by default.

Quick fix:
cd /etc/apt/sources.list.d/ 
cp pve-enterprise.list pve-no-subscription.list 
nano pve-enterprise.list

Comment out the first line and save:
#deb https://enterprise.proxmox.com/debian/pve buster pve-enterprise
nano pve-no-subscription.list

change deb https://enterprise.proxmox.com/debian/pve buster pve-enterprise
to deb http://download.proxmox.com/debian/pve buster pve-no-subscription

Upgrade should work now.

Reference: https://www.caretech.io/2018/06/08/how-to-update-proxmox-without-buying-a-subscription/

EDIT: Found a nicer way to do it: https://gist.github.com/whiskerz007/53c6aa5d624154bacbbc54880e1e3b2a
This script will not remove nagging popup with the newer versions of Proxmox, works up to 5.3.x version.

For a newer versions use this command:
 sed -i.bak "s/data.status !== 'Active'/false/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && systemctl restart pveproxy.service

Make sure to clear your cookies and cache for this method to work.

PfSense supports only outbound traffic shapping so you can’t shape multiple LAN/VLAN interfaces without putting another PfSense box in front of it. The only way to shape it is to use only one physical interface LAN and tag other VLANS on that interface. You need to select only WAN and LAN interface for traffic shaping. All traffic that will pass from VLANs will go trough LAN interface where QOS traffic shaper will catch it. If you don’t do it via only one interface, traffic shaping will work, but the VLAN to VLAN traffic will be limited to the speed of a WAN download bandwidth.

For start, you can use traffic shaping wizard and modify rules after.

Go to:

Firewall -> Traffic Shaper -> Wizards -> Multiple LAN/WAN

Select one WAN connection and one LAN connection:

For interface select LAN and WAN, scheduler should be HFSC (you can choose another one if you like, but this post is about HFSC setup).

Define your WAN upload and download speed and continue wizzard till the end and save.

Go to:

Firewall -> Traffic shaper

Click on LAN and set bandwidth to your physical interface speed.

Set qLink bandwidth percentage to: ((LAN bandwidth – WAN download bandwidth) / 10)

Example:

My LAN bandwidth = 1000 Mbit

My WAN download banwidth = 200 Mbit

(1000 – 200) / 10 = 80%

The sum of parent trees has to be 100%

Save.

All you have to do now is add two more floating rules. Rules added by the wizzard are good enough to get an idea how it works. You can later add custom ports, depends on what you need.

Go to:

Firewall -> Rules -> Floating

We will add a rule to catch all traffic that does not fall under defined floating rules created by the wizzard. We will put all not defined traffic to qOtherLow queue. The important thing is to have rules added at the top of the floating rules and not at the bottom.

 

Add rule 1:

Match, interface: WAN, direction: any, protocol: TCP, source: any, destination: any, destination port range: from any to any

Advanced options: Ackqueue / Queue: qACK / qOtherLow

 

Add rule 2: 

Match, interface: WAN, direction: any, protocol: UDP, source: any, destination: any, destination port range: from any to any

Advanced options: Ackqueue / Queue: none / qOtherLow

The two created rules have to be at the top:

Basic traffic shaping should work now. It’s up to you know to fine tune the rules. Check the status of traffic shaper at Status -> Queues

qLink queue is VLAN <-> VLAN traffic while all the queues bellow +/-qInternet are VLAN <-> WAN traffic

Downsides of this setup:

  • You are limited to only one physical interface for VLAN traffic meaning your VLAN to VLAN bandwidth can suffer with multiple heavy users on a local network (like transferring a lot of files from local servers to local clients). You could probably solve that with LAN bridges but I don’t know how a QOS would behave in that case.
  • You can’t run squid proxy service because download traffic on port 80 and 443 will bypass traffic shaper (it can probably be done with some tweaking but I haven’t tested it yet).

This is useful when you can’t use peer to peer (site to site) tunnel. For example, when you don’t have administrative access to a remote network (you can’t open ports, you can only go out – egress). To bypass this and gain access to remote network devices, you can simply install a VPN client on the remote network and make it act as a gateway for your local network. I will not go trough basic OpenVPN server configuration (generating certs, adding users etc), I will only pinpoint the parts that differ from a normal VPN client server setup.

Example:

Remote network: 192.168.10.0/24 (Client side)

Local network: 192.168.1.0/24 (Server side)

1. Go to OpenVPN server settings, under advanced configuration, custom options and enter:

 push "route 192.168.1.0 255.255.255.0";

route 192.168.10.0 255.255.255.0; 

2. Go to OpenVPN client specific overrides tab and add a new rule. Select your OpenVPN server, enter common name (name of the user – VPN client), under IPv4 remote network/s enter: 192.168.10.0/24

3. If you haven’t already, you have to assign an interface to your VPN server. Go to Interfaces, Assignments, Available network ports: ovpns1, click Add and save. Click on your newly created interface, check box Enable interface and add a description: OpenVPN1 (name it however you want), save.

4. Go to System, routing, static routes.

Add a new route, destination network: 192.168.10.0/24

Gateway: OpenVPN1

5. You need to enable NAT and forwarding on a client, this example is for a linux client:

 sysctl -w net.ipv4.ip_forward=1

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE 

6. Connect your VPN client, you should be able to access devices behind the client from your local network.

To connect via RTSP:

rtsp://camera_username:camera_password@IP:rtsp_port/live/ch00_1

Example:

rtsp://admin:admin123@192.168.30.102:554/live/ch00_1

If you are filtering outgoing connections, allow this outgoing ports to camera:

554 TCP

6970-6990 UDP

You can test RTSP stream with VLC media player.

Possible bug: When you connect to the camera with your phone, disconnect from it and then try to open rtsp stream in VLC media player, it will only load the first frame and stuck there. You need to reboot the camera, connect to rtsp with VLC media player without accessing it via mobile device.

Extra note: It’s advisable to block outgoing traffic from camera into internet. My camera is connecting to some IP with weird ports.

Quick whois showed me this IP belongs to alibaba.com. I did not sniff the traffic, so I’m not sure if the nature of it is spyware. It’s probably their cloud service or some other service.

For the extra paranoid, physically disconnect the microphone on the camera:

TL;DR:

Xerox phaser 3020 black ink percentage remaining – SNMP cacti data and graph template at the bottom of this post.

 

With some tweaks this method should also works for other brand printers.

With the help of this article: https://thwack.solarwinds.com/docs/DOC-171511 I could set up a cacti template for my Xerox 3020 printer. Some printers return ink level value in percents but in my case I got only the raw value.

1. Get SNMP toner max capacity value, OID for that is 1.3.6.1.2.1.43.11.1.1.8.1.1

root@cacti: snmpget -v2c -c public 192.168.0.251 1.3.6.1.2.1.43.11.1.1.8.1.1
SNMPv2-SMI::mib-2.43.11.1.1.8.1.1 = INTEGER: 700

700 is the raw value for 100% toner capacity.

2. Get SNMP toner current levels value, OID for that is 1.3.6.1.2.1.43.11.1.1.9.1.1

root@cacti: snmpget -v2c -c public 192.168.0.251 1.3.6.1.2.1.43.11.1.1.9.1.1
SNMPv2-SMI::mib-2.43.11.1.1.9.1.1 = INTEGER: 686

686 is the current raw value of my toner levels. To calculate toner ink percentage remaining we need to divide current raw value (686) with max raw value (700) and multiply it by 100. 686 / 700 * 100 = 98 (percentage of ink remaining). Since the max raw value is a nice number (700), we can just divide current raw value with 7, 686/7 = 98. We can use this formula for our CDEF definitions in cacti later. Remember, this is only for Xerox 3020, other brand printers can output different raw values and you need to correct this formula accordingly.

Xerox 3020 ink remaining percentage formula: raw_current_ink_level / 7

3. Login to cacti and go to Console -> Presets -> CDEFs

Click plus sign and create new CDEF and name it Xerox toner percentage

Click plus at CDEF Items.

CDEF Item Type: Special Data Source

CDEF Item Value: Current Graph Item Data Source

Click Save

Click plus at CDEF Items.

CDEF Item Type: Custom String

CDEF Item Value: 7 (this is the value cacti will use to divide raw data)

Click Save

Click plus at CDEF Items.

CDEF Item Type: Operator

CDEF Item Value: / (this will tell cacti to use a divide operation with the custom string we defined in a previous step).

Click Save

4. Go to Console -> Templates -> Data Source

Click plus to create new data source template and name it Printer – black toner current

Name: |host_description| – black toner current

Data Input Method: Get SNMP Data

Data Source Active: tick the right box

Internal Data Source Name: toner_current

Click Create

New Custom Data field will appear.

OID: 1.3.6.1.2.1.43.11.1.1.9.1.1

Click Save

5.1 Go to Console -> Templates -> Graph

Click plus sign

Name: Printer – black toner levels

Title: Printer – black toner levels

Vertical Label: percent

Tick Rigid Boundaries Mode

Upper Limit: 100

Click Create

5.2 Now click plus sign at Graph Template Items

Graph Item Type: AREA

Data Source: Printer – black toner current

Color: select what you like

Consolidation Function: AVERAGE

CDEF Function: Xerox toner percentage

Text Format: Available

Click save

Add another Graph template item

Graph Item Type: GPRINT

Data Source: Printer – black toner current

Consolidation Function: LAST

CDEF Function: Xerox toner percentage

GPRINT Type: Percent(Round down to the nearest decimal)

Text format: Current:

Click Save

Add another Graph template item

Graph Item Type: LINE1

Data Source: Printer – black toner current

Consolidation function: AVERAGE

CDEF function: Xeror toner percentage

Save

Your graph is now ready to device assignment.

Final result:

Download data and graph templates for xerox phaser 3020:

xerox_3020_cacti_toner_level_template

 

 

TL;DR:

  1. SSH login to QNAP
  2. Identify virtual switch you want to put into monitoring mode, in my case qvs1
  3. Set ageing to 0
brctl show
brctl setageing qvs1 0

My example:

I’ve created a virtual machine  (SecurityOnion) on my QNAP virtualization station to monitor my home network traffic. I have setup a port mirroring on my switch to send all traffic to the QNAP ethernet adapter number 2. (My QNAP has 4 ethernet adapters). Sniffing OS usually needs two ethernet adapters, one for management and one dedicated for monitoring (sniffing). I’ve created a new virtual switch in QNAP with adapter number 2 and set it to external mode (no IP address), then I assigned this virtual switch to monitoring interface in SecurityOnion. I should’ve been able to see all the traffic now, but that wasn’t the case. There were no packets flowing to my monitoring ethernet adapter. After some investigating I found out a reddit user had the same problem. This is the solution:

SSH into your QNAP with your admin username and credentials. Check your virtual switches with a command “brctl show“, this will list all virtual switches you created. Now you need to select the virtual switch you assigned to your sniffing ethernet adapter in my case, that was adapter number 2 and run the following command: “brctl setageing qvs1 0″, where qvs1 is the number of your selected virtual switch (one that will do the sniffing, in my case adapter 2, identified as qvs1). That’s it, you should see all packets on the sniffing interface now. Thanks go to the reddit user I don’t want to name due privacy concerns.

SecuritOnion is now receiving packets on the monitoring interface:

Side note: Sniffing and analyzing traffic is heavy on CPU, HDD and RAM resources. Qnap is not a suitable candidate for that. My Qnap tests showed a CPU bottleneck (quad core celeron N3160) averaging around 70% cpu usage with low network traffic and less than 20 devices on the network.

I wanted to limit upload speed of my torrent clients (utorrent, qbittorent) with port forwarding enabled. This can be done on the client itself but I prefer the method via firewall.

For this example I forwarded port 17123 to my qbittorent client and limited upload speed to 1mbit/s. There are probably other more “proper” methods to achieve this on Pfsense, but this is working for me:

Set up a port in a client:

Go to Pfsense, Firewall, traffic shaper, limiters:

Click New limiter

Tick Enable limiter and its children

Name it upload1mbit

Set Bandwidth to 1 Mbit/s

Set Mask to Source addresses and set Description to something you like and save.

For limiters to work you also need to make a download limiter. Click new limiter and name it download1000mbit

Set bandwidth to 1000 Mbit/s

Set mask to Destination addresses

Set description and click save.

Now go to firewall, NAT and add a new rule:

Interface: WAN

Protocol: Depends on your needs, usually TCP, UDP or both

Destination: WAN address

Destination port range: 17123 to 17123

Redirect target IP: LAN IP of the machine torrent client is running on, example 192.168.0.2

Redirect target port: 17123

Description: Torrents

Click Save

 

Now go to firewall, rules, WAN and find the associated rule we created in the previous step, click edit.

Scroll down to the bottom and click Display Advanced, scroll down again to find In / Out pipe.

For In select download1000mbit, and for out select upload1mbit, save and apply changes. This is the opposite of what you do when you want to limit LAN IP bandwidth, because this rule is applied to WAN interface not LAN. Click save and the limiter should work. You should always reset the states when applying new settings to filters. You can do that on Diagnostics, states, reset states.

I will add more images later, this is only a quick draft. It should be sufficient to set up a rule though.

#!/bin/bash

# Rtsp to youtube streaming with ffmpeg

VBR="1000k" # Bitrate of the output video, bandwidth 1000k = 1Mbit/s
QUAL="ultrafast" # Encoding speed
YOUTUBE_URL="rtmp://a.rtmp.youtube.com/live2" # RTMP youtube URL
THREADS="0" # Number of cores, insert 0 for ffmpeg to autoselect, more threads = more FPS

CAMUSER="user"
CAMPASS="password"
CAMIP="192.168.0.2"
CAMPORT="88"
VIDEOCHANNEL="videoSub" # videoMain and VideoSub for Foscam cameras

SOURCE="rtsp://${CAMUSER}:${CAMPASS}@${CAMIP}:${CAMPORT}/${VIDEOCHANNEL}" # Camera source
KEY="xxx-xxxx-xxxx-xxxx" # Youtube account key

# To download fonts
# wget -O /usr/local/share/fonts/open-sans.zip "https://www.fontsquirrel.com/fonts/download/open-sans";unzip open-sans.zip
FONT="/usr/local/share/fonts/OpenSans-Regular.ttf"
FONTSIZE="15"

# Text allingment
x="5"
y="60"

# Other
box="1" # enable box
boxcolor="black@0.5" # box background color with transparency factor
textfile="ffmpeg.txt"
reloadtext="1" # Reload textfile after each frame, usefull for overlaying changing data 
# like weather info. To update the textfile while streaming, you need to use mv command or a crash
# is going to happen when you update the textfile.
# Example:
# wget -q https://something.com/ -O - | grep somevalue > ffmpegraw.txt; mv ffmpegraw.txt ffmpeg.txt
boxborderwidth="5"

# Ffmpeg with drawtext, 
    ffmpeg -loglevel panic \
    -f lavfi -i anullsrc \
    -rtsp_transport tcp \
    -i "$SOURCE" \
    -vcodec libx264 -pix_fmt yuv420p -preset $QUAL -g 20 -b:v $VBR \
    -vf "drawtext="fontfile=${FONT}":textfile=${textfile}:x=${x}:y=${y}:reload=${reloadtext}: \
    fontcolor=white:fontsize=${FONTSIZE}:box=${box}:boxborderw=${boxborderwidth}:boxcolor=${boxcolor}" \
    -threads $THREADS -bufsize 512k \
    -f flv "$YOUTUBE_URL/$KEY"

# Copy stream only, don't encode
#ffmpeg \
#    -f lavfi -i anullsrc \
#    -rtsp_transport tcp \
#    -i "$SOURCE" \
#    -vcodec libx264 -pix_fmt yuv420p -preset $QUAL -g 20 -c:v copy -b:v $VBR \
#    -f flv "$YOUTUBE_URL/$KEY"

Overlayed data over webcam stream example:

To run the script in background you need to add nohup otherwise ffmpeg will hang.

nohup bash this_script.sh &

Ffmpeg likes to crash from time to time. Create a script to check for ffmpeg process and restart it if there is no process running.

#!/bin/bash
#
# Description: Checks for existing ffmpeg process and starts one if needed
#
script=/path/to/first_script.sh

if ! pgrep -x "ffmpeg" > /dev/null
then
    /bin/bash $script > /dev/null 2>&1 &
fi

Save script as check_ffmpeg.sh

chmod +x check_ffmpeg.sh

Run the script with crontab every minute.

crontab -e
* * * * * sudo bash /path_to_script/check_ffmpeg.sh

1. Make sure .well-known and acme-challenge directories are set permissions to 755

2. Create random file test.txt in .well-known/acme-challenge/ and try to view it with browser

If all of this is good, your certificate should renew. The problem I had on my server is that even when step 1. and 2. were ok and working, I still  got permission denied message. The problem was I setup my Varnish engine to force SSL on non SSL request. When bot requested http://somedomain.com/.well-known/acme-challenge/ it was automatically redirected to https://somedomain.com/.well-known/acme-challenge/. So,

3. Make sure you disable force SSL during renewal.

Error message example:

Failed authorization procedure. s55ma.radioamater.si (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://s55ma.radioamater.si/.well-known/acme-challenge/i825k_Mk8YGTTD1GOsZvMCkZ0KaRFdext04LfQdelQs: "<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<h1>Error 403 Forbidden</h1>
<p>Forb"

EDIT: I have experienced some lag with webm streaming, scroll down for swf configuration.

Live stream camera (Foscam in my case) over the internet cheat sheet:

apt-get install software-properties-common
add-apt-repository ppa:mc3man/trusty-media
apt-get update
apt-get install ffmpeg

Create ffserver.conf file

nano /etc/ffserver.conf
HTTPPort 8090 # Port to bind the server to
HTTPBindAddress 0.0.0.0
MaxHTTPConnections 2000
MaxClients 15
MaxBandwidth 50000 # Maximum bandwidth per client
 # set this high enough to exceed stream bitrate
CustomLog -

<Feed feed1.ffm>
 File /tmp/feed1.ffm
 FileMaxSize 1g
 ACL allow localhost
 ACL allow 192.168.0.0 192.168.0.255
</Feed>

<Stream live.webm>
 Format webm
 Feed feed1.ffm

 VideoCodec libvpx
 VideoSize 640x480
 VideoFrameRate 30
 VideoBitRate 512
 VideoBufferSize 512
 NoAudio
 AVOptionVideo flags +global_header
 StartSendOnKey

</Stream>

<Stream status.html> # Server status URL
 Format status
 # Only allow local people to get the status
 ACL allow localhost
 ACL allow 192.168.0.0 192.168.0.255
</Stream>

<Redirect index.html> # Just an URL redirect for index
 # Redirect index.html to the appropriate site
 URL live.webm/
</Redirect>

Save, exit and start the services

ffserver > /dev/null 2>&1 &
ffmpeg -loglevel error -r 30 -i rtsp://user:pass@camera_IP:port/url http://LAN_IP_WHERE_FFSERVER_IS_RUNNING:8090/feed1.ffm /dev/null 2>/var/log/ffmpeg.log &

Visit http://LAN_IP_WHERE_FFSERVER_IS_RUNNING:8090/live.webm
For status go to http://LAN_IP_WHERE_FFSERVER_IS_RUNNING:8090/status.html

I have experienced some lag with the above configuration, here is the config for a swf streaming:

HTTPPort 8090 # Port to bind the server to
HTTPBindAddress 0.0.0.0
MaxHTTPConnections 2000
MaxClients 15
MaxBandwidth 50000 # Maximum bandwidth per client
 # set this high enough to exceed stream bitrate
CustomLog -

<Feed feed1.ffm>
 File /tmp/feed1.ffm
 FileMaxSize 1g
 ACL allow localhost
 ACL allow 192.168.0.0 192.168.0.255
</Feed>

<Stream live.ffm>
 Feed feed1.ffm

Format swf
VideoCodec flv
VideoFrameRate 30
VideoBufferSize 80000
VideoBitRate 100
# quality ranges - 1-31 (1 = best, 31 = worst)
VideoQMin 1
VideoQMax 5
VideoSize 1024x786
PreRoll 0
Noaudio

</Stream>

<Stream status.html> # Server status URL
 Format status
 # Only allow local people to get the status
 ACL allow localhost
 ACL allow 192.168.0.0 192.168.0.255
</Stream>

<Redirect index.html> # Just an URL redirect for index
 # Redirect index.html to the appropriate site
 URL live.ffm/
</Redirect>

Save and restart ffserver and ffmpeg.

Edit your index.html file to play swf file in the browser:

<html>
<head>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<title>Site title</title>
<script type="text/javascript" src="swfobject.js"></script>
 <script type="text/javascript">
 swfobject.registerObject("myFlashContent", "9.0.0", "expressInstall.swf");
 </script>
 <script type="text/javascript">
 swfobject.embedSWF("http://FF_SERVER_IP:8090/live.ffm", "myContent", "1024", "786", "9.0.0");
 </script>
</head>
<body>
<p align="top">Some optional text.</p>
 <div id="myContent">
 <p>Live stream</p>
 </div>
</video>

</body>

The rpisystat script will report the following system parameters to your LCD:

  • Internal IP
  • External IP
  • CPU temperature
  • GPU temperature
  • CPU usage
  • Memory usage
  • Free disk space
  • Incoming and outgoing network traffic

You need:

1. Breadboard with T-Cobbler (or connect the wires directly)
2. 16×2 LCD board
3. Adjustable resistor (potentiometer) for adjusting LCD contrast

1. Wiring (source: https://learn.adafruit.com/drive-a-16×2-lcd-directly-with-a-raspberry-pi/wiring):

Pin #1 of the LCD goes to ground (black wire)
Pin #2 of the LCD goes to +5V (red wire)
Pin #3 (Vo) connects to the middle of the potentiometer (orange wire)
Pin #4 (RS) connects to the Cobbler #25 (yellow wire)
Pin #5 (RW) goes to ground (black wire)
Pin #6 (EN) connects to Cobbler #24 (green wire)
Skip LCD Pins #7, #8, #9 and #10
Pin #11 (D4) connects to cobbler #23 (blue wire)
Pin #12 (D5) connects to Cobbler #17 (violet wire)
Pin #13 (D6) connects to Cobber #21 (gray wire)
Pin #14 (D7) connects to Cobber #22 (white wire)
Pin #15 (LED +) goes to +5V (red wire)
Pin #16 (LED -) goes to ground (black wire)

raspberry_pi_pi-char-lcd

This schematics is for RaspberryPi 1 version, but you can connect to the same pins on RaspberryPi 2 (picture bellow).

16x2_lcd_display_rpi2

2. Software

Download required packages:

sudo apt-get update
sudo apt-get install python-dev python-setuptools python-pip git
sudo easy_install -U distribute
sudo pip install rpi.gpio

Download my scripts:

sudo git clone git://github.com/s55ma/16-2-LCD-rpisystat.git
cd 16-2-LCD-rpisystat
sudo ./rpisystat.py

Make sure you edit rpisystat.py to match your GPIO pins (default is for the wiring above). Also edit rx.sh and tx.sh to match your network adapter.

Check the display in action: https://www.youtube.com/watch?v=5YkLTBd5-bw

Scripts: https://github.com/s55ma/16-2-LCD-rpisystat

References: https://learn.adafruit.com/drive-a-16×2-lcd-directly-with-a-raspberry-pi/wiring

20151021_150632

Hardware:

  • RasberryPi 2
  • AM2302 humidity/temperature sensor
  • Some wires from old PCs to connect sensor with RaspberryPi

Software:

  • Raspbian OS
  • Nginx
  • Munin
  • WiringPi
  • Lol_dht22

1. Solder wires to the sensor like on the picture above, and connect them to the correct pins:

Pin 1 on the AM2302 to pin 1 (+3.3V) on the GPIO connector (labeled P1 on the raspi)
Pin 2 on the AM2302 to pin 7 (GPIO 4) on the GPIO connector
Pin 4 on the AM2302 to pin 9 (Ground) on the GPIO connector

For detailed instructions, check this blog up to step 4: https://hackaday.io/project/3766/instructions

All shell commands will be run as root, so I will not use sudo.

2. Install Nginx (web server)

apt-get update
apt-get install nginx php5-fpm

3. Install Munin

Muning is a monitoring tool for sysadmins. It creates graphs to monitor various parameters. We will configure munin to display AM2302 sensor in graphs.

apt-get install munin munin-node munin-plugins-extra

Edit munin configuration file:

pico /etc/munin/munin.conf
[server.name]
 address 127.0.0.1
 use_node_name yes

4. Configure Nginx virtual host. Dynazoom will work with this config.

pico /etc/nginx/sites-enabled/default or pico /etc/nginx/sites-enabled/your.domain.com
server {
        listen 443 ssl;
        ssl_certificate /etc/nginx/ssl/your.domain.com.crt;
        ssl_certificate_key /etc/nginx/ssl/your.domain.com.key;
        server_name your.domain.com;
        root "/var/cache/munin/www/";
        auth_basic            "Private access";
        auth_basic_user_file  /etc/munin/munin_htpasswd;

        location ^~ /munin-cgi/munin-cgi-graph/ {
                fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*);
                fastcgi_param PATH_INFO $fastcgi_path_info;
                fastcgi_pass unix:/var/run/munin/spawn-fcgi-munin-graph.sock;
                include fastcgi_params;
        }

        location /static/ {
                alias /etc/munin/static/;
        }
}

5. Generate SSL cert

mkdir /etc/nginx/ssl
openssl req -subj '/CN=your.domain.com' -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/your.domain.com.key -out /etc/nginx/ssl/your.domain.com.crt

6. Generate website password

apt-get install apache2-utils
htpasswd -c /etc/munin/munin_htpasswd admin

You will be promted to enter a new password.

7. Add common modules to munin

cd /usr/share/munin/plugins
wget -O pisense_ https://raw.github.com/perception101/pisense/master/pisense_
chmod a+x pisense_
ln -s /usr/share/munin/plugins/pisense_ /etc/munin/plugins/pisense_temp
ln -s /usr/share/munin/plugins/pisense_ /etc/munin/plugins/pisense_clock
pico /etc/munin/plugin-conf.d/munin-node
[pisense_*]
user root

8. Configure AM2302 prerequisites

apt-get install git-core
cd /opt/
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
cd /opt/
git clone https://github.com/technion/lol_dht22
cd lol_dht22
./configure
make

9. Create plugins for munin

pico /etc/munin/plugins/DHT22-humidity
#!/bin/sh

case $1 in
 config)
 cat <<'EOM'
graph_title Relative humidity
graph_vlabel Percent
graph_category AM2302
humidity.label RH
humidity.draw AREASTACK
humidity.colour 3E9BFB
EOM
 exit 0;;
esac

printf "humidity.value "
/opt/lol_dht22/loldht 7 | grep -i "humidity" | cut -d ' ' -f3
chmod +x /etc/munin/plugins/DHT22-humidity
pico /etc/munin/plugins/DHT22-temperature
#!/bin/sh

case $1 in
 config)
 cat <<'EOM'
graph_title Temperature
graph_vlabel Celsius
graph_category AM2302
temperature.label Celsius
temperature.label Temperature
temperature.draw AREASTACK
temperature.colour 00FF00
EOM
 exit 0;;
esac

printf "temperature.value "
/opt/lol_dht22/loldht 7 | grep -i "temperature" | cut -d ' ' -f7
chmod +x /etc/munin/plugins/DHT22-temperature
pico /etc/munin/plugin-conf.d/munin-node

Add this to the end of the file:

[DHT22-*]
user root

10. Enable Dynazoom for graphs

apt-get install spawn-fcgi libcgi-fast-perl
pico /etc/init.d/munin-fastcgi
#! /bin/sh

### BEGIN INIT INFO
# Provides: spawn-fcgi-munin-graph
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: starts FastCGI for Munin-Graph
### END INIT INFO
# --------------------------------------------------------------
# Munin-CGI-Graph Spawn-FCGI Startscript by Julien Schmidt
# eMail: munin-trac at julienschmidt.com
# www: http://www.julienschmidt.com
# --------------------------------------------------------------
# Install: 
# 1. Copy this file to /etc/init.d
# 2. Edit the variables below
# 3. run "update-rc.d spawn-fcgi-munin-graph defaults"
# --------------------------------------------------------------
# Special thanks for their help to:
# Frantisek Princ
# Jérôme Warnier
# --------------------------------------------------------------
# Last Update: 14. February 2013
#
# Please change the following variables:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=spawn-fcgi-munin-graph
PID_FILE=/var/run/munin/$NAME.pid
SOCK_FILE=/var/run/munin/$NAME.sock
SOCK_USER=www-data
FCGI_USER=www-data
FCGI_GROUP=www-data
FCGI_WORKERS=2
DAEMON=/usr/bin/spawn-fcgi
DAEMON_OPTS="-s $SOCK_FILE -F $FCGI_WORKERS -U $SOCK_USER -u $FCGI_USER -g $FCGI_GROUP -P $PID_FILE -- /usr/lib/munin/cgi/munin-cgi-graph"

# --------------------------------------------------------------
# No edits necessary beyond this line
# --------------------------------------------------------------

if [ ! -x $DAEMON ]; then
 echo "File not found or is not executable: $DAEMON!"
 exit 0
fi

status() {
 if [ ! -r $PID_FILE ]; then
 return 1
 fi
 
 for FCGI_PID in `cat $PID_FILE`; do 
 if [ -z "${FCGI_PID}" ]; then
 return 1
 fi
 
 FCGI_RUNNING=`ps -p ${FCGI_PID} | grep ${FCGI_PID}`
 if [ -z "${FCGI_RUNNING}" ]; then
 return 1
 fi
 done;
 
 return 0
}
 
start() {
 if status; then
 echo "FCGI is already running!"
 exit 1
 else
 $DAEMON $DAEMON_OPTS
 fi
}

stop () { 
 if ! status; then
 echo "No PID-file at $PID_FILE found or PID not valid. Maybe not running"
 exit 1
 fi
 
 # Kill processes
 for PID_RUNNING in `cat $PID_FILE`; do
 kill -9 $PID_RUNNING
 done
 
 # Remove PID-file
 rm -f $PID_FILE
 
 # Remove Sock-File
 rm -f $SOCK_FILE
}

case "$1" in
 start)
 echo "Starting $NAME: "
 start
 echo "... DONE"
 ;;

 stop)
 echo "Stopping $NAME: "
 stop
 echo "... DONE"
 ;;

 force-reload|restart)
 echo "Stopping $NAME: "
 stop
 echo "Starting $NAME: "
 start
 echo "... DONE"
 ;;
 
 status)
 if status; then
 echo "FCGI is RUNNING"
 else
 echo "FCGI is NOT RUNNING"
 fi
 ;;
 
 *)
 echo "Usage: $0 {start|stop|force-reload|restart|status}"
 exit 1
 ;;
esac

exit 0
chmod 755 /etc/init.d/munin-fastcgi
update-rc.d munin-fastcgi defaults
/etc/init.d/munin-fastcgi start

11. Restart daemons and visit your munin site

munin-node-configure

/etc/init.d/nginx restart

/etc/init.d/munin-node restart

Go to https://your.domain.com/munin/

 

Check how to add dewpoint graph on my next post.

References:

 

This is duplicate of my original post: https://troubleshoot-coltpython.blogspot.com/2015/05/ubuntu-nginx-php5-fpm-mariadb-varnish.html

This is my cheat sheet for future reference in case I forget. It’s composed from various blogs around the interwebz and modified to suit my needs. I thought someone might find this useful.
I won’t go into much details about config definitions, it’s cheat sheet after all 🙂

We’ll setup Varnish caching engine with Nginx. Nginx will also serve as reverse proxy for SSL (https) requests.

My working environment:

Ubuntu 14.04.2 LTS | Trusty
Nginx 1.4.6
PHP 5.5.9
Varnish: 4.0.3-2
MariaDB: 5.5.43

Important config sections are highlighted. You need to change this.

Varnish will listen on port 80 and forward requests to backend (Nginx) listening on port 8080.

We are doing this as root:

sudo -s

 

1. Install Varnish

 

apt-get install apt-transport-https

curl https://repo.varnish-cache.org/GPG-key.txt | apt-key add -

echo "deb https://repo.varnish-cache.org/ubuntu/ trusty varnish-4.0" &amp;amp;amp;gt;&amp;amp;amp;gt; /etc/apt/sources.list.d/varnish-cache.list

apt-get update

apt-get install varnish

 

2. Install Nginx + Naxsi

 

echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/nginx-stable.list

apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C

apt-get update

apt-get install nginx

apt-get install nginx-naxsi

apt-get install libpcre3-dev libssl-dev

 

3. Install PHP5-FPM

 

apt-get install php5-fpm

 

4. Install MariaDB server

 

apt-get install mariadb-server

 

5. Configure Nginx (I also use CloudFlare in front)


Generate certificates for SSL sessions:

mkdir -p /etc/nginx/ssl

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/domain.example.key -out /etc/nginx/ssl/domain.example.crt


Edit nginx.conf:

nano /etc/nginx/nginx.conf


user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
worker_connections 768;
multi_accept on;
use epoll;
}

http {

#Basic Settings

#Cloudflare real IP
set_real_ip_from 199.27.128.0/21;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
real_ip_header CF-Connecting-IP;

#Varnish get real IP
real_ip_header X-Forwarded-For;
set_real_ip_from 127.0.0.1;

#TCP and buffer settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 20;
client_max_body_size 15m;
client_body_timeout 60;
client_header_timeout 60;
#client_body_buffer_size 1K;
#client_header_buffer_size 1k;
#large_client_header_buffers 4 8k;
send_timeout 60;
reset_timedout_connection on;
types_hash_max_size 2048;
server_tokens off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

#Logging Settings

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

#Gzip Settings
gzip on;
gzip_disable “msie6”;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 512;
gzip_buffers 16 8k;
gzip_http_version 1.1;
#gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;


#Uncomment it if you installed nginx-naxsi
include /etc/nginx/naxsi_core.rules;

#Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

nano /etc/nginx/sites-enabled/example.domain.conf


server {
listen 127.0.0.1:8080;
server_name example.domain.com www.example.domain.com;
root “/home/example.domain/public_html”;

index index.php;
client_max_body_size 10m;

access_log /home/example.domain/_logs/access.log;
error_log /home/example.domain/_logs/error.log;

if ($http_user_agent ~* (Baiduspider|webalta|nikto|wkito|pikto|scan|acunetix|morfeus|webcollage|youdao) ) {
return 401;
}

if ($http_user_agent ~* (HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner) ) {
return 401;
}

location ~ /(\.|wp-config.php|readme.html|license.txt) {
return 404;
}

# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

location / {
include /etc/nginx/naxsi.rules;
try_files $uri $uri/ /index.php$uri?$args;
}

#Needed by Naxsi
location /RequestDenied {
return 403;
}

location ~ “^(.+\.php)($|/)” {
fastcgi_split_path_info ^(.+\.php)(.*)$;

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SERVER_NAME $host;

if ($uri !~ “^/uploads/”) {
fastcgi_pass unix:/var/run/example.domain_fpm.sock; #You can use TCP connection instead or single sock for all sites. You can define this (pools) in /etc/php5/fpm/pool.d/ 
}
include fastcgi_params;
}

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
access_log off;
}

location ~* \.(html|htm)$ {
expires 30m;
}

location ~* /\.(ht|git|svn) {
deny all;
}

#Add compression
gzip on;
gzip_comp_level 2;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/x-javascript text/xml text/css application/xml;

}

server {
listen 443 ssl;
server_name example.domain.com www.example.domain.com;
ssl_certificate /etc/nginx/ssl/example.domain.crt;
ssl_certificate_key /etc/nginx/ssl/example.domain.key;

location / {

## Pass the request on to Varnish.
location / {
proxy_pass http://127.0.0.1:80;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $host;
proxy_redirect off;
                }
         }
}

6. Configure naxsi for Nginx (Optimized for WordPress):

 

nano /etc/nginx/naxsi.rules


# Sample rules file for default vhost.

#LearningMode;
SecRulesEnabled;
#SecRulesDisabled;
DeniedUrl “/RequestDenied”;

## check rules
CheckRule “$SQL >= 8” BLOCK;
CheckRule “$RFI >= 8” BLOCK;
CheckRule “$TRAVERSAL >= 4” BLOCK;
CheckRule “$EVADE >= 4” BLOCK;
CheckRule “$XSS >= 8” BLOCK;

# WordPress naxsi rules

### HEADERS
BasicRule wl:1000,1001,1005,1007,1010,1011,1013,1100,1200,1308,1309,1310,1311,1315 “mz:$HEADERS_VAR:cookie”;
# xmlrpc
BasicRule wl:1402 “mz:$HEADERS_VAR:content-type”;

### simple BODY (POST)
BasicRule wl:1001,1015,1009,1311,1310,1101,1016 “mz:$URL:/|$BODY_VAR:customized”;
# comments
BasicRule wl:1000,1010,1011,1013,1015,1200,1310,1311 “mz:$BODY_VAR:post_title”;
BasicRule wl:1000 “mz:$BODY_VAR:original_publish”;
BasicRule wl:1000 “mz:$BODY_VAR:save”;
BasicRule wl:1008,1010,1011,1013,1015 “mz:$BODY_VAR:sk2_my_js_payload”;
BasicRule wl:1001,1009,1005,1016,1100,1310 “mz:$BODY_VAR:url”;
BasicRule wl:1009,1100 “mz:$BODY_VAR:referredby”;
BasicRule wl:1009,1100 “mz:$BODY_VAR:_wp_original_http_referer”;
BasicRule wl:1000,1001,1005,1008,1007,1009,1010,1011,1013,1015,1016,1100,1200,1302,1303,1310,1311,1315,1400 “mz:$BODY_VAR:comment”;
BasicRule wl:1100 “mz:$BODY_VAR:redirect_to”;
BasicRule wl:1000,1009,1315 “mz:$BODY_VAR:_wp_http_referer”;
BasicRule wl:1000 “mz:$BODY_VAR:action”;
BasicRule wl:1001,1013 “mz:$BODY_VAR:blogname”;
BasicRule wl:1015,1013 “mz:$BODY_VAR:blogdescription”;
BasicRule wl:1015 “mz:$BODY_VAR:date_format_custom”;
BasicRule wl:1015 “mz:$BODY_VAR:date_format”;
BasicRule wl:1015 “mz:$BODY_VAR:tax_input%5bpost_tag%5d”;
BasicRule wl:1015 “mz:$BODY_VAR:tax_input[post_tag]”;
BasicRule wl:1100 “mz:$BODY_VAR:siteurl”;
BasicRule wl:1100 “mz:$BODY_VAR:home”;
BasicRule wl:1000,1015 “mz:$BODY_VAR:submit”;
# news content matches pretty much everything
BasicRule wl:0 “mz:$BODY_VAR:content”;
BasicRule wl:1000 “mz:$BODY_VAR:delete_option”;
BasicRule wl:1000 “mz:$BODY_VAR:prowl-msg-message”;
BasicRule wl:1100 “mz:$BODY_VAR:_url”;
BasicRule wl:1001,1009 “mz:$BODY_VAR:c2c_text_replace%5btext_to_replace%5d”;
BasicRule wl:1200 “mz:$BODY_VAR:ppn_post_note”;
BasicRule wl:1100 “mz:$BODY_VAR:author”;
BasicRule wl:1001,1015 “mz:$BODY_VAR:excerpt”;
BasicRule wl:1015 “mz:$BODY_VAR:catslist”;
BasicRule wl:1005,1008,1009,1010,1011,1015,1315 “mz:$BODY_VAR:cookie”;
BasicRule wl:1101 “mz:$BODY_VAR:googleplus”;
BasicRule wl:1007 “mz:$BODY_VAR:name”;
BasicRule wl:1007 “mz:$BODY_VAR:action”;
BasicRule wl:1100 “mz:$BODY_VAR:attachment%5burl%5d”;
BasicRule wl:1100 “mz:$BODY_VAR:attachment_url”;
BasicRule wl:1001,1009,1100,1302,1303,1310,1311 “mz:$BODY_VAR:html”;
BasicRule wl:1015 “mz:$BODY_VAR:title”;
BasicRule wl:1001,1009,1015 “mz:$BODY_VAR:recaptcha_challenge_field”;
BasicRule wl:1011 “mz:$BODY_VAR:pwd”;
BasicRule wl:1000 “mz:$BODY_VAR:excerpt”;

### BODY|NAME
BasicRule wl:1000 “mz:$BODY_VAR:delete_option|NAME”;
BasicRule wl:1000 “mz:$BODY_VAR:from|NAME”;

### Simple ARGS (GET)
# WP login screen
BasicRule wl:1100 “mz:$ARGS_VAR:redirect_to”;
BasicRule wl:1000,1009 “mz:$ARGS_VAR:_wp_http_referer”;
BasicRule wl:1000 “mz:$ARGS_VAR:wp_http_referer”;
BasicRule wl:1000 “mz:$ARGS_VAR:action”;
BasicRule wl:1000 “mz:$ARGS_VAR:action2”;
# load and load[] GET variable
BasicRule wl:1000,1015 “mz:$ARGS_VAR:load”;
BasicRule wl:1000,1015 “mz:$ARGS_VAR:load[]”;
BasicRule wl:1015 “mz:$ARGS_VAR:q”;
BasicRule wl:1000,1015 “mz:$ARGS_VAR:load%5b%5d”;

### URL
BasicRule wl:1000 “mz:URL|$URL:/wp-admin/update-core.php”;
BasicRule wl:1000 “mz:URL|$URL:/wp-admin/update.php”;
# URL|BODY
BasicRule wl:1009,1100 “mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_http_referer”;
BasicRule wl:1016 “mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect”;
BasicRule wl:11 “mz:$URL:/xmlrpc.php|BODY”;
BasicRule wl:11 “mz:$URL:/wp-cron.php|BODY”;
BasicRule wl:2 “mz:$URL:/wp-admin/async-upload.php|BODY”;
# URL|BODY|NAME
BasicRule wl:1100 “mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_original_http_referer|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/user-edit.php|$BODY_VAR:from|NAME”;
BasicRule wl:1100 “mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:attachment%5burl%5d|NAME”;
BasicRule wl:1100 “mz:$URL:/wp-admin/post.php|$BODY_VAR:attachment_url|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/plugins.php|$BODY_VAR:verify-delete|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/post.php|$BODY_VAR:post_category[]|NAME”;
BasicRule wl:1311 “mz:$URL:/wp-admin/post.php|$BODY_VAR:post_category|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/post.php|$BODY_VAR:tax_input[post_tag]|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/post.php|$BODY_VAR:newtag[post_tag]|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/users.php|$BODY_VAR:users[]|NAME”;
# URL|ARGS|NAME
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/load-scripts.php|$ARGS_VAR:load[]|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/users.php|$ARGS_VAR:delete_count|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/users.php|$ARGS_VAR:update|NAME”;

# plain WP site
BasicRule wl:1000 “mz:URL|$URL:/wp-admin/update-core.php”;
BasicRule wl:1000 “mz:URL|$URL:/wp-admin/update.php”;
# URL|BODY
BasicRule wl:1009,1100 “mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_http_referer”;
BasicRule wl:1016 “mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect”;
BasicRule wl:11 “mz:$URL:/xmlrpc.php|BODY”;
BasicRule wl:11 “mz:$URL:/wp-cron.php|BODY”;
# URL|BODY|NAME
BasicRule wl:1100 “mz:$URL:/wp-admin/post.php|$BODY_VAR:_wp_original_http_referer|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/post.php|$BODY_VAR:metakeyselect|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/user-edit.php|$BODY_VAR:from|NAME”;
BasicRule wl:1100 “mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:attachment%5burl%5d|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:data[wp-auth-check]|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/admin-ajax.php|$BODY_VAR:data[wp-check-locked-posts][]|NAME”;
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/update-core.php|$BODY_VAR:checked[]|NAME”;
# URL|ARGS|NAME
BasicRule wl:1310,1311 “mz:$URL:/wp-admin/load-scripts.php|$ARGS_VAR:load[]|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/users.php|$ARGS_VAR:delete_count|NAME”;
BasicRule wl:1000 “mz:$URL:/wp-admin/users.php|$ARGS_VAR:update|NAME”;

### Plugins
#WP Minify
BasicRule wl:1015 “mz:$URL:/wp-content/plugins/bwp-minify/min/|$ARGS_VAR:f”;

7. Configure Varnish:

 

nano /etc/varnish/default


# Configuration file for varnish
#
# /etc/init.d/varnish expects the variables $DAEMON_OPTS, $NFILES and $MEMLOCK
# to be set from this shell script fragment.
#
# Note: If systemd is installed, this file is obsolete and ignored. You will
# need to copy /lib/systemd/system/varnish.service to /etc/systemd/system/ and
# edit that file.

# Should we start varnishd at boot? Set to “no” to disable.
START=yes

# Maximum number of open files (for ulimit -n)
NFILES=131072

# Maximum locked memory size (for ulimit -l)
# Used for locking the shared memory log in memory. If you increase log size,
# you need to increase this number as well
MEMLOCK=82000

# Default varnish instance name is the local nodename. Can be overridden with
# the -n switch, to have more instances on a single server.
# INSTANCE=$(uname -n)

# This file contains 4 alternatives, please use only one.

## Alternative 1, Minimal configuration, no VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# content server on localhost:8080. Use a 1GB fixed-size cache file.
#
# DAEMON_OPTS=”-a :6081 \
# -T localhost:6082 \
# -b localhost:8080 \
# -u varnish -g varnish \
# -S /etc/varnish/secret \
# -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G”


## Alternative 2, Configuration with VCL
#
# Listen on port 6081, administration on localhost:6082, and forward to
# one content server selected by the vcl file, based on the request.
# Use a 256MB memory based cache.
#
DAEMON_OPTS=”-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m”


## Alternative 3, Advanced configuration
#
# See varnishd(1) for more information.
#
# # Main configuration file. You probably want to change it 🙂
# VARNISH_VCL_CONF=/etc/varnish/default.vcl
#
# # Default address and port to bind to
# # Blank address means all IPv4 and IPv6 interfaces, otherwise specify
# # a host name, an IPv4 dotted quad, or an IPv6 address in brackets.
# VARNISH_LISTEN_ADDRESS=
# VARNISH_LISTEN_PORT=6081
#
# # Telnet admin interface listen address and port
# VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
# VARNISH_ADMIN_LISTEN_PORT=6082
#
# # The minimum number of worker threads to start
# VARNISH_MIN_THREADS=1
#
# # The Maximum number of worker threads to start
# VARNISH_MAX_THREADS=1000
#
# # Idle timeout for worker threads
# VARNISH_THREAD_TIMEOUT=120
#
# # Cache file location
# VARNISH_STORAGE_FILE=/var/lib/varnish/$INSTANCE/varnish_storage.bin
#
# # Cache file size: in bytes, optionally using k / M / G / T suffix,
# # or in percentage of available disk space using the % suffix.
# VARNISH_STORAGE_SIZE=1G
#
# # File containing administration secret
# VARNISH_SECRET_FILE=/etc/varnish/secret
#
# # Backend storage specification
# VARNISH_STORAGE=”file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}”
#
# # Default TTL used when the backend does not specify one
# VARNISH_TTL=120
#
# # DAEMON_OPTS is used by the init script. If you add or remove options, make
# # sure you update this section, too.
# DAEMON_OPTS=”-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
# -f ${VARNISH_VCL_CONF} \
# -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
# -t ${VARNISH_TTL} \
# -p thread_pool_min=${VARNISH_MIN_THREADS} \
# -p thread_pool_max=${VARNISH_MAX_THREADS} \
# -p thread_pool_timeout=${VARNISH_THREAD_TIMEOUT} \
# -S ${VARNISH_SECRET_FILE} \
# -s ${VARNISH_STORAGE}”
#


## Alternative 4, Do It Yourself
#
# DAEMON_OPTS=””

nano /etc/varnish/default.vcl


# Configuration file for varnish (optimized for WordPress)

vcl 4.0;

##########BACKEND##########
backend server1 {
.host = “127.0.0.1”;
.port = “8080”;
.connect_timeout = 600s;
.first_byte_timeout = 600s;
.between_bytes_timeout = 600s;
.max_connections = 800;
}

#Only allow purging from specific IPs
acl purge {
“localhost”;
“127.0.0.1”;
}

# This function is used when a request is send by a HTTP client (Browser)
##########START SUB VCL_RECV##########
sub vcl_recv {
#Normalize the header, remove the port (in case you’re testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, “:[0-9]+”, “”);

#Which pages to cache
if(!(req.http.host ~ “domain1.com“) &&
!(req.http.host ~ “domain2.com“) &&
!(req.http.host ~ “domain3.com“)) {
return (pass);
}

#FORCE SSL
if ( (req.http.host ~ “^(?i)domain1.com” || req.http.host ~ “^(?i)www.domain1.com“) && req.http.X-Forwarded-Proto !~ “(?i)https”) {
return (synth(751, “”));
}

if ( (req.http.host ~ “^(?i)domain2.com” || req.http.host ~ “^(?i)www.domain2.com“) && req.http.X-Forwarded-Proto !~ “(?i)https”) {
return (synth(750, “”));
}

if ( (req.http.host ~ “^(?i)domain3.com” || req.http.host ~ “^(?i)www.domain3.com“) && req.http.X-Forwarded-Proto !~ “(?i)https”) {
return (synth(752, “”));
}


#Set client IP to headers
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + “, ” + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}


#Allow purging from ACL
if (req.method == “PURGE”) {
#If not allowed then a error 405 is returned
if (!client.ip ~ purge) {
return(synth(405, “This IP is not allowed to send PURGE requests.”));
}
#If allowed, do a cache_lookup -> vlc_hit() or vlc_miss()
return (purge);
}

#Post requests will not be cached
if (req.http.Authorization || req.method == “POST”) {
return (pass);
}

#———-Wordpress specific configuration———-“

#Do not cache the RSS feed
if (req.url ~ “/feed”) {
return (pass);
}

#Blitz hack
if (req.url ~ “/mu-.*”) {
return (pass);
}


#Do not cache the admin and login pages
if (req.url ~ “/wp-(login|admin)”) {
return (pass);
}

#Do not cache the WooCommerce pages
### REMOVE IT IF YOU DO NOT USE WOOCOMMERCE ###
if (req.url ~ “/(cart|my-account|checkout|addons|/?add-to-cart=)”) {
return (pass);
}

#Remove the “has_js” cookie
set req.http.Cookie = regsuball(req.http.Cookie, “has_js=[^;]+(; )?”, “”);

#Remove any Google Analytics based cookies
set req.http.Cookie = regsuball(req.http.Cookie, “__utm.=[^;]+(; )?”, “”);

#Remove the Quant Capital cookies (added by some plugin, all __qca)
set req.http.Cookie = regsuball(req.http.Cookie, “__qc.=[^;]+(; )?”, “”);

#Remove the wp-settings-1 cookie
set req.http.Cookie = regsuball(req.http.Cookie, “wp-settings-1=[^;]+(; )?”, “”);

#Remove the wp-settings-time-1 cookie
set req.http.Cookie = regsuball(req.http.Cookie, “wp-settings-time-1=[^;]+(; )?”, “”);

#Remove the wp test cookie
set req.http.Cookie = regsuball(req.http.Cookie, “wordpress_test_cookie=[^;]+(; )?”, “”);

#Are there cookies left with only spaces or that are empty?
if (req.http.cookie ~ “^ *$”) {
unset req.http.cookie;
}

#Cache the following files extensions
if (req.url ~ “\.(css|js|png|gif|jp(e)?g|swf|ico)”) {
unset req.http.cookie;
}

#Normalize Accept-Encoding header and compression
if (req.http.Accept-Encoding) {
#Do not compress compressed files …
if (req.url ~ “\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$”) {
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ “gzip”) {
set req.http.Accept-Encoding = “gzip”;
} elsif (req.http.Accept-Encoding ~ “deflate”) {
set req.http.Accept-Encoding = “deflate”;
} else {
unset req.http.Accept-Encoding;
}
}

#Check the cookies for WordPress-specific items
if (req.http.Cookie ~ “wordpress_” || req.http.Cookie ~ “comment_”) {
return (pass);
}
if (!req.http.cookie) {
unset req.http.cookie;
}

#———-End of WordPress specific configuration———-#

#Do not cache HTTP authentication and HTTP Cookie
if (req.http.Authorization || req.http.Cookie) {
# Not cacheable by default
return (pass);
}

#Cache all others requests
return (hash);
}
#########END SUB_VCL_RECV##########

#PART OF FORCE SSL
sub vcl_synth {
if (resp.status == 751) {
set resp.status = 301;
set resp.http.Location = “https://domain1.com” + req.url;
return(deliver);
}

if (resp.status == 750) {
set resp.status = 301;
set resp.http.Location = “https://domain2.com” + req.url;
return(deliver);
}

if (resp.status == 752) {
set resp.status = 301;
set resp.http.Location = “https://domain3.com + req.url;
return(deliver);
}


}


sub vcl_pipe {
return (pipe);
}

sub vcl_pass {
return (fetch);
}

#The data on which the hashing will take place
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}

#Include the X-Forward-Proto header, since we want to treat HTTPS
# requests differently, and make sure this header is always passed
# properly to the backend server.
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}

#If the client supports compression, keep that in a different cache
if (req.http.Accept-Encoding) {
hash_data(req.http.Accept-Encoding);
}
return (lookup);
}

#This function is used when a request is sent by our backend (Nginx server)
##########START VCL_BACKEND_RESPONSE##########
sub vcl_backend_response {
#Remove some headers we never want to see
unset beresp.http.Server;
unset beresp.http.X-Powered-By;

#For static content strip all backend cookies
if (bereq.url ~ “\.(css|js|png|gif|jp(e?)g)|swf|ico”) {
unset beresp.http.cookie;
}

#Only allow cookies to be set if we’re in admin area
if (beresp.http.Set-Cookie && bereq.url !~ “^/wp-(login|admin)”) {
unset beresp.http.Set-Cookie;
}

#Do not cache response to posted requests or those with basic auth
if ( bereq.method == “POST” || bereq.http.Authorization ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}

#Do not cache search results
if ( bereq.url ~ “\?s=” ){
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}

#Only cache status ok
if ( beresp.status != 200 ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}

#A TTL of 24h
set beresp.ttl = 24h;
#Define the default grace period to serve cached content
set beresp.grace = 30s;

return (deliver);
}
##########END VCL_BACKEND_RESPONSE##########

##########START VCL_DELIVER##########
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = “cached”;
} else {
set resp.http.x-Cache = “uncached”;
}

#Remove some headers: PHP version
unset resp.http.X-Powered-By;

#Remove some headers: Apache\Nginx version & OS
unset resp.http.Server;

#Remove some headers: Varnish
unset resp.http.Via;
unset resp.http.X-Varnish;

return (deliver);
}
##########END VCL_DELIVER##########

sub vcl_init {
return (ok);
}

sub vcl_fini {
return (ok);
}

8. Set other config files:

 

nano /etc/php5/fpm/php.ini


[PHP]
display_errors = off
log_errors: on
max_input_time: 60
output_buffering: 4096
register_argc_argv: off
request_order: GP
session.bug_compat_42: off
session.bug_compat_warn: off
session.gc_divisor: 1000
session.hash_bits_per_character: 5
short_open_tag: off
variables_order: GPCS
engine = On
short_open_tag = Off
asp_tags = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 17
disable_functions=pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,
pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,system,exec,shell_exec,passthru,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,popen,pclose,phpinfo,eval
disable_classes =
ignore_user_abort = Off
zend.enable_gc = On
expose_php = Off
max_execution_time = 120
max_input_time = 60
memory_limit = 64M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On
variables_order = “GPCS”
request_order = “GP”
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 15M
auto_prepend_file =
auto_append_file =
default_mimetype = “text/html”
default_charset = “UTF-8”
doc_root =
user_dir =
enable_dl = Off
cgi.fix_pathinfo=1
file_uploads = On
upload_max_filesize = 15M
max_file_uploads = 20
allow_url_fopen = Off
allow_url_include = Off
default_socket_timeout = 30
[CLI Server]
cli_server.color = On
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = “%Y-%m-%d %H:%M:%S”
ibase.dateformat = “%Y-%m-%d”
ibase.timeformat = “%H:%M:%S”
[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = Off
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[bcmath]
bcmath.scale = 0
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 0
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.bug_compat_42 = Off
session.bug_compat_warn = Off
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = “a=href,area=href,frame=src,input=src,form=fakeentry”
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatibility_mode = Off
mssql.secure_connection = Off
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir=”/tmp”
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[ldap]
ldap.max_links = -1

nano /etc/php5/fpm/pool.d/domain.example.pool.conf


; Use this config only if you want to run separate php5-fpm process per user
; Pool name, the variable $pool can be used in any directive and will be replaced by the
; pool name (‘www’ here)
[user]

; Per pool prefix
; It only applies on the following directives:
; – ‘slowlog’
; – ‘listen’ (unixsocket)
; – ‘chroot’
; – ‘chdir’
; – ‘php_values’
; – ‘php_admin_values’
; When not set, the global prefix (or /usr) applies instead.
; Note: This directive can also be relative to the global prefix.
; Default Value: none
;prefix = /path/to/pools/$pool

; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; ‘ip.add.re.ss:port’ – to listen on a TCP socket to a specific address on
; a specific port;
; ‘port’ – to listen on a TCP socket to all addresses on a
; specific port;
; ‘/path/to/unix/socket’ – to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/example.domain_fpm.sock

; Set listen(2) backlog. A value of ‘-1’ means unlimited.
; Default Value: 128 (-1 on FreeBSD and OpenBSD)
;listen.backlog = -1

; List of ipv4 addresses of FastCGI clients which are allowed to connect.
; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
; must be separated by a comma. If this value is left blank, connections will be
; accepted from any ip address.
; Default Value: any
;listen.allowed_clients = 127.0.0.1

; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many
; BSD-derived systems allow connections regardless of permissions.
; Default Values: user and group are set as the running user
; mode is set to 0666
listen.owner = user
listen.group = user
listen.mode = 0660

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user’s group
; will be used.
user = user
group = user

; Choose how the process manager will control the number of child processes.
; Possible Values:
; static – a fixed number (pm.max_children) of child processes;
; dynamic – the number of child processes are set dynamically based on the
; following directives:
; pm.max_children – the maximum number of children that can
; be alive at the same time.
; pm.start_servers – the number of children created on startup.
; pm.min_spare_servers – the minimum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is less than this
; number then some children will be created.
; pm.max_spare_servers – the maximum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is greater than this
; number then some children will be killed.
; Note: This value is mandatory.
pm = dynamic

; The number of child processes to be created when pm is set to ‘static’ and the
; maximum number of child processes to be created when pm is set to ‘dynamic’.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI.
; Note: Used when pm is set to either ‘static’ or ‘dynamic’
; Note: This value is mandatory.
pm.max_children = 1

; The number of child processes created on startup.
; Note: Used only when pm is set to ‘dynamic’
; Default Value: min_spare_servers + (max_spare_servers – min_spare_servers) / 2
pm.start_servers = 1

; The desired minimum number of idle server processes.
; Note: Used only when pm is set to ‘dynamic’
; Note: Mandatory when pm is set to ‘dynamic’
pm.min_spare_servers = 1

; The desired maximum number of idle server processes.
; Note: Used only when pm is set to ‘dynamic’
; Note: Mandatory when pm is set to ‘dynamic’
pm.max_spare_servers = 1

; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For
; endless request processing specify ‘0’. Equivalent to PHP_FCGI_MAX_REQUESTS.
; Default Value: 0
pm.max_requests = 500

; The URI to view the FPM status page. If this value is not set, no URI will be
; recognized as a status page. By default, the status page shows the following
; information:
; accepted conn – the number of request accepted by the pool;
; pool – the name of the pool;
; process manager – static or dynamic;
; idle processes – the number of idle processes;
; active processes – the number of active processes;
; total processes – the number of idle + active processes.
; max children reached – number of times, the process limit has been reached,
; when pm tries to start more children (works only for
; pm ‘dynamic’)
; The values of ‘idle processes’, ‘active processes’ and ‘total processes’ are
; updated each second. The value of ‘accepted conn’ is updated in real time.
; Example output:
; accepted conn: 12073
; pool: www
; process manager: static
; idle processes: 35
; active processes: 65
; total processes: 100
; max children reached: 1
; By default the status page output is formatted as text/plain. Passing either
; ‘html’, ‘xml’ or ‘json’ as a query string will return the corresponding output
; syntax. Example:
; http://www.foo.bar/status
; http://www.foo.bar/status?json
; http://www.foo.bar/status?html
; http://www.foo.bar/status?xml
; Note: The value must start with a leading slash (/). The value can be
; anything, but it may not be a good idea to use the .php extension or it
; may conflict with a real PHP file.
; Default Value: not set
;pm.status_path = /status

; The ping URI to call the monitoring page of FPM. If this value is not set, no
; URI will be recognized as a ping page. This could be used to test from outside
; that FPM is alive and responding, or to
; – create a graph of FPM availability (rrd or such);
; – remove a server from a group if it is not responding (load balancing);
; – trigger alerts for the operating team (24/7).
; Note: The value must start with a leading slash (/). The value can be
; anything, but it may not be a good idea to use the .php extension or it
; may conflict with a real PHP file.
; Default Value: not set
;ping.path = /ping

; This directive may be used to customize the response of a ping request. The
; response is formatted as text/plain with a 200 response code.
; Default Value: pong
;ping.response = pong

; The access log file
; Default: not set
;access.log = log/$pool.access.log

; The access log format.
; The following syntax is allowed
; %%: the ‘%’ character
; %C: %CPU used by the request
; it can accept the following format:
; – %{user}C for user CPU only
; – %{system}C for system CPU only
; – %{total}C for user + system CPU (default)
; %d: time taken to serve the request
; it can accept the following format:
; – %{seconds}d (default)
; – %{miliseconds}d
; – %{mili}d
; – %{microseconds}d
; – %{micro}d
; %e: an environment variable (same as $_ENV or $_SERVER)
; it must be associated with embraces to specify the name of the env
; variable. Some exemples:
; – server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
; – HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
; %f: script filename
; %l: content-length of the request (for POST request only)
; %m: request method
; %M: peak of memory allocated by PHP
; it can accept the following format:
; – %{bytes}M (default)
; – %{kilobytes}M
; – %{kilo}M
; – %{megabytes}M
; – %{mega}M
; %n: pool name
; %o: ouput header
; it must be associated with embraces to specify the name of the header:
; – %{Content-Type}o
; – %{X-Powered-By}o
; – %{Transfert-Encoding}o
; – ….
; %p: PID of the child that serviced the request
; %P: PID of the parent of the child that serviced the request
; %q: the query string
; %Q: the ‘?’ character if query string exists
; %r: the request URI (without the query string, see %q and %Q)
; %R: remote IP address
; %s: status (response code)
; %t: server time the request was received
; it can accept a strftime(3) format:
; %d/%b/%Y:%H:%M:%S %z (default)
; %T: time the log has been written (the request has finished)
; it can accept a strftime(3) format:
; %d/%b/%Y:%H:%M:%S %z (default)
; %u: remote user
;
; Default: “%R – %u %t \”%m %r\” %s”
;access.format = %R – %u %t “%m %r%Q%q” %s %f %{mili}d %{kilo}M %C%%

; The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the ‘max_execution_time’ ini option
; does not stop script execution for some reason. A value of ‘0’ means ‘off’.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_terminate_timeout = 30s

; The timeout for serving a single request after which a PHP backtrace will be
; dumped to the ‘slowlog’ file. A value of ‘0s’ means ‘off’.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
;request_slowlog_timeout = 0

; The log file for slow requests
; Default Value: not set
; Note: slowlog is mandatory if request_slowlog_timeout is set
;slowlog = log/$pool.log.slow

; Set open file descriptor rlimit.
; Default Value: system defined value
;rlimit_files = 1024

; Set max core size rlimit.
; Possible Values: ‘unlimited’ or an integer greater or equal to 0
; Default Value: system defined value
;rlimit_core = 0

; Chroot to this directory at the start. This value must be defined as an
; absolute path. When this value is not set, chroot is not used.
; Note: you can prefix with ‘$prefix’ to chroot to the pool prefix or one
; of its subdirectories. If the pool prefix is not set, the global prefix
; will be used instead.
; Note: chrooting is a great security feature and should be used whenever
; possible. However, all PHP paths will be relative to the chroot
; (error_log, sessions.save_path, …).
; Default Value: not set
;chroot =

; Chdir to this directory at the start.
; Note: relative path can be used.
; Default Value: current directory or / when chroot
chdir = /

; Redirect worker stdout and stderr into main error log. If not set, stdout and
; stderr will be redirected to /dev/null according to FastCGI specs.
; Note: on highloaded environement, this can cause some delay in the page
; process time (several ms).
; Default Value: no
;catch_workers_output = yes

; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
; Default Value: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp

; Additional php.ini defines, specific to this pool of workers. These settings
; overwrite the values previously defined in the php.ini. The directives are the
; same as the PHP SAPI:
; php_value/php_flag – you can set classic ini defines which can
; be overwritten from PHP call ‘ini_set’.
; php_admin_value/php_admin_flag – these directives won’t be overwritten by
; PHP call ‘ini_set’
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.

; Defining ‘extension’ will load the corresponding shared extension from
; extension_dir. Defining ‘disable_functions’ or ‘disable_classes’ will not
; overwrite previously defined php.ini values, but will append the new value
; instead.

; Note: path INI options can be relative and will be expanded with the prefix
; (pool, global or /usr)

; Default Value: nothing is defined by default except the values in php.ini and
; specified at startup with the -d argument
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
;php_flag[display_errors] = off
;php_admin_value[error_log] = /var/log/fpm-php.www.log
;php_admin_flag[log_errors] = on
;php_admin_value[memory_limit] = 32M
php_admin_value[session.save_path] = “/home/user/_sessions”
php_admin_value[open_basedir] = “/home/user:/usr/share/pear:/usr/share/php:/tmp:/usr/local/lib/php”

php_flag[display_errors] = off
php_admin_value[error_reporting] = 0
php_admin_value[error_log] = /var/log/php5-fpm.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 128M

9. Add SSL to WordPress:


Go to your WordPress web folder, open file wp-config.php and add:

define(‘FORCE_SSL_ADMIN’, true);

define(‘FORCE_SSL_LOGIN’, true);

if ($_SERVER[‘HTTP_X_FORWARDED_PROTO’] == ‘https’)

$_SERVER[‘HTTPS’]=’on’;


Important! Add this before the line “require_once(ABSPATH . ‘wp-settings.php’);”, otherwise you’ll get “You do not have sufficient permissions to access this page” message when trying to login into admin (wp-admin).

10. Restart services

 

service nginx restart

service php5-fpm restart

service varnish restart

Duplicate of my original post: https://troubleshoot-coltpython.blogspot.com/2013/11/bash-script-domain-expiration-check.html

This script checks if domain has expired and also supports e-mail notice. 

Original script is from Matt (domain-check). I modifed already modified script from Vivek (http://www.cyberciti.biz/tips/domain-check-script.html).


List of changes:


– Added support for Slovenian (.si) domains.

– Added VAR for “mail from:”.
– Increased time between whois queries to 7 seconds (Slovenian whois only allows 10 queries per minute).
– Mail subject and mail data are translated to Slovene language.
– Changed default VAR path for mail (/bin/mail/ to /usr/bin/mail)

Get the script:

wget http://krejzi.si/files/domain-check;mv domain-check domain-check.sh;chmod +x domain-check.sh

Mirror: https://pastebin.com/pQe3RmDz


Usage:

Usage: ./domain-check.sh [ -e email ] [ -x expir_days ] [ -q ] [ -a ] [ -h ] {[ -d domain_namee ]} || { -f domainfile}

  -a                                   : Send a warning message through email
  -d domain                            : Domain to analyze (interactive mode)
  -e email address                     : Email address to send expiration notices
  -f domain file                       : File with a list of domains
  -h                                   : Print this screen
  -s whois server                      : Whois sever to query for information
  -q                                   : Don't print anything on the console
  -x days                              : Domain expiration interval (eg. if domain_date < days)


Check single domain:

./domain-check.sh -d domain.si


Check single domain and send e-mail notice if domain will expire in less than defined in WARNDAYS:

./domain-check.sh -a -d domain.si


You can also check multiple domains. Create a file domains.txt and add your domains like:


domain1.com

domain2.com
domain3.com

Check multiple domains:

./domain-check.sh -f domains.txt


Check multiple domains and send e-mail notice if any domain will expire in less than defined in WARNDAYS:

./domain-check.sh -a -f domains.txt


Set your own parameters from command line. Next command will check domains in domains.txt with expiration date less than 60 days and send e-mail notice to admin@domain.si

./domain-check.sh -a -f domains.txt -e admin@domain.si -x 60 


If you are going to use this script with cron, use -q option or change QUIET=”FALSE” to QUIET=”TRUE”

Let’s say we want to run this script every day at 4 AM. Open crontab with crontab -e (Ubuntu) and add the following line:

0 4 * * * /path/to/your/script/domain-check.sh -q -a -f /path/to/your/list/domains.txt

Duplicate of original post: https://troubleshoot-coltpython.blogspot.com/2013/11/phpsysinfo-loading-slow-on-raspberrypi.html

Default installation of PhpSysInfo on RaspberryPI takes a long time to load due some missing programs and hardware components.

My system info:


Hardware: RaspberryPI Model B with 512MB RAM

OS: Raspbian GNU/Linux 7

Nginx version: 1.2.1-2.2+wheezy1

PHP version: 5.4.4-14+deb7u5

PhpSysInfo version: 3.0.17-1

Enable debug mode in /etc/phpsysinfo/config.php

define('PSI_DEBUG', true);

Open http://yoursitephpsysinfo/xml.php

I found the following errors:

<Error Function="find_program(lsb_release)">

<![CDATA[

program not found on the machine ./xml.php on line 45 ./includes/output/class.WebpageXML.inc.php on line 138 in function run() ./includes/xml/class.XML.inc.php on line 456 in function getXml() ./includes/xml/class.XML.inc.php on line 435 in function _buildXml() ./includes/os/class.OS.inc.php on line 70 in function getSys() ./includes/os/class.Linux.inc.php on line 576 in function build() ./includes/os/class.Linux.inc.php on line 527 in function _distro() ./includes/class.CommonFunctions.inc.php on line 117 in function executeProgram( "lsb_release", "-a 2>/dev/null", "", true )

]]>

</Error>

<Error Function="/usr/bin/lspci">

<![CDATA[

pcilib: Cannot open /proc/bus/pci lspci: Cannot find any working access method. Return value: 1 ./xml.php on line 45 ./includes/output/class.WebpageXML.inc.php on line 138 in function run() ./includes/xml/class.XML.inc.php on line 456 in function getXml() ./includes/xml/class.XML.inc.php on line 435 in function _buildXml() ./includes/os/class.OS.inc.php on line 70 in function getSys() ./includes/os/class.Linux.inc.php on line 583 in function build() ./includes/os/class.Linux.inc.php on line 306 in function _pci() ./includes/class.Parser.inc.php on line 36 in function lspci() ./includes/class.CommonFunctions.inc.php on line 142 in function executeProgram( "lspci", "", "", true )

]]>

</Error>

<Error Function="find_program(lsscsi)">

<![CDATA[

program not found on the machine ./xml.php on line 45 ./includes/output/class.WebpageXML.inc.php on line 138 in function run() ./includes/xml/class.XML.inc.php on line 456 in function getXml() ./includes/xml/class.XML.inc.php on line 435 in function _buildXml() ./includes/os/class.OS.inc.php on line 70 in function getSys() ./includes/os/class.Linux.inc.php on line 585 in function build() ./includes/os/class.Linux.inc.php on line 367 in function _scsi() ./includes/class.CommonFunctions.inc.php on line 117 in function executeProgram( "lsscsi", "-c", "", true )

]]>

</Error>

<Error Function="file_exists(/proc/scsi/scsi)">

<![CDATA[

the file does not exist on your machine ./xml.php on line 45 ./includes/output/class.WebpageXML.inc.php on line 138 in function run() ./includes/xml/class.XML.inc.php on line 456 in function getXml() ./includes/xml/class.XML.inc.php on line 435 in function _buildXml() ./includes/os/class.OS.inc.php on line 70 in function getSys() ./includes/os/class.Linux.inc.php on line 585 in function build() ./includes/os/class.Linux.inc.php on line 367 in function _scsi() ./includes/class.CommonFunctions.inc.php on line 191 in function rfts( "/proc/scsi/scsi", "", 0, 4096, true )

]]>

</Error>

First, third and fourth error are because some programs are not present on the system, let’s install them.

sudo apt-get install lsb-release lsscsi -y

Second error is due missing PCI bus on raspberryPI.

# lspci

pcilib: Cannot open /proc/bus/pci

lspci: Cannot find any working access method.

We can’t do anything about that but disable that function in PhpSysInfo PHP code. Open the file/your/path/to/phpsyinfo/includes/class.Parser.inc.php and find the lspci function.

/**

     * parsing the output of lspci command

     *

     * @return Array

     */

    public static function lspci()

        {

        $arrResults = array();

        if (CommonFunctions::executeProgram("lspci", "", $strBuf, PSI_DEBUG)) {

            $arrLines = preg_split("/\n/", $strBuf, -1, PREG_SPLIT_NO_EMPTY);

            foreach ($arrLines as $strLine) {

                list($strAddr, $strName) = preg_split('/ /', trim($strLine), 2);

                $strName = preg_replace('/\(.*\)/', '', $strName);

                $dev = new HWDevice();

                $dev->setName($strName);

                $arrResults[] = $dev;

            }

        }

        return $arrResults;

    }

Change the code above to match the one bellow:

/**

     * parsing the output of lspci command

     *

     * @return Array

     */

    public static function lspci()

        {

        return array();

            $arrResults = array();

        if (CommonFunctions::executeProgram("lspci", "", $strBuf, PSI_DEBUG)) {

            $arrLines = preg_split("/\n/", $strBuf, -1, PREG_SPLIT_NO_EMPTY);

            foreach ($arrLines as $strLine) {

                list($strAddr, $strName) = preg_split('/ /', trim($strLine), 2);

                $strName = preg_replace('/\(.*\)/', '', $strName);

                $dev = new HWDevice();

                $dev->setName($strName);

                $arrResults[] = $dev;

            }

        }

        return $arrResults;

    }

Disable debug mode in phpsysinfo config, save, reload, drink beer.

Duplicate of original post: https://troubleshoot-coltpython.blogspot.com/2013/11/ubuntu-fail2ban-fails-to-parse-apache.html

I was trying to setup Fail2ban to block WordPress login bruteforce attacks, but Fail2ban somehow failed to parse access.log

When parsing log file with command:

fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/apache-wp-login.conf

CPU rises to 100% usage until I kill the process. I made a quick fix – workaround with redirecting needed content from access.log to another log file.

My setup is as follows:

OS: Ubuntu Server 12.04 LTS
Fail2ban: 0.8.6-3wheezy2build0.12.04.1
Python: 2.7.3-0ubuntu2.2

Fail2ban configuration:

 nano /etc/fail2ban/fail2ban.conf 
# Fail2Ban configuration file
# Author: Cyril Jaquier
# $Revision$


[Definition]

# Option: loglevel
# Notes.: Set the log level output.
# 1 = ERROR
# 2 = WARN
# 3 = INFO
# 4 = DEBUG
# Values: NUM Default: 3
#

loglevel = 4

# Option: logtarget
# Notes.: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT.
# Only one log target can be specified.
# Values: STDOUT STDERR SYSLOG file Default: /var/log/fail2ban.log
#

logtarget = /var/log/fail2ban.log

# Option: socket
# Notes.: Set the socket file. This is used to communicate with the daemon. Do
# not remove this file when Fail2ban runs. It will not be possible to
# communicate with the server afterwards.
# Values: FILE Default: /var/run/fail2ban/fail2ban.sock
#
socket = /var/run/fail2ban/fail2ban.sock

We add a new entry for WordPress

Add configuration to /etc/fail2ban/jail.conf

[apache-wp-login]

enabled = true
port = http,https
filter = apache-wp-login
logpath = /var/log/apache2/apache-wp-login.log
maxretry = 3
findtime = 60

Now me make new filter for WordPress. Some servers logs are in different format so we have to make different regex entries. These are two most common configurations:

Log format example 1:

www.domain.si:80 188.65.115.90 - - [08/Nov/2013:13:20:46 +0100] "POST /en/wp-login.php HTTP/1.1" 200 1784 "http://www.domain.si/en/wp-login.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1623.0 Safari/537.36"

Log format example 2:

89.222.15.152 - - [08/Nov/2013:13:40:12 +0000] "POST /wp-login.php HTTP/1.1" 200 1756 "http://domain.wordpress.com/wp-login.php" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0"

Create /etc/fail2ban/filter.d/apache-wp-login.conf

For log format example 1 use:

[Definition]
failregex = ^[^\:]+\:80 <HOST> .* "POST
ignoreregex =

ATTENTION! Don’t apply this filter to default access.log, it would block all POST request, not only WordPress. Only use it with modified log file we will create bellow.

For log format example 2 use:

failregex = <HOST>.*] "POST /wp-login.php

ATTENTION! Don’t apply this filter to log format example 1, it would block your own server, because <HOST> regex would match your domain (www.domain.si).

Now we create new log file for parsing (/var/log/apache2/apache-wp-login.log). We only want to filter out POST requests for wp-login.php and write them to new log file called apache-wp-login.log

tail --follow=name /var/log/apache2/access.log | grep --line-buffered wp-login.php &amp;amp;gt; /var/log/apache2/apache-wp-login.log &amp;amp;amp;

Add this command to /etc/rc.local so it would run at reboot:

 

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Fail2ban WordPress Login
tail -f /var/log/apache2/access.log | grep --line-buffered wp-login.php > /var/log/apache2/apache-wp-login.log &

exit 0
Restart Fail2ban and you’re done.

/etc/init.d/fail2ban restart