• If you are still using CentOS 7.9, it's time to convert to Alma 8 with the free centos2alma tool by Plesk or Plesk Migrator. Please let us know your experiences or concerns in this thread:
    CentOS2Alma discussion
  • Inviting everyone to the UX test of a new security feature in the WP Toolkit
    For WordPress site owners, threats posed by hackers are ever-present. Because of this, we are developing a new security feature for the WP Toolkit. If the topic of WordPress website security is relevant to you, we would be grateful if you could share your experience and help us test the usability of this feature. We invite you to join us for a 1-hour online session via Google Meet. Select a convenient meeting time with our friendly UX staff here.

Script to fix apache ownership

Amin Taheri

Golden Pleskian
Plesk Certified Professional
Hello all, I was wondering if anyone had a script that they run to reset ownership on files and directories for users who use joomla or other php components that upload files and then set the owner to apache.

I understand that there are ways around this (fcgi, suphp) but since Parallels is going to be adding fcgi as a native component in the next version, those work arounds are not ideal since they will be soon obsolete.


This is rough and isnt very elegant, and Im not sure if this will even work as desired or if there is a better way.
Please feel free to post something better or make any changes you think are necessary.

The idea is to only change the files and folders where apache is the owner, so that way nothing else is messed up.


Code:
find /var/www/vhosts -user apache | grep '/httpdocs/' > /tmp/tmp-list

for i in `cat /tmp/tmp-list`; do

	DOMAIN=`echo $i | awk -F/ '{print $5}'` > /dev/null 2>&1
	echo Procesing $DOMAIN

	USER=`ls -la /var/www/vhosts/$DOMAIN/httpdocs/index.* | awk '{print $3}'` > /dev/null 2>&1
	GROUP=`ls -la /var/www/vhosts/$DOMAIN/httpdocs/index.* | awk '{print $4}'` > /dev/null 2>&1

	if [ `grep -c $DOMAIN /tmp/tmp-list` -gt 0 ]; then
		chown -R $USER:$GROUP `grep $DOMAIN /tmp/tmp-list`
	fi

	for $subdomain in `ls /var/www/vhosts/$DOMAIN/subdomains`; do
		echo Procesing subdomain $subdomain
		USER=`ls -la /var/www/vhosts/$DOMAIN/subdomains/$subdomain/httpdocs | awk '{print $3}'` > /dev/null 2>&1
		GROUP=`ls -la /var/www/vhosts/$DOMAIN/subdomains/$subdomain/httpdocs | awk '{print $4}'` > /dev/null 2>&1

		if [ `grep -c $subdomain /tmp/tmp-list` -gt 0 ]; then
			chown -R $USER:$GROUP `grep $subdomain /tmp/tmp-list`
		fi
	done

done
 
Last edited:
you can replace '/var/www/vhosts' with HTTPD_VHOSTS_D value from /etc/psa/psa.conf - this will make script more universal.

you can find domain names with:

DOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select name from domains where htype='vrt_hst' ")

then proceed with loop:

for domain in $DOMAINS
do
blah blah $HTTPD_VHOSTS_D/$domain/httpdocs
...
done

Also for each domain you can find

- subdomain names with query "select s.name from subdomains s, domains d where d.id = s.dom_id and d.name='$domain'"

- ftp user name (USER) with query "select u.login from sys_users u, domains d, hosting h where h.sys_user_id = u.id and h.dom_id = d.id and d.name = '$domain'"

GROUP is always psacln
 
Those are good suggestions.

here is a better version of that script.

Code:
#!/bin/sh

#Blindly fix everything? 
FIXALL="0"   # 1 = yes | 0 = No

#Detect problems only, dont actually do anything - basically run in test mode
DRYRUN="1"   # 1 = yes | 0 = No

#Path to psa.conf
PSACONF=/etc/psa/psa.conf

#Temp file to use -- it wil be deleted at the end of the script anyways
TMPFILE=/tmp/apache-user-fix-`date +%m-%d-%y`

#------------- Dont edit beyond this

#Group for Web files - this shouldnt change
GROUP='psacln'

#Determine the Vhost Root
VHOSTROOT=`grep HTTPD_VHOSTS_D $PSACONF | awk '{print $2}'`

#Get List of domains
DOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select name from domains where htype='vrt_hst' ")






