Setting Virtualmin to work with Apache and Nginx

I will install virtualmin on Centos 6 (works with centos 7 too), nginx to work in front  of apache for serving cache.

Connect on root, download virtualmin from here

http://software.virtualmin.com/gpl/scripts/install.sh
chmod +x install.sh
./install.sh

Launch virtualmin in browser

https://xxx.xxx.xxx.xxx:10000

After installing,  go in “Virtualmin/System Settings/Server Templates/ Default Settings/Apache website” and change apache port from 80 in 8080 and “Port number for SSL virtual hosts” from 443 in 7443 .  Why ? Because on port 80 we will setup nginx and apache will work behind nginx on port 8080.

Go in “Virtualmin/System settings/Features and Plugins” and uncheck “Webmin login” , “Nginx website” ,  “Nginx SSL website” otherwise it will create conflict between apache and nginx when you want to create a virtual server.

edit

nano /etc/httpd/conf/httpd.conf

Change port 80 in 8080 and 443 in 7443

Edit

nano /etc/webmin/virtual-server/config

Change “web_port=80”  with  “web_port=8080” and “web_sslport=443” with “web_sslport=7443”

Install nginx

yum install nginx
yum install wbm-virtualmin-nginx
yum install wbm-virtualmin-nginx-ssl
service httpd restart
service nginx start
chkconfig nginx on

Welcome page for nginx will be here /usr/share/nginx/html (just like for apache is in /var/www/html)

create a file

nano /etc/nginx/proxy.conf

and add

proxy_redirect          off;
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP    $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout    90;
proxy_read_timeout    90;
proxy_buffers           32 4k;
proxy_cache_valid  200 302  60m;
proxy_cache_valid  404      1m;

Edit nginx.conf (or depends of installation default.conf)

nano /etc/nginx/nginx.conf

and add this at the begining of file  ( or before server { ……………….. }    )

proxy_cache_path /etc/nginx/cache levels=1:2 keys_zone=my_zone:10m inactive=60m max_size=10g use_temp_path=off;
proxy_cache_key "$scheme$request_method$host$request_uri";

and this on “location /”

proxy_cache my_zone;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_revalidate on;
proxy_cache_lock on;
index index.html index.htm;

to look like (replace SERVER_IP_ADDRESS with your IP address. If you are using an internal IP address, ex. 10.2.4.5, put internal IP)

location / {
proxy_cache my_zone;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_revalidate on;
proxy_cache_lock on;
index  index.html index.htm;
proxy_pass http://SERVER_IP_ADDRESS (or internal address if you have NAT):8080;
include /etc/nginx/proxy.conf;
               }

