Skip to content

Instantly share code, notes, and snippets.

@ppmotskula
Last active September 25, 2023 11:19
Show Gist options
  • Save ppmotskula/4288167460de27d22225e4959c44c6c4 to your computer and use it in GitHub Desktop.
Save ppmotskula/4288167460de27d22225e4959c44c6c4 to your computer and use it in GitHub Desktop.
piactl -- install, configure and control CNIL's PIA software
#!/bin/bash
ABOUT="piactl 0.10
Copyright (c) 2018-2020 Peeter P. Mõtsküla <peeterpaul@motskula.net>
https://gist.github.com/ppmotskula/4288167460de27d22225e4959c44c6c4
License: MIT License (https://opensource.org/licenses/MIT)
piactl helps you to install, configure and control CNIL's PIA software
(https://www.cnil.fr/en/open-source-pia-software-helps-carry-out-data-protection-impact-assesment)
Special thanks to github.com/ylachgar for his runbook and github.com/kosmas58 for his pia_docker
NOTE: piactl has been successfully tested on a fresh DigitalOcean droplet
with 2 GB RAM and 1 VCPU running Ubuntu 18.04.2, and fresh VirtualBox VMs
running Ubuntu 18.04.1 (server and desktop editions).
"
USAGE="Usage:
piactl [status]
Display running PIA software if any
piactl start back|front|all
Start PIA software (pia-back, pia, or both)
piactl stop back|front|all
Stop running PIA software
piactl install back|front|all HOST [VERSION]
Download and install PIA software (latest version unless a
particular version number is given), and configure it to be
accessed via specified hostname
piactl reinstall back|front|all HOST [VERSION]
Shortcut for 'piactl remove OPTIONS && piactl install OPTIONS'
piactl secure back|front|all HOST
Reconfigure installed PIA software to be served via https,
obtaining letsencrypt (test) certificates unless already present
piactl certify HOST
Request non-test letsencrypt certificate for the given hostname.
Note that letsencrypt certificates expire in 90 days. To renew
them, run 'certbot renew' from time to time, or read certbot
documentation for how to configure your system to auto-renew them
piactl remove back|front|all
Remove installed PIA software. If you want to also remove the
dependencies and/or certificates, then you must do it manually
piactl resetcap
re-setcap /usr/bin/node to allow pia-front to run on :443
(this may be needed when nodejs has been updated)
piactl help|--help|-h
Show this help message and exit
NOTE: you need root permissions to use piactl.
"
main() {
case "$1" in
""|"status") # piactl
pia-status
;;
"start") # piactl start back|front|all
if [ $# != 2 ] ; then
usage "piactl start back|front|all"
fi
case "$2" in
back)
start-back
;;
front)
start-front
;;
all)
start-back
start-front
;;
*)
usage "piactl start back|front|all";
esac
;;
"stop") # piactl stop back|front|all
if [ $# != 2 ] ; then usage ; fi
case "$2" in
back)
stop-back
;;
front)
stop-front
;;
all)
stop-back
stop-front
;;
*)
usage "piactl stop back|front|all";
esac
;;
"install") # piactl install back|front|all HOST [VERSION]
if [[ $# < 3 || $# > 4 ]] ; then
usage "piactl install back|front|all HOST [VERSION]"
fi
install $2 $3 $4
;;
"reinstall") # piactl reinstall back|front|all HOST [VERSION]
if [[ $# < 3 || $# > 4 ]] ; then
usage "piactl reinstall back|front|all HOST [VERSION]"
fi
remove $2 && install $2 $3 $4
;;
"secure") # piactl secure back|front|all HOST
if [ $# != 3 ] ; then
usage "piactl secure back|front|all HOST"
fi
case "$2" in
back)
secure-back $3
;;
front)
secure-front $3
;;
all)
secure-back $3
secure-front $3
;;
*)
usage "piactl secure back|front|all HOST";
esac
;;
"certify") # piactl certify HOST
if [ $# != 2 ] ; then
usage "piactl certify HOST"
fi
certify $2 --prod
;;
"remove") # piactl remove back|front|all
remove $2 $3 $4
;;
"resetcap") # piactl resetcap
resetcap
;;
"help"|"--help"|"-h") # piactl help
echo "$ABOUT"
echo "$USAGE"
exit
;;
*) # piactl <unrecognized params>
usage
;;
esac
}
usage() {
local MSG
if [ $# != 0 ] ; then
MSG="$@"
else
MSG="piactl [COMMAND] [OPTIONS]"
fi
echo "Usage:
$MSG
Run 'piactl help' for details"
exit 1
}
pid-front() {
echo $(ps ax|grep -v grep|grep ' ng'|sed -e 's/\([0-9 ]*\).*/\1/'|sed -e 's/ //g')
}
pid-back() {
echo $(ps ax|grep -v grep|grep '\[pia-back]'|sed -e 's/\([0-9 ]*\).*/\1/'|sed -e 's/ //g')
}
pia-status() {
echo -n "PIA status: backend "
if [ ! -e ~/pia-back ] ; then echo -n "not installed"
else
if [ "$(pid-back)" != "" ] ; then echo -n "running ($(pid-back))" ; else echo -n "stopped" ; fi
fi
echo -n ", frontend "
if [ ! -e ~/pia ] ; then echo -n "not installed"
else
if [ "$(pid-front)" != "" ] ; then echo -n "running ($(pid-front))" ; else echo -n "stopped" ; fi
fi
echo
}
start-back() {
if ( ! sudo -v ) ; then nosudo ; fi
if [ ! -e ~/pia-back ] ; then
echo "piactl: warning: backend not installed"
elif [ "$(pid-back)" != "" ] ; then
echo "piactl: warning: backend is already running ($(pid-back))"
else
cd ~/pia-back
if [ -e ssl ] ; then
sudo -Hu www-data bin/rails s -b "ssl://0.0.0.0?key=ssl/server.key&cert=ssl/server.crt" &
else
sudo -Hu www-data bin/rails s -b 0.0.0.0 &
fi
fi
}
start-front() {
if ( ! sudo -v ) ; then nosudo ; fi
if [ ! -e ~/pia ] ; then
echo "piactl: warning: frontend not installed"
elif [ "$(pid-front)" != "" ] ; then
echo "piactl: warning: frontend is already running ($(pid-front))"
else
cd ~/pia
sudo -Hu www-data npm run-script start &
fi
}
stop-back() {
if ( ! sudo -v ) ; then nosudo ; fi
if [ ! -e ~/pia-back ] ; then
echo "piactl: warning: backend not installed"
elif [ "$(pid-back)" = "" ] ; then
echo "piactl: warning: backend not running"
else
sudo -Hu www-data kill $(pid-back)
fi
}
stop-front() {
if ( ! sudo -v ) ; then nosudo ; fi
if [ ! -e ~/pia ] ; then
echo "piactl: warning: frontend not installed"
elif [ "$(pid-front)" = "" ] ; then
echo "piactl: warning: frontend not running"
else
sudo -Hu www-data kill $(pid-front)
fi
}
nosudo() {
echo "piactl: ERROR: you need root permissions but sudo failed"
exit 1
}
install() { # install back|front|all HOST [VERSION]
if [[ $# < 2 || $# > 3 ]] ; then
usage "piactl install back|front|all HOST [VERSION]"
fi
if ( ! sudo -v ) ; then nosudo ; fi
case "$1" in
back)
install-back $2 $3
;;
front)
install-front $2 $3
;;
all)
install-back $2 $3
install-front $2 $3
;;
*)
usage "piactl install back|front|all HOST [VERSION]";
esac
}
install-back() { # install-back HOST [VERSION]
if [ -e ~/pia-back ] ; then
echo "piactl: ERROR: ~/pia-back exists; remove or reinstall. Run 'piactl help' for details'"
exit 1
fi
echo Installing pia-back into ~/pia-back...
local HOST=$1
local VERSION=$2
# install dependencies
sudo apt update && sudo apt install -y git ruby-dev sqlite3 build-essential zlib1g-dev postgresql libpq-dev libssl-dev
sudo gem install rails
# set postgres password
local PGPASS
read -p 'Enter new password for PostgreSQL user (role) "postgres": ' PGPASS
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '$PGPASS';"
# the following alternative would be more secure as it leaves no traces in user's history
# echo '\password postgres' | sudo -u postgres psql postgres
# download latest pia-back, checking out specific version if provided
cd
git clone https://github.com/LINCnil/pia-back.git
cd pia-back
if [ "$VERSION" != "" ] ; then
git checkout $VERSION
fi
# remove Gemfile.lock and install latest bundler
rm Gemfile.lock
sudo gem install bundler
# alternative: install specific version of bundler
#sudo gem install bundler -v `grep -A 1 "BUNDLED WITH" Gemfile.lock|tail -1`
# fix Gemfile to refer to Ruby 2.5.1
# as 2.6.5 is not yet available in Ubuntu repos
sed -i "s/^\(ruby '~> 2\).6.5'/\1.5.1'/" Gemfile
# fix Gemfile to fix Chrome 70 SSL curve compatibility issue
# ( https://github.com/puma/puma/issues/1670 )
sed -i "s/^gem 'puma'.*/gem 'puma', github: 'eric-norcross\/puma', branch: 'chrome_70_ssl_curve_compatiblity'/" Gemfile
# configure and build pia-back
sed -e "s/username:/username: postgres/" -e "s/password:/password: $PGPASS/" config/database.example.yml > config/database.yml
bundle install
bundle install --deployment # needed to get the SSL fix in
local SECRET=`bin/rake secret`
sed -e "s/__SECRET_KEY_HERE__/$SECRET/" config/application.example.yml > config/application.yml
# allow requests to $HOST
cat >> config/application.rb << .
Rails.application.configure do
config.hosts << "$HOST"
end
.
# create and initialise database
bin/rake db:create
bin/rake db:migrate
# make log and tmp writeable to www-data
sudo chgrp -R www-data tmp log
sudo chmod -R g+w tmp log
# create uploads and data and make them writeable to www-data
sudo mkdir uploads data
sudo chgrp -R www-data uploads data
sudo chmod -R g+w uploads data
# final message
echo "Done. pia-back should now be installed. Start it with 'piactl start back', then go to http://$HOST:3000"
}
install-front() { # install-front HOST [VERSION]
if [ -e ~/pia ] ; then
echo "piactl: ERROR: ~/pia exists; remove or reinstall. Run 'piactl help' for details'"
exit 1
fi
echo "Installing pia (frontend) into ~/pia..."
local HOST=$1
local VERSION=$2
# enable universe repository if not enabled -- needed for installing nodejs
if ! grep -q universe /etc/apt/sources.list ; then
sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu bionic universe"
fi
# install dependencies
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
sudo echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install -y nodejs npm yarn
# download latest pia, checking out specific version if needed
cd
git clone https://github.com/LINCnil/pia.git
cd pia
if [ "$VERSION" != "" ] ; then
git checkout $VERSION
fi
# configure pia
yarn install
cp src/environments/environment.prod.ts.example src/environments/environment.prod.ts
sed -i -e "s/version: ''/version: '$VERSION'/g" src/environments/environment.prod.ts
# if you want to BUILD pia for use with other webservers, use the following command
# node_modules/@angular/cli/bin/ng build --prod --build-optimizer --sourcemaps
# remove version number from package.json (might throw errors otherwise)
sed -i -e 's/^ *"version": .*//' package.json
# create npm startup script
sed -i -e 's/"ng",/"node_modules\/@angular\/cli\/bin\/ng",/g' package.json
sed -i -e 's/"ng serve",/"ng serve --host 0.0.0.0 --public-host '$HOST'",/g' package.json
# final message
echo "Done. pia should now be installed. Start it with 'piactl start front', then go to http://$HOST:4200"
}
remove() { # remove back|front|all
if [ $# != 1 ] ; then
usage "piactl remove back|front|all"
fi
case "$1" in
back)
remove-back
;;
front)
remove-front
;;
all)
remove-back
remove-front
;;
*)
usage "piactl remove back|front|all";
esac
}
remove-back() {
if ( ! sudo -v ) ; then nosudo ; fi
if [ -e ~/pia-back ] ; then
stop-back
killall ruby # otherwise 'rake secret' will fail when reinstalling
local SURE
read -p "Removing ~/pia-back including any possible customizations. Continue (y/N)? " SURE
case "$SURE" in
y|Y)
sudo rm -rf ~/pia-back
echo "Removed ~/pia-back. You may remove database, dependencies and certificates manually."
;;
*)
exit 2
;;
esac
else
echo "piactl: warning: ~/pia-back not found, nothing to remove"
fi
}
remove-front() {
if ( ! sudo -v ) ; then nosudo ; fi
if [ -e ~/pia ] ; then
stop-front
local SURE
read -p "Removing ~/pia including any possible customizations. Continue (y/N)? " SURE
case "$SURE" in
y|Y)
sudo rm -rf ~/pia
echo "Removed ~/pia. You may remove dependencies and certificates manually."
;;
*)
exit 2
;;
esac
else
echo "piactl: warning: ~/pia not found, nothing to remove"
fi
}
secure-back() { # secure-back HOST
if ( ! sudo -v ) ; then nosudo ; fi
local HOST=$1
if [ ! -e ~/pia-back ] ; then
echo "piactl: warning: pia-back is not installed, skipping"
elif [ -e ~/pia-back/ssl ] ; then
echo "piactl: warning: pia-back is already secured, skipping"
else
certify $HOST
mkdir ~/pia-back/ssl
cd ~/pia-back/ssl
ln -s /etc/letsencrypt/live/$HOST/fullchain.pem server.crt
ln -s /etc/letsencrypt/live/$HOST/privkey.pem server.key
## reinstall puma to get ssl support
#local PUMA=$(puma --version|sed -e "s/puma version //")
#sudo gem uninstall puma
#sudo gem install puma -v "$PUMA"
echo "Done. Restart pia-back, then go to https://$HOST:3000"
fi
}
secure-front() { # secure-front HOST
if ( ! sudo -v ) ; then nosudo ; fi
local HOST=$1
if [ ! -e ~/pia ] ; then
echo "piactl: warning: pia is not installed, skipping"
elif [ -e ~/pia/ssl ] ; then
echo "piactl: warning: pia is already secured, skipping"
else
certify $HOST
mkdir ~/pia/ssl
cd ~/pia/ssl
ln -s /etc/letsencrypt/live/$HOST/fullchain.pem server.crt
ln -s /etc/letsencrypt/live/$HOST/privkey.pem server.key
cd ~/pia
sed -i -e "s/ng serve --host/ng serve --ssl --port 443 --ssl-cert=ssl\/server.crt --ssl-key=ssl\/server.key --host/" package.json
sed -i -e "s/--public-host [^ \"]*/--public-host $HOST/" package.json
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/node
echo "Done. Restart pia-front, then go to https://$HOST"
fi
}
certify() { # certify HOST [--prod]
if ( ! sudo -v ) ; then nosudo ; fi
local HOST=$1
local PROD=$2
local TYPE="--test-cert"
if [ "$PROD" = "--prod" ] ; then TYPE="" ; fi
if ! dpkg -l certbot >/dev/null 2>&1 ; then
# install certbot if not already installed
sudo apt install certbot
fi
if [[ (! -e /etc/letsencrypt/live/$HOST) || ("$PROD" = "--prod") ]] ; then
# request new certs if not yet requested or requested for production
sudo certbot $TYPE certonly --standalone -d $HOST
sudo chmod 755 /etc/letsencrypt/live /etc/letsencrypt/archive
fi
}
resetcap() { # resetcap
if ( ! sudo -v ) ; then nosudo ; fi
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/node
}
main "$@"
@snelhard
Copy link