#Do Domains
for domain in $DOMAINS; do

	#Get FTP user for the domain
	USER=(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select u.login from sys_users u, domains d, hosting h where h.sys_user_id = u.id and h.dom_id = d.id and d.name = '$domain'")

	#Blindly change owner on everything?
	if [ "$FIXALL" == "1" ]; then
		
		if [ "$DRYRUN" == "1" ]; then
			echo -e "\tDry Run: Would run:"
			echo -e "\tchown -R $USER:$GROUP `ls $VHOSTROOT/$domain/httpdocs | grep -v plesk-stat`"
		else
			echo "Fixing $domain"
			chown -R $USER:$GROUP `ls $VHOSTROOT/$domain/httpdocs | grep -v plesk-stat`
		fi
		
	else
		find $VHOSTROOT/$domain/httpdocs -user apache > $TMPFILE

		#if the domain has files in the temp list then fix those
		if [ `grep -c $domain $TMPFILE` -gt 0 ]; then
		
			if [ "$DRYRUN" == "1" ]; then
				echo -e "\tDry Run: Would run:"
				echo -e "\tchown -R $USER:$GROUP `grep $domain $TMPFILE`"
			else
				echo "Fixing $domain"
				chown -R $USER:$GROUP `grep $domain $TMPFILE`
			fi
		
		else
			echo "Skipping $domain"
		fi
	fi

	#Get list of sub domains for a given domain name
	SUBDOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select s.name from subdomains s, domains d where d.id = s.dom_id and d.name='$domain'")
	
	for subdomain in $SUBDOMAINS; do
		echo Procesing $subdomain.$domain

		USER=`ls -la $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | awk '{print $3}'`

		if [ "$FIXALL" == "1" ]; then
		
			if [ "$DRYRUN" == "1" ]; then
				echo -e "\tDry Run: Would run:"
				echo -e "\tchown -R $USER:$GROUP `ls $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | grep -v plesk-stat`"
			else
				echo "Fixing $subdomain.$domain"
				chown -R $USER:$GROUP `ls $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | grep -v plesk-stat`
			fi
		
		else
		
			find $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs -user apache > $TMPFILE
			
			if [ `grep -c '$domain/subdomains/$subdomain' $TMPFILE` -gt 0 ]; then
			
				if [ "$DRYRUN" == "1" ]; then
					echo -e "\tDry Run: Would run:"
					echo -e "\tchown -R $USER:$GROUP `grep $subdomain $TMPFILE`"
				else
					echo "Fixing $subdomain.$domain"
					chown -R $USER:$GROUP `grep $subdomain $TMPFILE`
				fi
			
			else
				echo "Skipping $subdomain.$domain"
			fi
		fi
		
	#Done with Sub Domains
	done
	
#Done with Domains
done
rm -Rf $TMPFILE
 
This script will break e.g. PHPBB as files that is saved to cache dir has default permissions:
-rw--w---- 1 apache apache


and after the user is "corrected" then the PHP with apache user can not access the file anymore.
 
Ok, I have placed a grep -v /cache in there, hopefully that will solve that

Code:
#!/bin/sh

## Version 1.0
#   By Amin Taheri
#   01/26/2009
#
#  This is a script used to fix ownership of files that are incorrectly owned by the web user
#  from applications such as Joomla where the web site writes files to the disk
#
#	$FIXALL is a basic blind fix - it will just re-chown everything except for plesk-stat when
#	set to 1 (on).  When set to 0 (off) it will do a search for files owned by the web user
#	and only change those files - may be safer to do this way until you fully trust the script
#
#	$DRYRUN is basically test mode - it will just output what it will do instead of actually 
#	doing it - no changes are made in this regardless of what fixall is set to
#
#	$PSACONF is the path to your psa.conf file
#	
#	$WEBUSER is set to "apache"  - the user the web server runs as - if yours is different 
#	make sure to change that value or this script will not do anything
#
##


#Blindly fix everything? 
FIXALL="0"   # 1 = yes | 0 = No - Set Default value

#Detect problems only, dont actually do anything - basically run in test mode
DRYRUN="1"   # 1 = yes | 0 = No - Set Default value

#Path to psa.conf
PSACONF=/etc/psa/psa.conf

#Web User
WEBUSER='apache'

#Temp file to use -- it wil be deleted at the end of the script anyways
TMPFILE=/tmp/apache-user-fix-`date +%m-%d-%y`

#------------- Dont edit beyond this

#Group for Web files - this shouldnt change
GROUP='psacln'

#Determine the Vhost Root
VHOSTROOT=`grep HTTPD_VHOSTS_D $PSACONF | awk '{print $2}'`


#Get List of domains
DOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select name from domains where htype='vrt_hst' ")
clear

function CheckDomain
{

	domain=$1
	echo -ne "Processing $domain: "
	
	SUBDOMAINECHO="1"

	#Get FTP user for the domain
	USER=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select u.login from sys_users u, domains d, hosting h where h.sys_user_id = u.id and h.dom_id = d.id and d.name = '$domain'")

	#Blindly change owner on everything?
	if [ "$FIXALL" == "1" ]; then
		
		if [ "$DRYRUN" == "1" ]; then
			echo -ne "\tDry Run: Would run:"
			echo
			echo -e "\tchown -R $USER:$GROUP `ls $VHOSTROOT/$domain/httpdocs | grep -v plesk-stat`"
		else
			echo -ne " - Fixed"
			chown -R $USER:$GROUP `ls $VHOSTROOT/$domain/httpdocs | grep -v plesk-stat  | grep -v '/cache'`
		fi
		
	else
		find $VHOSTROOT/$domain/httpdocs -user $WEBUSER  | grep -v '/cache' > $TMPFILE

		#if the domain has files in the temp list then fix those
		if [ `grep -c $domain $TMPFILE` -gt 0 ]; then
		
			if [ "$DRYRUN" == "1" ]; then
			echo -ne "\tDry Run: Would run:"
			echo
				for file in `grep $domain $TMPFILE`; do
					echo -e "\tchown -R $USER:$GROUP \"$file\""
				done
			else
			echo -ne " - Fixed"
				for file in `grep $domain $TMPFILE`; do
					chown -R $USER:$GROUP "$file"
				done
			fi
		
		else
			echo -ne " - Skipped"
		fi
	fi
	echo

	#Get list of sub domains for a given domain name
	SUBDOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select s.name from subdomains s, domains d where d.id = s.dom_id and d.name='$domain'")
	
	for subdomain in $SUBDOMAINS; do
		if [ "$SUBDOMAINECHO" == "1" ]; then
			echo -e "\tProcesing sub domains of $domain"
		fi
		
		SUBDOMAINECHO="0"
		
		echo -ne "\t - $subdomain.$domain"

		USER=`ls -la $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | awk '{print $3}'`

		if [ "$FIXALL" == "1" ]; then
		
			if [ "$DRYRUN" == "1" ]; then
				echo -e "\t\tDry Run: Would run:"
				echo -e "\t\tchown -R $USER:$GROUP `ls $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | grep -v plesk-stat  | grep -v '/cache'`"
			else
				echo -e "\t\t - Fixed"
				chown -R $USER:$GROUP `ls $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | grep -v plesk-stat  | grep -v '/cache'`
			fi
		
		else
		
			find $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs -user $WEBUSER | grep -v '/cache' > $TMPFILE
			
			if [ `grep -c '$domain/subdomains/$subdomain' $TMPFILE` -gt 0 ]; then
			
				if [ "$DRYRUN" == "1" ]; then
					echo -e "\t\tDry Run: Would run:"
					for file in `grep '$domain/subdomains/$subdomain' $TMPFILE`; do
						echo -e "\t\tchown -R $USER:$GROUP \"$file\""
					done
				else
					echo -e " - Fixed"
					for file in `grep "$domain/subdomains/$subdomain" $TMPFILE`; do
						chown -R $USER:$GROUP \"$file\"
					done
				fi
			
			else
				echo -e " - Skipped"
			fi
		fi
		
	#Done with Sub Domains
	done



}

#Do Domains
for domain in $DOMAINS; do
	CheckDomain $domain
#Done with Domains
done

#Remove the temp file
rm -Rf $TMPFILE



#### Push to boxes
# for i in `cat ~/all-boxes`; do
# scp ~/fix-permissions.sh $i:~/fix-permissions.sh
# done
 
this doesn't work with one problem we are facing.

One of the client website have a php script for uploading of files. The php script will create subfolders whenever someone need to upload. We can't run this script everytime someone try to upload something.

The folder created by this php script must have it's ownership by user:psacln and access must be 777. Any other solutions?
 
- you can put the script in a chroot and let a phpscript do the work
or
- set a crontab that run every x-time

For other permissions and ownerships we have a script that set the main directorystructure rights back to normal, we needed this after a raid 1 crash and had to copy everything manual disk to disk.
 
this doesn't work with one problem we are facing.

One of the client website have a php script for uploading of files. The php script will create subfolders whenever someone need to upload. We can't run this script everytime someone try to upload something.

The folder created by this php script must have it's ownership by user:psacln and access must be 777. Any other solutions?

1) use suphp or fastcgi (configured in vhost.conf)