For SSL add in the same file nginx.conf  before the last }

    server {
        listen       443 ssl default_server;
        listen       [::]:443 ssl default_server;
        server_name  _;
        root         /usr/share/nginx/html;
        ssl on;
        ssl_certificate "/etc/nginx/ssl/ssl.cert";
        ssl_certificate_key "/etc/nginx/ssl/ssl.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        include /etc/nginx/default.d/*.conf;
        location / {
proxy_cache my_zone;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_revalidate on;
proxy_cache_lock on;
index  index.html index.htm;
proxy_pass https://SERVER_IP_ADDRESS(or internal address):7443;
include /etc/nginx/proxy.conf;
              }
        error_page 404 /404.html;
            location = /40x.html {
        }
    error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

nano /etc/httpd/conf.d/ssl.conf

and delete or comment

Listen 443 https

Otherwise is possible to have a conflict  ( make_sock: could not bind to address ) when you want to restart apache or nginx – server will try to open a port who is already open

Don’t forget both server, apache and nginx, work on same IP address only ports is different (same for SSL).

mkdir /etc/nginx/cache
cd /etc/nginx
chmod 755 cache
chown nginx:root cache
service nginx restart
service httpd restart

Go in “Virtualmin/Create virtual server/Enabled features” check Apache website and SSL website and uncheck Nginx website (virtualmin can’t create virtual server for both apache and nginx but no worries we will do it automatically bellow)

Let’s create virtual server in nginx when you will create one in virtualmin (apache):

Create a file

nano /etc/nginx/install.sh

and add

#!/bin/sh

NGINX_CONF_DIR="/etc/nginx"

#
# Create the nginx conf entry upon creating or modifying a domain
#
if [ "$VIRTUALSERVER_ACTION" = "CREATE_DOMAIN" ] || [ "$VIRTUALSERVER_ACTION" = "MODIFY_DOMAIN" ]; then
    cd ${NGINX_CONF_DIR}/sites-available/

    # Create the Nginx config directives into a sites-available entry
    echo "server {
    server_name  ${VIRTUALSERVER_DOM} www.${VIRTUALSERVER_DOM};
    listen      ${VIRTUALSERVER_IP}:80;
    root ${VIRTUALSERVER_PUBLIC_HTML_PATH};
                index index.html index.htm index.php;
                access_log ${VIRTUALSERVER_PUBLIC_HTML_PATH}/${VIRTUALSERVER_DOM}_nginx_access_log;
                error_log ${VIRTUALSERVER_PUBLIC_HTML_PATH}/${VIRTUALSERVER_DOM}_nginx_error_log;
                fastcgi_param GATEWAY_INTERFACE CGI/1.1;
                fastcgi_param SERVER_SOFTWARE nginx;
                fastcgi_param QUERY_STRING "\$query_string";
                fastcgi_param REQUEST_METHOD "\$request_method";
                fastcgi_param CONTENT_TYPE "\$content_type";
                fastcgi_param CONTENT_LENGTH "\$content_length";
                fastcgi_param SCRIPT_FILENAME ${VIRTUALSERVER_PUBLIC_HTML_PATH}"\$fastcgi_script_name";
                fastcgi_param SCRIPT_NAME "\$fastcgi_script_name";
                fastcgi_param REQUEST_URI "\$request_uri";
                fastcgi_param DOCUMENT_URI "\$document_uri";
                fastcgi_param DOCUMENT_ROOT ${VIRTUALSERVER_PUBLIC_HTML_PATH};
                fastcgi_param SERVER_PROTOCOL "\$server_protocol";
                fastcgi_param REMOTE_PORT "\$remote_port";
                fastcgi_param SERVER_ADDR "\$server_addr";
                fastcgi_param SERVER_NAME "\$server_name";

                location ~ \.php$ {
                        try_files "\$uri" =404;
                        fastcgi_pass unix:/var/php-nginx/142376571918837.sock/socket;
                        proxy_pass http://${VIRTUALSERVER_IP}:${VIRTUALSERVER_WEB_PORT};
                        include /etc/nginx/proxy.conf;
                       }

# Static contents
    location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|woff|ttf|otf|svg|woff2|eot)$ {
root ${VIRTUALSERVER_PUBLIC_HTML_PATH};
        expires 1M;
add_header Cache-Control "public";
                    }
gzip on;

    location / {
        proxy_pass http://${VIRTUALSERVER_IP}:${VIRTUALSERVER_WEB_PORT};
        include /etc/nginx/proxy.conf;   
    }

# if you don't like seeing all the errors for missing favicon.ico in root
       location = /favicon.ico { access_log off; log_not_found off; }

# if you don't like seeing errors for a missing robots.txt in root
       location = /robots.txt { access_log off; log_not_found off; }

# In the case of rewriting (mod_rewrite) with apache behind nginx you can use an incredibly simple directive called try_files. Here’s the same code as above, but when the changes are made any files or folder that are not found by nginx gets passed to apache for processing (useful for situations like WordPress, or .htaccess based rewrites when the file or folder is not caught by Nginx)

location / {
            # try_files attempts to serve a file or folder, until it reaches the fallback at the end
            try_files "\$uri" "\$uri"/ @backend;
      }

      location @backend {
            # essentially the same as passing php requests back to apache

            proxy_set_header X-Real-IP  "\$remote_addr";
            proxy_set_header X-Forwarded-For "\$proxy_add_x_forwarded_for";
            proxy_set_header Host "\$host";
            proxy_pass http://${VIRTUALSERVER_IP}:${VIRTUALSERVER_WEB_PORT};

     }
# Blocks access to .ht files
     location ~ /\.ht {
     deny all;
     }
        
}" > ${VIRTUALSERVER_DOM}.conf

    # If SSL in enabled, add the SSL directive too
    if [ $VIRTUALSERVER_SSL -eq 1 ]; then
        echo "

