77# installation script for py4web on Ubuntu server
88# see https://github.com/web2py/py4web/blob/master/docs/updateDocs.sh
99#
10- # tested with Ubuntu Server 22.04 LTS
10+ # tested with Ubuntu Server 22.04.03 LTS
1111#
1212# Usage:
13- # copy and run it in any directory with 'sudo ./machine-setup .sh'
14- #
13+ # copy and run it in any directory with 'sudo ./machine-setup_24.04.03 .sh'
14+ #
1515# ========================================================================
1616
1717# Parameters:
1818
19- # python_bin is used to state your python version
20- # by default python_bin=python3.10
21- python_bin=python3.10
22-
2319# use_iptables is set to yes if
2420# you want to setup linux firewall from scratch
25- # allowing only ssh and http/https
21+ # allowing ssh, http/https ( mqtt to port 1883 and postgres 5432 can be enabled around lines 107-118 )
2622use_iptables=yes
2723
24+ # Virtual Environment Configuration (FIX for 'externally-managed-environment')
25+ venv_dir=/opt/py4web/venv
26+ python_bin=${venv_dir} /bin/python3 # This will be the python executable path after venv creation
27+
2828if [ " $EUID " -ne 0 ] 2> /dev/null
2929 then echo " Please run as root or with sudo"
3030 exit
4949 iptables -t nat -X
5050 iptables -t mangle -F
5151 iptables -t mangle -X
52-
52+
5353 #unlimited loopback
5454 iptables -A INPUT -i lo -j ACCEPT
5555 iptables -A OUTPUT -o lo -j ACCEPT
56-
56+
5757 #unlimited output
5858 iptables -P OUTPUT ACCEPT
59-
59+
6060 # Block sync
6161 iptables -A INPUT -p tcp ! --syn -m state --state NEW -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "Drop Sync"
6262 iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
63-
63+
6464 # Block Fragments
6565 iptables -A INPUT -f -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "Fragments Packets"
6666 iptables -A INPUT -f -j DROP
67-
67+
6868 # Block bad stuff
6969 iptables -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
7070 iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
71-
71+
7272 iptables -A INPUT -p tcp --tcp-flags ALL NONE -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "NULL Packets"
7373 iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # NULL packets
74-
74+
7575 iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
76-
76+
7777 iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "XMAS Packets"
7878 iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP #XMAS
79-
79+
8080 iptables -A INPUT -p tcp --tcp-flags FIN,ACK FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "Fin Packets Scan"
8181 iptables -A INPUT -p tcp --tcp-flags FIN,ACK FIN -j DROP # FIN packet scans
82-
82+
8383 iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
84-
84+
8585 # Allow established connections and outcoming stuff
8686 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
8787 iptables -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
88-
89- # Allow ssh
88+
89+ # Allow ssh
9090 iptables -A INPUT -p tcp --destination-port 22 -j ACCEPT
91-
91+
9292 # allow incomming ICMP ping pong stuff
9393 iptables -A INPUT -p icmp --icmp-type 8 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
9494 iptables -A OUTPUT -p icmp --icmp-type 0 -m state --state ESTABLISHED,RELATED -j ACCEPT
95-
95+
9696 # Allow port 53 tcp/udp (DNS Server)
9797 iptables -A INPUT -p udp --dport 53 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
9898 iptables -A OUTPUT -p udp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT
99-
99+
100100 iptables -A INPUT -p tcp --destination-port 53 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
101101 iptables -A OUTPUT -p tcp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT
102-
102+
103103 # Open port 80
104104 iptables -A INPUT -p tcp --destination-port 80 -j ACCEPT
105105 iptables -A INPUT -p tcp --destination-port 443 -j ACCEPT
106- ##### Add your rules below ######
107-
106+
107+ ##### Add your rules below ######
108+ # Open port 1883 moskitto mqtt standard port
109+ #iptables -A INPUT -p tcp --destination-port 1883 -j ACCEPT
110+ # Open port 5432 postgresql
111+ #iptables -A INPUT -p tcp --destination-port 5432 -j ACCEPT
112+
113+ # for limiting source and destination:
114+ #iptables -A INPUT -p tcp -s XXX.XXX.XXX.XXX -j ACCEPT
115+ #iptables -A OUTPUT -p tcp -d XXX.XXX.XXX.XXX -j ACCEPT
116+
117+
108118 ##### END your rules ############
109119
110120 # log everything else and drop it
116126
117127 chmod +x iptables-py4web.sh
118128 ./iptables-py4web.sh
119-
129+
120130 # make ipchain persistent on Ubuntu
121131 echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
122132 echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
@@ -130,9 +140,10 @@ else
130140fi
131141
132142echo " ======================================="
133- echo " Installing Packages"
143+ echo " Installing System Packages"
134144echo " ======================================="
135145apt-get update
146+ # We install python3 and python3-venv here
136147apt-get -y install emacs
137148apt-get -y install zip unzip
138149apt-get -y install tar
@@ -142,17 +153,36 @@ apt-get -y install sendmail
142153apt-get -y install fail2ban
143154apt-get -y install supervisor
144155apt-get -y install nginx
145- apt-get -y install ${python_bin}
156+ apt-get -y install python3
146157apt-get -y install python3-pip
147- apt-get -y install ${python_bin} -dev
158+ # Make sure venv is available
159+ apt-get -y install python3-venv
160+ apt-get -y install python3-dev
148161apt-get -y install postgresql-client
149162apt-get -y install postgresql-client-common
150163apt-get -y install sendmail
151164apt-get -y install redis-server
152165
166+ # --- FIX: Create and Configure Virtual Environment ---
167+ echo " ======================================="
168+ echo " Setting up Virtual Environment for py4web"
169+ echo " ======================================="
170+
171+ # Ensure the py4web app and venv directories exist
172+ mkdir -p /home/www-data/py4web
173+ mkdir -p $venv_dir
174+
175+ # Create the virtual environment using the system's python3
176+ /usr/bin/python3 -m venv $venv_dir
177+
178+ # Correct permissions for the app and venv folders so www-data can run py4web
179+ chown -R www-data:www-data /home/www-data/py4web
180+ chown -R www-data:www-data $venv_dir
181+ # --- END FIX ---
182+
153183
154184echo " ======================================="
155- echo " Installing Python Packages for py4web"
185+ echo " Installing Python Packages for py4web (in venv) "
156186echo " entf server: tornado, gevent, gunicorn"
157187echo " ======================================="
158188cat > requirements-py4web.txt << EOF
@@ -162,13 +192,15 @@ psycopg2
162192py4web
163193EOF
164194
195+ # Use the python executable inside the virtual environment
165196${python_bin} -m pip install -r requirements-py4web.txt
166197
167198if [ -f requirements.txt ]
168199then
169200 echo " ======================================="
170- echo " Installing Packages for apps"
201+ echo " Installing Packages for apps (in venv) "
171202 echo " ======================================="
203+ # Use the python executable inside the virtual environment
172204 ${python_bin} -m pip install -r requirements.txt
173205fi
174206
185217 echo " creating missing py4web folders and apps"
186218 echo " ========================================="
187219 mkdir -p /home/www-data/py4web
188- py4web setup /home/www-data/py4web/apps
220+ # py4web is now installed in venv, so we call it via the venv's python
221+ ${python_bin} -m py4web setup /home/www-data/py4web/apps
189222 chown -R www-data:www-data /home/www-data/py4web/apps
190223fi
191224
@@ -259,17 +292,23 @@ then
259292 cd $oldpath
260293fi
261294
295+ # --- FIX: Use 'tee' to correctly write to a root-owned file ---
262296if [ ! -f /etc/init.d/py4web ]
263297then
264-
265- echo '
298+ echo " ======================================="
299+ echo " Creating /etc/init.d/py4web startup file"
300+ echo " ======================================="
301+
302+ # Use 'cat << EOF' and pipe it to 'sudo tee' to handle root-owned files
303+ # The 'EOF' is quoted ('EOF') to prevent shell variable expansion inside the block
304+ cat << 'EOF ' | sudo tee /etc/init.d/py4web > /dev/null
266305#! /bin/sh
267306
268307NAME=py4web
269308DESC="py4web process"
270309PIDFILE="/var/run/${NAME}.pid"
271310LOGFILE="/var/log/${NAME}.log"
272- DAEMON="/usr/local /bin/py4web"
311+ DAEMON="/opt/py4web/venv /bin/py4web"
273312DAEMON_OPTS="run --password_file /home/www-data/py4web/password.txt /home/www-data/py4web/apps"
274313START_OPTS="--start --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} -- ${DAEMON_OPTS}"
275314STOP_OPTS="--stop --oknodo --pidfile ${PIDFILE}"
@@ -302,12 +341,13 @@ restart|force-reload)
302341 ;;
303342esac
304343exit 0
305- ' > /etc/init.d/py4web
344+ EOF
306345
307346fi
308347
348+ # This block is outside the 'if' and will execute every time to ensure final configuration
309349chmod +x /etc/init.d/py4web
310350echo Enter the password for py4web Dashboard:
311- py4web set_password --password_file=/home/www-data/py4web/password.txt
351+ ${python_bin} -m py4web set_password --password_file=/home/www-data/py4web/password.txt
312352/etc/init.d/py4web restart
313- /etc/init.d/nginx restart
353+ /etc/init.d/nginx restart
0 commit comments