2) upgrade to plesk 9 and switch php from apache module to cgi
 
Latest version
- updated so that it doesnt change cache or sess_ files/folders so that it doesnt break caching or sessions
Only problem with the script that I know of is that it doesnt work against files that have spaces in the name.

Code:
#!/bin/sh

## Version 1.1
#   By Amin Taheri
#   01/26/2009
#
#  This is a script used to fix ownership of files that are incorrectly owned by the web user
#  from applications such as Joomla where the web site writes files to the disk
#
#	$FIXALL is a basic blind fix - it will just re-chown everything except for plesk-stat when
#	set to 1 (on).  When set to 0 (off) it will do a search for files owned by the web user
#	and only change those files - may be safer to do this way until you fully trust the script
#
#	$DRYRUN is basically test mode - it will just output what it will do instead of actually 
#	doing it - no changes are made in this regardless of what fixall is set to
#
#	$PSACONF is the path to your psa.conf file
#	
#	$WEBUSER is set to "apache"  - the user the web server runs as - if yours is different 
#	make sure to change that value or this script will not do anything
#
#
#
#	Changelog:
#	1/27/09		Added grep -v '/cache/' to prevent the script from breaking phpbb cache
#	1/27/09		Added grep -v '/sess_' to prevent the script from breaking sessions
##