server {
    listen       ${VIRTUALSERVER_IP}:443 ssl;
    server_name  ${VIRTUALSERVER_DOM} www.${VIRTUALSERVER_DOM};
    root ${VIRTUALSERVER_PUBLIC_HTML_PATH};
    ssl on;
    ssl_certificate ${VIRTUALSERVER_SSL_CERT};
    ssl_certificate_key ${VIRTUALSERVER_SSL_KEY};

     location ~ \.php$ {
            try_files "\$uri" =404;
            proxy_pass https://${VIRTUALSERVER_IP}:${VIRTUALSERVER_WEB_SSLPORT};
            include /etc/nginx/proxy.conf;
                       }

        location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|woff|ttf|otf|svg|woff2|eot)$ {
                root ${VIRTUALSERVER_PUBLIC_HTML_PATH};
        expires 1M;
        add_header Cache-Control "public";
                     }

gzip on;

# if you don't like seeing all the errors for missing favicon.ico in root
       location = /favicon.ico {
                access_log off;
                log_not_found off;
                 }

# if you don't like seeing errors for a missing robots.txt in root
       location = /robots.txt {
                access_log off;
                log_not_found off;
                 }

    location / {
        proxy_pass https://${VIRTUALSERVER_IP}:${VIRTUALSERVER_WEB_SSLPORT};
        include /etc/nginx/proxy.conf;
    }

location / {
            # try_files attempts to serve a file or folder, until it reaches the fallback at the end
            try_files "\$uri" "\$uri"/ @backend;
      }

      location @backend {
            # essentially the same as passing php requests back to apache

            proxy_set_header X-Real-IP  "\$remote_addr";
            proxy_set_header X-Forwarded-For "\$proxy_add_x_forwarded_for";
            proxy_set_header Host "\$host";
            proxy_pass https://${VIRTUALSERVER_IP}:${VIRTUALSERVER_WEB_SSLPORT};

     }
# Blocks access to .ht files
     location ~ /\.ht {
     deny all;
     }

}" >> ${VIRTUALSERVER_DOM}.conf
    fi

    # Create a symlink if this is a new entry
    if [ "$VIRTUALSERVER_ACTION" = "CREATE_DOMAIN" ]; then
        ln -s ${NGINX_CONF_DIR}/sites-available/${VIRTUALSERVER_DOM}.conf ${NGINX_CONF_DIR}/sites-enabled/${VIRTUALSERVER_DOM}.conf
    fi
fi

# Delete the config file, log files and the symlink if the entry is being deleted
#
if [ "$VIRTUALSERVER_ACTION" = "DELETE_DOMAIN" ]; then
    rm -f ${NGINX_CONF_DIR}/sites-enabled/${VIRTUALSERVER_DOM}.conf ${NGINX_CONF_DIR}/sites-available/${VIRTUALSERVER_DOM}.conf
fi

# Reload nginx

service nginx restart

Save file and then give it execution right.

chmod +x install.sh

Go in “Virtualmin/System Settings/Virtualmin Configuration/Action upon server and user creation”

and add on “Command to run after making changes to a server”

/etc/nginx/install.sh

Go in /etc/nginx

cd /etc/nginx
mkdir sites-available
mkdir sites-enabled
mkdir ssl

Go in “Webmin/servers/Nginx Webserver/Module Config” (a cog settings icon on top)

and add on

“File or directory for new virtual hosts”

/etc/nginx/sites-available/

and on

“Directory for links to new virtual host files”

/etc/nginx/sites-enabled/

“Command to start Nginx”

/bin/systemctl start nginx.service

“Command to stop Nginx”

/bin/systemctl stop nginx.service

“Command to apply Nginx configuration”

/bin/systemctl restart nginx.service

Atention! If you work with “sites-available” and “sites-enable” directories when you will create virtual servers they are not showing in  Webmin/Servers/Nginx Webserver but you can modify them in directories mention above.

Don’t forget to open ports in firewall – 443, 80, 7443

To test the functionability create a virtual server (add a site) in virtualmin and then launch on terminal the following command twice

curl -I http://your-sites.com/

First response will be X-Proxy-Cache: MISS (because cache doesn’t exist, now it’s saved) , and second response X-Proxy-Cache: HIT (find the cache which was saved first time you launch the curl command and give you the response: HIT)
or
Check the cache directory to see if it store something

