Piwigo and htaccess

As a long time WordPress and Gallery 3 user I become accustomed to some detailed guidelines on how htaccess file is managed and what can be added there to improve site speed and security.

Unfortunately, there is no significant documentation about that in Piwigo. So I have decided to compile sample htaccess rules you can use to achieve some of the goals above.

By default Piwigo does not come with htaccess file, so there should be no apparent conflict with any of the existing auto generated content.

DISCLAIMER: As with any htaccess please make use it on your own risk because your individual setup may vary from one rules below are tested for. Please read associated comments for each rule to see if it is applicable to your setup. Assumption is made that htaccess support is enabled for the server, you have FTP access and min version of PHP is 5.0+

Note: you need adjust site and email references in content below – look for yoursite.com

htaccess

# Set some reasonable defaults for PHP.  Most of these cannot be set
# inside the script itself.  For hosts that don't have .htaccess
# support but do support per-dir php.ini files, these settings are
# mirrored in php.ini
#
<IfModule mod_php5.c>
php_flag short_open_tag            On
php_flag magic_quotes_gpc          Off
php_flag magic_quotes_sybase       Off
php_flag magic_quotes_runtime      Off
php_flag register_globals          Off
php_flag session.auto_start        Off
php_flag suhosin.session.encrypt   Off
php_value upload_max_filesize   20M
php_value post_max_size     100M
</IfModule></code>
AcceptPathInfo on
############ disable directory browsing, includes, etc
#
Options +MultiViews -ExecCGI -Includes -Indexes FollowSymLinks
IndexIgnore *
############ Set default character set, turn off server signature, set server admin email, enable MP4 support
#
SetEnv TZ America/New_York
SetEnv SERVER_ADMIN webmaster@yoursite.com
ServerSignature off
AddDefaultCharset UTF-8
DefaultLanguage en-US
AddType audio/mp4 m4a
# Disallow script execution
AddHandler cgi-script .pl .py .jsp .asp .htm .shtml .sh .cgi
<FilesMatch "^php5?\.(ini|cgi)$">
Order Deny,Allow
Deny from All
Allow from env=REDIRECT_STATUS
</FilesMatch>
<IfModule mod_rewrite.c>
RewriteEngine On
# Safe Request Methods
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|POST|PROPFIND|OPTIONS|PUT)$ [NC]
RewriteRule .* - [F,NS,L]
# Bogus Graphics Exploit
RewriteCond %{HTTP:Content-Disposition} \.php [NC]
RewriteCond %{HTTP:Content-Type} image/.+ [NC]
RewriteRule .* - [F,NS,L]
# Trackback Spam
RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP_USER_AGENT} ^.*(opera|mozilla|firefox|msie|safari).*$ [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]
</IfModule>
# Increase security by uncommenting this block.  It keeps browsers
# from seeing support files that they shouldn't have access to.  We
# comment this out because Apache2 requires some minor configuration
# in order for you to use it.  You must specify "AllowOverride Limit"
# in your Apache2 config file before you uncomment this block or
# you'll get an "Internal Server Error".
<FilesMatch "(\.(class|fla|gitignore|inc|ini|sql|txt)|(README|LICENSE|.build_number))$">
Order deny,allow
Deny from all
</FilesMatch>
<FilesMatch "robots.txt">
Order allow,deny
Allow from all
</FilesMatch>
<IfModule mod_deflate.c>
# compress the files
AddOutputFilter DEFLATE js css php
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript application/x-httpd-php
# removes some bugs
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
Header append Vary User-Agent env=!dont-vary
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(js|css|xml|gz)$">
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
<IfModule mod_gzip.c>
#
# http://www.schroepl.net/projekte/mod_gzip/config.htm
mod_gzip_on                   Yes
mod_gzip_can_negotiate        Yes
mod_gzip_static_suffix        .gz
AddEncoding              gzip .gz
mod_gzip_update_static        No
mod_gzip_command_version      '/mod_gzip_status'
mod_gzip_keep_workfiles       No
mod_gzip_minimum_file_size    500
mod_gzip_maximum_file_size    500000
mod_gzip_maximum_inmem_size   60000
mod_gzip_min_http             1000
mod_gzip_handle_methods       GET POST
mod_gzip_item_exclude         reqheader  "User-agent: Mozilla/4.0[678]"
mod_gzip_dechunk              Yes
mod_gzip_item_include         file       \.css$
mod_gzip_item_include         file       \.js$
</IfModule>
# Improve performance by uncommenting this block.  It tells the
# browser that your images don't change very often so it won't keep
# asking for them.  If you get an error after uncommenting this, make
# sure you specify "AuthConfig Indexes" in your Apache config file.
#
<IfModule mod_expires.c>
# Turn on Expires and set default to 0
ExpiresActive On
ExpiresDefault A0
# Set up caching on media files for 1 year (forever?)
<FilesMatch "\.(flv|ico|pdf|avi|mov|ppt|doc|mp3|wmv|wav|m4a)$">
ExpiresDefault A29030400
Header append Cache-Control "public"
</FilesMatch>
# Set up caching on media files for 1 month
<FilesMatch "\.(jpg|jpeg|png|gif|swf)$">
ExpiresDefault A2678400
Header append Cache-Control "public"
</FilesMatch>
# Set up 2 Hour caching on commonly updated files
<FilesMatch "\.(xml|txt|html|js|css)$">
ExpiresDefault A7200
Header append Cache-Control "proxy-revalidate"
</FilesMatch>
# Force no caching for dynamic files
<FilesMatch "\.(php|cgi|pl|htm|html)$">
ExpiresActive Off
Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
</IfModule>
####################### BEGIN Url Rewrite section
#
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
########## Error Documents
#
#ErrorDocument 400 /error400.php
#ErrorDocument 401 /error401.php
#ErrorDocument 403 /error403.php
#ErrorDocument 404 /error404.php
#ErrorDocument 500 /error500.php
#
############################################
########## Site protection logic
#
########## SEF Section
#
#  RewriteCond %{REQUEST_URI} (/|\.htm|\.php|\.html|/[^.]*)$  [NC]
#  RewriteCond %{REQUEST_FILENAME} !-f
#  RewriteCond %{REQUEST_FILENAME} !-d
#  RewriteRule (.*) /error404.php
#
############################################
########## Stop hot linking
#
#  RewriteCond %{HTTP_REFERER} !^$
#  RewriteCond %{HTTP_REFERER} !^http://(*\.)?yoursite.com/.*$ [NC]
#  RewriteRule \.(gif|jpg|png|js|css|flv|swf)$ - [F]
#
############################################
########## Rewrite rules to block out some common exploits
#
# Block out any script trying to set a mosConfig value through the URL
#  RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
# Block out any script trying to base64_encode crap to send via URL
#  RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [OR]
# Block out any script that includes a <script> tag in URL
#  RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
# Block out any script trying to set a PHP GLOBALS variable via URL
#  RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
# Block out any script trying to modify a _REQUEST variable via URL
#  RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
# Send all blocked request to homepage with 403 Forbidden error!
#  RewriteRule ^(.*)$ index.php [F,L]
#
############################################
########## Block PHP injection attempts
#
RewriteCond %{QUERY_STRING} ^(.*)=http: [NC]
RewriteRule ^(.*)$ - [F,L]
#
############################################
########## Remove Query_String. May conflict with some plugins and logic
#
#  RewriteCond %{THE_REQUEST} ^GET\ /.*\;.*\ HTTP/
#  RewriteCond %{QUERY_STRING} !^$
#  RewriteRule .* http://yoursite.com%{REQUEST_URI}? [R=301,L]
#
############################################
########## From evil bots
# Update this list from http://www.invision-graphics.com/robotstxt_badbots.html
#
RewriteCond %{HTTP_USER_AGENT} ^BlackWidow [OR]
RewriteCond %{HTTP_USER_AGENT} ^Bot\ mailto:craftbot@yahoo.com [OR]
RewriteCond %{HTTP_USER_AGENT} ^ChinaClaw [OR]
RewriteCond %{HTTP_USER_AGENT} ^Custo [OR]
RewriteCond %{HTTP_USER_AGENT} ^DISCo [OR]
RewriteCond %{HTTP_USER_AGENT} ^Download\ Demon [OR]
RewriteCond %{HTTP_USER_AGENT} ^eCatch [OR]
RewriteCond %{HTTP_USER_AGENT} ^EirGrabber [OR]
RewriteCond %{HTTP_USER_AGENT} ^EmailSiphon [OR]
RewriteCond %{HTTP_USER_AGENT} ^EmailWolf [OR]
RewriteCond %{HTTP_USER_AGENT} ^Express\ WebPictures [OR]
RewriteCond %{HTTP_USER_AGENT} ^ExtractorPro [OR]
RewriteCond %{HTTP_USER_AGENT} ^EyeNetIE [OR]
RewriteCond %{HTTP_USER_AGENT} ^FlashGet [OR]
RewriteCond %{HTTP_USER_AGENT} ^GetRight [OR]
RewriteCond %{HTTP_USER_AGENT} ^GetWeb! [OR]
RewriteCond %{HTTP_USER_AGENT} ^Go!Zilla [OR]
RewriteCond %{HTTP_USER_AGENT} ^Go-Ahead-Got-It [OR]
RewriteCond %{HTTP_USER_AGENT} ^GrabNet [OR]
RewriteCond %{HTTP_USER_AGENT} ^Grafula [OR]
RewriteCond %{HTTP_USER_AGENT} ^HMView [OR]
RewriteCond %{HTTP_USER_AGENT} HTTrack [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Image\ Stripper [OR]
RewriteCond %{HTTP_USER_AGENT} ^Image\ Sucker [OR]
RewriteCond %{HTTP_USER_AGENT} Indy\ Library [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^InterGET [OR]
RewriteCond %{HTTP_USER_AGENT} ^Internet\ Ninja [OR]
RewriteCond %{HTTP_USER_AGENT} ^JetCar [OR]
RewriteCond %{HTTP_USER_AGENT} ^JOC\ Web\ Spider [OR]
RewriteCond %{HTTP_USER_AGENT} ^larbin [OR]
RewriteCond %{HTTP_USER_AGENT} ^LeechFTP [OR]
RewriteCond %{HTTP_USER_AGENT} ^Mass\ Downloader [OR]
RewriteCond %{HTTP_USER_AGENT} ^MIDown\ tool [OR]
RewriteCond %{HTTP_USER_AGENT} ^Mister\ PiX [OR]
RewriteCond %{HTTP_USER_AGENT} ^Navroad [OR]
RewriteCond %{HTTP_USER_AGENT} ^NearSite [OR]
RewriteCond %{HTTP_USER_AGENT} ^NetAnts [OR]
RewriteCond %{HTTP_USER_AGENT} ^NetSpider [OR]
RewriteCond %{HTTP_USER_AGENT} ^Net\ Vampire [OR]
RewriteCond %{HTTP_USER_AGENT} ^NetZIP [OR]
RewriteCond %{HTTP_USER_AGENT} ^Octopus [OR]
RewriteCond %{HTTP_USER_AGENT} ^Offline\ Explorer [OR]
RewriteCond %{HTTP_USER_AGENT} ^Offline\ Navigator [OR]
RewriteCond %{HTTP_USER_AGENT} ^PageGrabber [OR]
RewriteCond %{HTTP_USER_AGENT} ^Papa\ Foto [OR]
RewriteCond %{HTTP_USER_AGENT} ^pavuk [OR]
RewriteCond %{HTTP_USER_AGENT} ^pcBrowser [OR]
RewriteCond %{HTTP_USER_AGENT} ^RealDownload [OR]
RewriteCond %{HTTP_USER_AGENT} ^ReGet [OR]
RewriteCond %{HTTP_USER_AGENT} ^SiteSnagger [OR]
RewriteCond %{HTTP_USER_AGENT} ^SmartDownload [OR]
RewriteCond %{HTTP_USER_AGENT} ^SuperBot [OR]
RewriteCond %{HTTP_USER_AGENT} ^SuperHTTP [OR]
RewriteCond %{HTTP_USER_AGENT} ^Surfbot [OR]
RewriteCond %{HTTP_USER_AGENT} ^tAkeOut [OR]
RewriteCond %{HTTP_USER_AGENT} ^Teleport\ Pro [OR]
RewriteCond %{HTTP_USER_AGENT} ^VoidEYE [OR]
RewriteCond %{HTTP_USER_AGENT} ^Web\ Image\ Collector [OR]
RewriteCond %{HTTP_USER_AGENT} ^Web\ Sucker [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebAuto [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebCopier [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebFetch [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebGo\ IS [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebLeacher [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebReaper [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebSauger [OR]
RewriteCond %{HTTP_USER_AGENT} ^Website\ eXtractor [OR]
RewriteCond %{HTTP_USER_AGENT} ^Website\ Quester [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebStripper [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebWhacker [OR]
RewriteCond %{HTTP_USER_AGENT} ^WebZIP [OR]
RewriteCond %{HTTP_USER_AGENT} ^Wget [OR]
RewriteCond %{HTTP_USER_AGENT} ^Widow [OR]
RewriteCond %{HTTP_USER_AGENT} ^WWWOFFLE [OR]
RewriteCond %{HTTP_USER_AGENT} ^Xaldon\ WebSpider [OR]
RewriteCond %{HTTP_USER_AGENT} ^Zeus [OR]
RewriteCond %{HTTP_USER_AGENT} ^RepoMonkey\ Bait\ &\ Tackle/v1.01 [OR]
RewriteCond %{HTTP_USER_AGENT} ^RepoMonkey [or]
RewriteCond %{HTTP_USER_AGENT} ^Zeus\ 32297\ Webster\ Pro\ V2.9\ Win32\ [or]
RewriteCond %{HTTP_USER_AGENT} ^Webster\ Pro [or]
RewriteCond %{HTTP_USER_AGENT} ^EroCrawler [or]
RewriteCond %{HTTP_USER_AGENT} ^LinkScan/8.1a\ Unix [or]
RewriteCond %{HTTP_USER_AGENT} ^Keyword\ Density/0.9 [or]
RewriteCond %{HTTP_USER_AGENT} ^Kenjin\ Spider [or]
RewriteCond %{HTTP_USER_AGENT} ^Cegbfeieh
RewriteRule ^.* - [F,L]
#
############################################
####################### END Url Rewrite section
</IfModule>
<files .htaccess>
########## Begin - Deny access (firewall)
order allow,deny
deny from all
########## End - Deny access (firewall)
</files>
###################Do not have any whitespace/empty lines after this line#################
This entry was posted in Piwigo. Bookmark the permalink.

7 thoughts on “Piwigo and htaccess”

  1. I some reason do not indexed by images from the gallery in Google and Yandex =(

    1. not sure what you are asking about

  2. Charless says:

    Sergey which directory should this go into I keep getting error 500 issues installing certain plugins…Thanks

    1. htaccess goes into root of the PWG
      if you run into issues with certain plugins my advise would be to comment all sections out and then uncomment them one by one while testing to see which one would break plugin logic

      Possible suspects:
      * Disallow script execution – some plugins may require direct PHP code execution
      * Safe Request Methods – this should be rare but code may not be properly structured
      * “Increase security by uncommenting this block. It keeps browsers from seeing support files that they shouldn’t have access to. We comment this out because Apache2 requires some minor configuration – this block is Apache specific and can in fact break your code if Apache is misconfigured

      other sections can contribute as well, but it should be unlikely occurrence

  3. grant says:

    Thanks Serge! I could never get the index . php out of gallery3 URLs without breaking it. Any ideas here.

    1. No, you cannot
      As discussed here http://piwigo.org/forum/viewtopic.php?id=24250 even removing .php is problemmatic
      In WordPress everything goes through index.php, in PWG it is all over the place and many times plugin dependent
      You may try adding
      $conf[‘question_mark_in_urls’] = false;
      $conf[‘php_extension_in_urls’] = false;
      to local config to hide both, but it may not work properly
      there is no real elegant way to support permalinks people are used to in WP here

  4. Brett says:

    Thanks for posting this! I had issues after upgrading Piwigo via Softaculous (stuck with 403 permission errors, pointing me to upgrade.php without giving me a chance to login). I had no .htaccess file in the piwigo folder and used your template. Problem immediately solved… I got to the normal upgrade login page and the upgrade completed without issue.

Leave a Reply

  • About

    From being a junior developer all the way to Development Manager position, I was always interested in new technologies. Passionate speaker, IT junky, developer, architect, team lead, and development manager - many hats, one goal - making software better and closer to people’s needs. For the most part I am using my blog as a scratch pad, writing small articles on things which I came across, was asked about more then once, and which would otherwise require additional research again and again.

    View Serguei Dosyukov's profile on LinkedIn
  • Testimonials

    I’m a huge fan of this theme. I’ve got more than 90,000 pictures in my gallery3 running on a Ubuntu...

    Jklobo

    I've been using this [theme] since the start. It is by far the most attractive, feature packed and stable of...

    Rhyull

    The greydragon theme is fantastic. It’s clean, stable and feature rich. It took me a while to decide to move...

    Ed

    more...

  • Categories