#Blindly fix everything? 
FIXALL="0"   # 1 = yes | 0 = No - Set Default value

#Detect problems only, dont actually do anything - basically run in test mode
DRYRUN="1"   # 1 = yes | 0 = No - Set Default value

#Path to psa.conf
PSACONF=/etc/psa/psa.conf

#Web User
WEBUSER='apache'

#Temp file to use -- it wil be deleted at the end of the script anyways
TMPFILE=/tmp/apache-user-fix-`date +%m-%d-%y`

#------------- Dont edit beyond this -------------#

#Group for Web files - this shouldnt change
GROUP='psacln'

#Determine the Vhost Root
VHOSTROOT=`grep HTTPD_VHOSTS_D $PSACONF | awk '{print $2}'`

#Get List of domains
DOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select name from domains where htype='vrt_hst' ")
clear

function CheckDomain
{

	domain=$1
	echo -ne "Processing $domain: "
	
	SUBDOMAINECHO="1"

	#Get FTP user for the domain
	USER=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select u.login from sys_users u, domains d, hosting h where h.sys_user_id = u.id and h.dom_id = d.id and d.name = '$domain'")

	#Blindly change owner on everything?
	if [ "$FIXALL" == "1" ]; then
		
		if [ "$DRYRUN" == "1" ]; then
			echo -ne "\tDry Run: Would run:"
			echo
			echo -e "\tchown -R $USER:$GROUP `ls $VHOSTROOT/$domain/httpdocs | grep -v plesk-stat`"
		else
			echo -ne " - Fixed"
			chown -R $USER:$GROUP `ls $VHOSTROOT/$domain/httpdocs | grep -v plesk-stat  | grep -v '/cache/' | grep -v '/sess_'`
		fi
		
	else
		find $VHOSTROOT/$domain/httpdocs -user $WEBUSER  | grep -v '/cache/' | grep -v '/sess_' > $TMPFILE

		#if the domain has files in the temp list then fix those
		if [ `grep -c $domain $TMPFILE` -gt 0 ]; then
		
			if [ "$DRYRUN" == "1" ]; then
			echo -ne "\tDry Run: Would run:"
			echo
				for file in `grep $domain $TMPFILE`; do
					echo -e "\tchown -R $USER:$GROUP \"$file\""
				done
			else
			echo -ne " - Fixed"
				for file in `grep $domain $TMPFILE`; do
					chown -R $USER:$GROUP "$file"
				done
			fi
		
		else
			echo -ne " - Skipped"
		fi
	fi
	echo

	#Get list of sub domains for a given domain name
	SUBDOMAINS=$(mysql -Ns -uadmin -p`cat /etc/psa/.psa.shadow` -Dpsa -e"select s.name from subdomains s, domains d where d.id = s.dom_id and d.name='$domain'")
	
	for subdomain in $SUBDOMAINS; do
		if [ "$SUBDOMAINECHO" == "1" ]; then
			echo -e "\tProcesing sub domains of $domain"
		fi
		
		SUBDOMAINECHO="0"
		
		echo -ne "\t - $subdomain.$domain"

		USER=`ls -la $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | awk '{print $3}'`

		if [ "$FIXALL" == "1" ]; then
		
			if [ "$DRYRUN" == "1" ]; then
				echo -e "\t\tDry Run: Would run:"
				echo -e "\t\tchown -R $USER:$GROUP `ls $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | grep -v plesk-stat  | grep -v '/cache/' | grep -v '/sess_'`"
			else
				echo -e "\t\t - Fixed"
				chown -R $USER:$GROUP `ls $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs | grep -v plesk-stat  | grep -v '/cache/' | grep -v '/sess_'`
			fi
		
		else
		
			find $VHOSTROOT/$domain/subdomains/$subdomain/httpdocs -user $WEBUSER | grep -v '/cache/' | grep -v '/sess_' > $TMPFILE
			
			if [ `grep -c '$domain/subdomains/$subdomain' $TMPFILE` -gt 0 ]; then
			
				if [ "$DRYRUN" == "1" ]; then
					echo -e "\t\tDry Run: Would run:"
					for file in `grep '$domain/subdomains/$subdomain' $TMPFILE`; do
						echo -e "\t\tchown -R $USER:$GROUP \"$file\""
					done
				else
					echo -e " - Fixed"
					for file in `grep "$domain/subdomains/$subdomain" $TMPFILE`; do
						chown -R $USER:$GROUP \"$file\"
					done
				fi
			
			else
				echo -e " - Skipped"
			fi
		fi
		
	#Done with Sub Domains
	done



}