du -shc /etc/nginx/cache

Now you can work in virtualmin and apache like usually. You can install and delete sites, work with htaccess and everything. Nginx just create cache for sites you create in apache (with virtualmin).

Good luck!

11 Comments

  1. Sandy M.

    When i do a ssl checker I got problem with ssl chain. Do you have any ideea about that? I install letsencrypt ssl certificate from virtualmin.

    Reply
    • Hmmm...

      Go in the folder you have install ssl certficate, for virtualmin usually in /home/DOMAIN/ and do a concatenation between cert and ca files. Let’s say you have ssl.ca and ss.cert files.
      cat ssl.ca >> ssl.cert
      Don’t forget to put ssl.key and ssl.cert files in nginx site config (you can see how in post).

      Reply
  2. Thomas Grant

    Thanks. Hard to find good documentation for this combination – Nginx, Apache and Virtualmin

    Reply
  3. David Fenn

    I’m stumped, cannot find a way to do this>>
    Go in “Webmin/servers/Nginx Webserver/Module Config”
    and add on
    “File or directory for new virtual hosts”
    /etc/nginx/sites-available/
    and on
    “Directory for links to new virtual host files”
    Theres nowhere to do this PLEASE EXPLAIN

    Reply
    • Hmmm...

      In Webmin/Servers/Nginx Webserver is Module settings (a cog settings icon on top) and there you will find “Directory for links to new virtual host files”

      Reply
  4. James Gomez

    Thanks for sharing. Little problem with the SSL configuration but I figure it out.

    Reply
  5. conandrum

    Thanks for the guide. I did not setup SSL at all so disregard. Followed as closely as possible and I get:
    in /var/log/nginx/error.log
    2019/05/10 19:32:43 [error] 5979#5979: *11 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream, client: 45.115.6.184, server: _, request: “GET / HTTP/1.1”, upstream: “https://134.209.247.233:8080/”, host: “134.209.247.233:80”
    2019/05/10 19:32:43 [error] 5979#5979: *11 open() “/usr/share/nginx/html/50x.html” failed (2: No such file or directory), client: 45.115.6.184, server: _, request: “GET / HTTP/1.1”, upstream: “https://134.209.247.233:8080/”, host: “134.209.247.233:80”
    Accessing the site, I get 404 Not Found nginx/1.14.0 (Ubuntu), while when accessing
    http://134.209.247.233:8080/ i get the apache welcome page.

    I noticed also that I do not have such a folder in my structure: include /etc/nginx/default.d/*.conf; (which you specify in your server block for nginx.conf)
    Also noticed that I do not have any sym links in my sites-enabled folder. I already have a virtualhost from when I had only apache. I do not know if this is important that I have to do something in virtualmin to create the symlink.

    Sorry, completely new to this.
    If anybody can help out I would greatly appreciate it. Thank you in advance.

    This is what I added to my nginx.conf http{} section:
    ##
    # ADDITIONAL
    ##
    proxy_cache_path /etc/nginx/cache levels=1:2 keys_zone=my_zone:10m inactive=60m max_size=10g use_temp_path=off;
    proxy_cache_key “$scheme$request_method$host$request_uri”;

    server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;

    include /etc/nginx/default.d/*.conf;

    location / {
    proxy_cache my_zone;
    add_header X-Proxy-Cache $upstream_cache_status;
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
    proxy_cache_revalidate on;
    proxy_cache_lock on;
    index index.html index.htm;
    proxy_pass https://134.209.247.233:8080;
    include /etc/nginx/proxy.conf;
    }

    error_page 404 /404.html;
    location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
    }

    Reply
  6. Alex

    you’re really a excellent webmaster. The site
    loading pace is incredible. It seems that you are doing any distinctive trick.
    Moreover, The contents are masterwork. you’ve done a magnificent job on this subject!

    Reply
  7. James Muller

    Thanks for sharing man. I have slightly adjusted the code and everything is working fine. Virtualmin is the best!

    Reply
  8. Alexandros

    Hi, thanks for these information. What if i have already Virtualmin installed with virtual servers on it? Should i make some changes to these existing virtual servers?

    Thank you

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *