Table of Contents

Though ArchWiki has a page that explains the installation process of WordPress, it doesn’t cover the configuration for Nginx. (Yes, I prefer Nginx to Apache.) Fortunately, the NGINX wiki has provided some good examples. Here we combine them with uWSGI to avoid modifying global php.ini so it remains intact and secure.


  • WordPress is downloaded to /opt/wordpress, with the correct permission http:http set.
  • nginx, uwsgi-plugin-php and other modules of PHP are installed.
  • Nginx is configured to use virtual hosts. Manual creation of /etc/nginx/sites-available and /etc/nginx/sites-enabled is required. And don’t forget to add the include directive in nginx.conf.

Getting started

Add the following server block to /etc/nginx/sites-available/wordpress. Replace with your domain name.

server {
    listen 80;

    root /opt/wordpress;
    index index.php;

    location = /favicon.ico {
        log_not_found off;
        access_log off;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;

    location / {
        try_files $uri $uri/ /index.php?$args;

    location ~ \.php$ {
        # ...

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

Configuring uWSGI

Let’s begin first by creating a file named /etc/uwsgi/wordpress.ini. Append the following content:

plugins = php

socket = /run/uwsgi/%n.sock
processes = 2
master = true
procname-master = uwsgi %n

; drop privileges
uid    = http
gid    = http
umask  = 027

; reload whenever this file changes
touch-reload = %p

; enforce a DOCUMENT_ROOT
php-docroot     = /opt/wordpress/%n
; limit allowed extensions
php-allowed-ext = .php
; search for index.php if required
php-index = index.php

; all php configurations are for this instance only

; change your timezone
php-set = date.timezone=Etc/UTC
; limit accessable directories
php-set = open_basedir=/tmp/:/proc/:/opt/wordpress/
; prevent php information leak
php-set = expose_php=false

; change this if you want to upload files in bigger size
php-set = upload_max_filesize=16M
php-set = post_max_size=16M
; change accordingly
php-set = memory_limit=512M
; nginx does this
php-set = output_buffering=off

; php modules
php-set = extension=mysqli
php-set = extension=gd
php-set = extension=iconv
php-set = extension=imagick
php-set = extension=exif

As described in here, %n refers to the filename without extension, and %p refers to the absolute path of the file.

Fill in the missing location block. For modifier descriptions, please visit uWSGI docs.

location ~ \.php$ {
    include uwsgi_params;
    uwsgi_modifier1 14;
    # uwsgi_modifier2 0; # default value
    uwsgi_pass unix:/run/uwsgi/wordpress.sock;

Activate settings by running the following commands:

cd /etc/nginx/sites-enabled
ln -s ../sites-available/wordpress
systemctl start nginx
systemctl start uwsgi@wordpress.socket

Complete installation

Once you have spent a couple of hours setting up your http server, php, and mysql, it is finally time to let WordPress have its five minutes and install itself.