#Do Domains
for domain in $DOMAINS; do
	CheckDomain $domain
#Done with Domains
done

#Remove the temp file
rm -Rf $TMPFILE



#### Push to boxes
# for i in `cat ~/all-boxes`; do
# scp ~/fix-permissions.sh $i:~/fix-permissions.sh
# done
 
Pease advise how to run

Hello All,

I have this problem with joomla. Could somebody please post some simple instructions to run this script via plesk admin.

Can it be run on one domain only ?
Where do I upload to is the web root ? httpdocs ? etc.
Task to setup in cron?

Many Thanks
PAul
 
Upload it anywhere, set it to chmod 755 and then run it from SSH. If you like yuo can set it as a cron job, but I would run it manually the first few times to make sure it works on your system for your case. By default the values are set to use a dry run, which means it will only tell you what it would do, it wont actually do it. You would have to change that to make it actually run, but I would recomend running it in dry run mode so that you can see what it will do before anything happens.
 
To Clarrify

Sorry I'm just getting round to doing this and thank you for the information. To clarify I do as follows

Save this to the root as say perms.php

Amend the
#Web User
WEBUSER='apache' to

#Web User
WEBUSER='www-data' which in my case is what plesk runs as for all domains on my vps. you can see this by going into Plesk file manager for a domain and checking the owner of the file.

Test run first then amend script to fix

This will go through all domains and change the owner of the folders and files from the Plesk ftp user to www-data. this will then allow joomla to upload images, modules and so on without manually changing permissions in the system?

regards
Paul
 
Not exactly, plesk has nothing to do with it - it will change the apache user to the ftp user - this will fix issues that arise when joomla creates files and folders through the web UI, which will create them as the apache user.
 
Psa.conf?

I am a newbie. When trying to determine what to change in this code for my setup, I got stumped. I don't seem to have a file named psa.conf. What is it, where should it be, and where can I get it?

Also, how do I go about running this in SSH? Sorry for the stupid questions but that's the only way to learn! Thanks for any help provided.
 
Back
Top