Thank you @ppmotskula , i made it by crossing your script and the PIA Doc !

@deWasbeer
Copy link

deWasbeer commented Nov 27, 2020

Automation of piactl using crontab not working on ubuntu 20.04. I've created a script under my user, when I run it under ssh it works perfect but when I run under crontab under my user I get my output but the ip doesn't change.
Here is my ssh output:
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-54-generic x86_64)

1 update can be installed immediately.
0 of these updates are security updates.
To see these additional updates run: apt list --upgradable

Your Hardware Enablement Stack (HWE) is supported until April 2025.
Last login: Wed Nov 25 18:37:13 2020 from 192.168.2.27

----alias pia and pias point to enable and disable script pasted below------

----xxx is my ip address-----

J@T:$ pia wo 25 nov 2020 18:48:06 CET - old ip: xxx
wo 25 nov 2020 18:48:07 CET - getting new ip...
wo 25 nov 2020 18:48:14 CET - new ip: 89.187.174.197
done!
J@T:
$ pias wo 25 nov 2020 18:48:25 CET - old ip: 89.187.174.197
wo 25 nov 2020 18:48:25 CET - quitting openvpn service...
wo 25 nov 2020 18:48:28 CET - new ip: xxx
done!

-----here is the script------

J@T:~$ cat /home/J/Headless/PIA.sh #!/bin/bash
echo $(date) - old ip: $(wget http://ipecho.net/plain -O - -q;echo)
sleep 1
echo $(date) - getting new ip...
piactl background enable
sleep 3
piactl connect
sleep 3
echo $(date) - new ip: $(wget http://ipecho.net/plain -O - -q;echo)
echo done!

Here is the cron output.

J@T:$ cat /home/J/Desktop/pia.txt wo 25 nov 2020 18:30:01 CET - old ip: xxx
wo 25 nov 2020 18:30:02 CET - getting new ip...
wo 25 nov 2020 18:30:08 CET - new ip: xxx
done!
wo 25 nov 2020 18:45:01 CET - old ip: xxx
wo 25 nov 2020 18:45:01 CET - quitting openvpn service...
wo 25 nov 2020 18:45:04 CET - new ip: xxx
done!
J@T:
$

I've also tried to run using sudo crontab -e, same effect, unsuccessful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment