├── README.md ├── etc ├── apache2 │ └── ports.conf └── nginx │ └── conf.d │ ├── proxy.conf │ └── upstreams.conf └── usr └── local └── ispconfig └── server ├── conf-custom ├── nginx_reverse_proxy_plugin.vhost.conf.master └── vhost.conf.master └── plugins-available └── nginx_reverse_proxy_plugin.inc.php /README.md: -------------------------------------------------------------------------------- 1 | Please visit [MixasikM/ispconfig3-nginx-reverse-proxy](https://github.com/MixasikM/ispconfig3-nginx-reverse-proxy) for a fork that seems to be maintaned. 2 | -------------------------------------------------------------------------------- /etc/apache2/ports.conf: -------------------------------------------------------------------------------- 1 | # If you just change the port or add more ports here, you will likely also 2 | # have to change the VirtualHost statement in 3 | # /etc/apache2/sites-enabled/000-default 4 | # This is also true if you have upgraded from before 2.2.9-3 (i.e. from 5 | # Debian etch). See /usr/share/doc/apache2.2-common/NEWS.Debian.gz and 6 | # README.Debian.gz 7 | 8 | NameVirtualHost *:82 9 | Listen 127.0.0.1:82 10 | Listen ::1:82 11 | -------------------------------------------------------------------------------- /etc/nginx/conf.d/proxy.conf: -------------------------------------------------------------------------------- 1 | proxy_redirect off; 2 | proxy_buffering on; 3 | 4 | proxy_set_header Host $host; 5 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 6 | proxy_set_header X-Forwarded-Proto $scheme; 7 | 8 | proxy_pass_header Set-Cookie; 9 | -------------------------------------------------------------------------------- /etc/nginx/conf.d/upstreams.conf: -------------------------------------------------------------------------------- 1 | upstream apache2 { 2 | server [::1]:82 max_fails=3 fail_timeout=10; 3 | } 4 | -------------------------------------------------------------------------------- /usr/local/ispconfig/server/conf-custom/nginx_reverse_proxy_plugin.vhost.conf.master: -------------------------------------------------------------------------------- 1 | 2 | server { 3 | 4 | ###################################################################### 5 | ## Server configuration 6 | ###################################################################### 7 | 8 | 9 | listen :443 ssl spdy; 10 | listen [::]:443 ssl spdy; 11 | 12 | listen :80; 13 | listen [::]:80; 14 | 15 | 16 | server_name []; 17 | 18 | root ; 19 | 20 | # recommended but not manditory directives 21 | # leave commented out unless you know what they are doing 22 | #limit_req zone=ddos-cage burst=50; 23 | #proxy_cache nginx_cache; 24 | 25 | ###################################################################### 26 | ## Log configuration 27 | ###################################################################### 28 | 29 | access_log off; 30 | 31 | 32 | ###################################################################### 33 | ## SSL configuration 34 | ###################################################################### 35 | 36 | # recommended but not manditory directive 37 | # leave commented out unless you know what it is doing 38 | #more_set_headers 'Strict-Transport-Security: max-age=15768000'; 39 | 40 | ssl_certificate /.nginx.crt; 41 | ssl_certificate_key /.key; 42 | 43 | 44 | ###################################################################### 45 | ## Redirects configuration 46 | ###################################################################### 47 | 48 | 49 | # Redirect http -> https 50 | return 301 https://$server_name$request_uri; 51 | 52 | 53 | 54 | # SEO Redirect 55 | if ($http_host = "") { 56 | return 301 $scheme://$request_uri; 57 | } 58 | 59 | 60 | ###################################################################### 61 | ## Locations configuration 62 | ###################################################################### 63 | 64 | # global locations 65 | # recommended but not manditory directive 66 | # leave commented out unless you know what it is doing 67 | # include /etc/nginx/locations.d/*.conf; 68 | 69 | # alias to local error docs 70 | 71 | location ^~ /error { root /var/www; } 72 | 73 | 74 | # default location 75 | location / { 76 | proxy_pass http://apache2; 77 | } 78 | 79 | ###################################################################### 80 | ## Directives configuration 81 | ###################################################################### 82 | 83 | 84 | 85 | } 86 | 87 | -------------------------------------------------------------------------------- /usr/local/ispconfig/server/conf-custom/vhost.conf.master: -------------------------------------------------------------------------------- 1 | 2 | AllowOverride None 3 | 4 | Require all denied 5 | 6 | Order Deny,Allow 7 | Deny from all 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | # Common 16 | ServerAdmin admin@rackster-server.ch 17 | ServerName 18 | 19 | 20 | 21 | 22 | ServerAlias 23 | 24 | 25 | # Logging 26 | ErrorLog /var/log/ispconfig/httpd//error.log 27 | 28 | # Document root 29 | 30 | DocumentRoot 31 | 32 | 33 | DocumentRoot 34 | 35 | 36 | DocumentRoot 37 | 38 | DocumentRoot 39 | 40 | 41 | 42 | 43 | # Rewrites 44 | 45 | RewriteEngine on 46 | 47 | RewriteCond %{HTTP_HOST} ^$ [NC] 48 | RewriteRule ^(.*)$ https://$1 [R=301,L] 49 | 50 | 51 | RewriteCond %{HTTP_HOST} ^$ [NC] 52 | RewriteRule ^(.*)$ https://$1 [R=301,L] 53 | 54 | 55 | RewriteCond %{HTTP_HOST} $ [NC] 56 | 57 | RewriteCond %{REQUEST_URI} !^/webdav/ 58 | RewriteCond %{REQUEST_URI} !^/php5-fcgi/ 59 | RewriteCond %{REQUEST_URI} !^ 60 | 61 | RewriteRule ^/(.*)$ $1 62 | 63 | 64 | 65 | # Error pages 66 | 67 | Alias /error/ "/error/" 68 | 69 | Alias /error/ /var/www/error/ 70 | 71 | Options -Indexes +FollowSymLinks 72 | AllowOverride None 73 | 74 | Require all granted 75 | 76 | Order allow,deny 77 | Allow from all 78 | 79 | 80 | 81 | ErrorDocument 400 /error/400.html 82 | ErrorDocument 401 /error/401.html 83 | ErrorDocument 403 /error/403.html 84 | ErrorDocument 404 /error/404.html 85 | ErrorDocument 405 /error/405.html 86 | ErrorDocument 500 /error/500.html 87 | ErrorDocument 502 /error/502.html 88 | ErrorDocument 503 /error/503.html 89 | 90 | 91 | # Clear PHP settings of this website 92 | 93 | SetHandler None 94 | 95 | Options -Indexes +FollowSymLinks 96 | AllowOverride 97 | 98 | Require all granted 99 | 100 | Order allow,deny 101 | Allow from all 102 | 103 | 104 | 105 | # ssi enabled 106 | AddType text/html .shtml 107 | AddOutputFilter INCLUDES .shtml 108 | Options +Includes 109 | 110 | 111 | 112 | 113 | 114 | Require all denied 115 | 116 | Order allow,deny 117 | Deny from all 118 | Allow from none 119 | 120 | 121 | 122 | 123 | 124 | 125 | # Clear PHP settings of this website 126 | 127 | SetHandler None 128 | 129 | Options -Indexes +FollowSymLinks 130 | AllowOverride 131 | 132 | Require all granted 133 | 134 | Order allow,deny 135 | Allow from all 136 | 137 | 138 | 139 | # ssi enabled 140 | AddType text/html .shtml 141 | AddOutputFilter INCLUDES .shtml 142 | Options +Includes 143 | 144 | 145 | 146 | 147 | 148 | Require all denied 149 | 150 | Order allow,deny 151 | Deny from all 152 | Allow from none 153 | 154 | 155 | 156 | 157 | 158 | # Ruby 159 | 160 | 161 | 162 | Options +ExecCGI 163 | 164 | RubyRequire apache/ruby-run 165 | #RubySafeLevel 0 166 | AddType text/html .rb 167 | AddType text/html .rbx 168 | 169 | SetHandler ruby-object 170 | RubyHandler Apache::RubyRun.instance 171 | 172 | 173 | SetHandler ruby-object 174 | RubyHandler Apache::RubyRun.instance 175 | 176 | 177 | 178 | 179 | # Perl 180 | 181 | 182 | PerlModule ModPerl::Registry 183 | PerlModule Apache2::Reload 184 | 185 | PerlResponseHandler ModPerl::Registry 186 | PerlOptions +ParseHeaders 187 | Options +ExecCGI 188 | 189 | 190 | PerlResponseHandler ModPerl::Registry 191 | PerlOptions +ParseHeaders 192 | Options +ExecCGI 193 | 194 | 195 | SetHandler perl-script 196 | 197 | 198 | 199 | 200 | # Python 201 | 202 | 203 | 204 | 205 | SetHandler mod_python 206 | 207 | PythonHandler mod_python.publisher 208 | PythonDebug On 209 | 210 | 211 | 212 | 213 | # CGI 214 | 215 | # cgi enabled 216 | 217 | 218 | Require all granted 219 | 220 | Order allow,deny 221 | Allow from all 222 | 223 | 224 | 225 | ScriptAlias /cgi-bin/ /cgi-bin/ 226 | 227 | SetHandler cgi-script 228 | 229 | 230 | 231 | # SuExec 232 | 233 | # suexec enabled 234 | 235 | SuexecUserGroup 236 | 237 | 238 | 239 | # mod_php 240 | 241 | # mod_php enabled 242 | AddType application/x-httpd-php .php .php3 .php4 .php5 243 | php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -fwebmaster@" 244 | php_admin_value upload_tmp_dir /tmp 245 | php_admin_value session.save_path /tmp 246 | # PHPIniDir 247 | 248 | 249 | php_admin_value open_basedir 250 | 251 | 252 | 253 | # suPHP 254 | 255 | # suphp enabled 256 | 257 | 258 | suPHP_Engine on 259 | # suPHP_UserGroup 260 | 261 | 262 | suPHP_ConfigPath 263 | 264 | 265 | 266 | SetHandler x-httpd-suphp 267 | 268 | suPHP_AddHandler x-httpd-suphp 269 | 270 | 271 | 272 | 273 | # PHP CGI 274 | 275 | # php as cgi enabled 276 | ScriptAlias /php5-cgi 277 | Action php5-cgi /php5-cgi 278 | 279 | 280 | SetHandler php5-cgi 281 | 282 | 283 | 284 | 285 | SetHandler php5-cgi 286 | 287 | 288 | 289 | 290 | Require all granted 291 | 292 | Order allow,deny 293 | Allow from all 294 | 295 | 296 | 297 | 298 | # FastCGI 299 | 300 | # php as fast-cgi enabled 301 | # For config options see: http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html 302 | 303 | 304 | FcgidIdleTimeout 300 305 | FcgidProcessLifeTime 3600 306 | # FcgidMaxProcesses 1000 307 | FcgidMaxRequestsPerProcess 308 | FcgidMinProcessesPerClass 0 309 | FcgidMaxProcessesPerClass 10 310 | FcgidConnectTimeout 3 311 | FcgidIOTimeout 600 312 | FcgidBusyTimeout 3600 313 | FcgidMaxRequestLen 1073741824 314 | 315 | IdleTimeout 300 316 | ProcessLifeTime 3600 317 | # MaxProcessCount 1000 318 | DefaultMinClassProcessCount 0 319 | DefaultMaxClassProcessCount 100 320 | IPCConnectTimeout 3 321 | IPCCommTimeout 360 322 | BusyTimeout 3600 323 | 324 | 325 | 326 | 327 | 328 | SetHandler fcgid-script 329 | 330 | FCGIWrapper .php 331 | FCGIWrapper .php3 332 | FCGIWrapper .php4 333 | FCGIWrapper .php5 334 | Options +ExecCGI 335 | AllowOverride 336 | 337 | Require all granted 338 | 339 | Order allow,deny 340 | Allow from all 341 | 342 | 343 | 344 | 345 | 346 | SetHandler fcgid-script 347 | 348 | FCGIWrapper .php 349 | FCGIWrapper .php3 350 | FCGIWrapper .php4 351 | FCGIWrapper .php5 352 | Options +ExecCGI 353 | AllowOverride 354 | 355 | Require all granted 356 | 357 | Order allow,deny 358 | Allow from all 359 | 360 | 361 | 362 | 363 | # PHP-FPM 364 | 365 | 366 | 367 | 368 | Require all granted 369 | 370 | Order allow,deny 371 | Allow from all 372 | 373 | 374 | 375 | 376 | SetHandler php5-fcgi 377 | 378 | 379 | 380 | 381 | SetHandler php5-fcgi 382 | 383 | 384 | Action php5-fcgi /php5-fcgi 385 | Alias /php5-fcgi {tmpl_var name='document_root'}/cgi-bin/php5-fcgi-{tmpl_var name='ip_address'}-{tmpl_var name='port'}-{tmpl_var name='domain'} 386 | 387 | FastCgiExternalServer {tmpl_var name='document_root'}/cgi-bin/php5-fcgi-{tmpl_var name='ip_address'}-{tmpl_var name='port'}-{tmpl_var name='domain'} -idle-timeout 300 -host 127.0.0.1: -pass-header Authorization 388 | 389 | ProxyPassMatch ^/(.*\.php[345]?(/.*)?)$ fcgi://127.0.0.1:/$1 390 | 391 | 392 | 393 | FastCgiExternalServer {tmpl_var name='document_root'}/cgi-bin/php5-fcgi-{tmpl_var name='ip_address'}-{tmpl_var name='port'}-{tmpl_var name='domain'} -idle-timeout 300 -socket -pass-header Authorization 394 | 395 | 396 | 397 | 398 | # add support for apache mpm_itk 399 | 400 | AssignUserId 401 | 402 | 403 | 404 | # Do not execute PHP files in webdav directory 405 | 406 | 407 | SecRuleRemoveById 960015 408 | SecRuleRemoveById 960032 409 | 410 | 411 | SetHandler None 412 | 413 | 414 | 415 | DavLockDB {tmpl_var name='document_root'}/tmp/DavLock 416 | # DO NOT REMOVE THE COMMENTS! 417 | # IF YOU REMOVE THEM, WEBDAV WILL NOT WORK ANYMORE! 418 | # WEBDAV BEGIN 419 | # WEBDAV END 420 | 421 | 422 | 423 | 424 | 425 | 426 | -------------------------------------------------------------------------------- /usr/local/ispconfig/server/plugins-available/nginx_reverse_proxy_plugin.inc.php: -------------------------------------------------------------------------------- 1 | 10 | * @link https://open-source.rackster.ch/project/ispconfig3-nginx-reverse-proxy-plugin 11 | */ 12 | class nginx_reverse_proxy_plugin { 13 | 14 | /** 15 | * Stores the internal plugin name. 16 | * 17 | * @var string 18 | */ 19 | var $plugin_name = 'nginx_reverse_proxy_plugin'; 20 | 21 | /** 22 | * Stores the internal class name. 23 | * 24 | * Needs to be the same as $plugin_name. 25 | * 26 | * @var string 27 | */ 28 | var $class_name = 'nginx_reverse_proxy_plugin'; 29 | 30 | /** 31 | * Stores the current vhost action. 32 | * 33 | * When ISPConfig triggers the vhost event, it passes either create,update,delete etc. 34 | * 35 | * @see onLoad() 36 | * 37 | * @var string 38 | */ 39 | var $action = ''; 40 | 41 | 42 | /** 43 | * ISPConfig onInstall hook. 44 | * 45 | * Called during ISPConfig installation to determine if a symlink shall be created. 46 | * 47 | * @return bool create symlink if true 48 | */ 49 | function onInstall() { 50 | global $conf; 51 | return $conf['services']['web'] == true; 52 | } 53 | 54 | /** 55 | * ISPConfig onLoad hook. 56 | * 57 | * Register the plugin for some site related events. 58 | */ 59 | function onLoad() { 60 | global $app; 61 | 62 | $app->plugins->registerEvent('web_domain_insert', $this->plugin_name, 'ssl'); 63 | $app->plugins->registerEvent('web_domain_update', $this->plugin_name, 'ssl'); 64 | $app->plugins->registerEvent('web_domain_delete', $this->plugin_name, 'ssl'); 65 | 66 | $app->plugins->registerEvent('web_domain_insert', $this->plugin_name, 'insert'); 67 | $app->plugins->registerEvent('web_domain_update', $this->plugin_name, 'update'); 68 | $app->plugins->registerEvent('web_domain_delete', $this->plugin_name, 'delete'); 69 | 70 | $app->plugins->registerEvent('client_delete', $this->plugin_name, 'client_delete'); 71 | } 72 | 73 | 74 | /** 75 | * ISPConfig ssl hook. 76 | * 77 | * Called every time something in the ssl tab is done. 78 | * 79 | * @see onLoad() 80 | * @uses cert_helper() 81 | * 82 | * @param string $event_name the event/action name 83 | * @param array $data the vhost data 84 | */ 85 | function ssl($event_name, $data) { 86 | global $app, $conf; 87 | 88 | $app->uses('system'); 89 | 90 | //* Only vhosts can have a ssl cert 91 | if($data["new"]["type"] != "vhost" && $data["new"]["type"] != "vhostsubdomain") { 92 | return; 93 | } 94 | 95 | if ($data['new']['ssl_action'] == 'del') { 96 | $this->cert_helper('delete', $data); 97 | } else { 98 | $this->cert_helper('update', $data); 99 | } 100 | } 101 | 102 | /** 103 | * ISPConfig insert hook. 104 | * 105 | * Called every time a new site is created. 106 | * 107 | * @uses update() 108 | * 109 | * @param string $event_name the event/action name 110 | * @param array $data the vhost data 111 | */ 112 | function insert($event_name, $data) { 113 | global $app, $conf; 114 | 115 | $this->action = 'insert'; 116 | $this->update($event_name, $data); 117 | } 118 | 119 | /** 120 | * ISPConfig update hook. 121 | * 122 | * Called every time a site gets updated from within ISPConfig. 123 | * 124 | * @see insert() 125 | * @see delete() 126 | * 127 | * @param string $event_name the event/action name 128 | * @param array $data the vhost data 129 | */ 130 | function update($event_name, $data) { 131 | global $app, $conf; 132 | 133 | //* $VAR: command to run after vhost insert/update/delete 134 | $final_command = '/etc/init.d/nginx reload'; 135 | 136 | if ($this->action != 'insert') { 137 | $this->action = 'update'; 138 | } 139 | 140 | $app->uses('getconf'); 141 | $app->uses('system'); 142 | $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); 143 | 144 | $app->load('tpl'); 145 | 146 | $tpl = new tpl(); 147 | $tpl->newTemplate('nginx_reverse_proxy_plugin.vhost.conf.master'); 148 | 149 | $web_folder = 'web'; 150 | if($data['new']['type'] == 'vhostsubdomain') { 151 | $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($data['new']['parent_domain_id'])); 152 | $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $data['new']['domain']); 153 | 154 | if($subdomain_host == '') { 155 | $subdomain_host = 'web'.$data['new']['domain_id']; 156 | } 157 | 158 | $web_folder = $data['new']['web_folder']; 159 | unset($tmp); 160 | } 161 | 162 | $vhost_data = $data['new']; 163 | $vhost_data['web_document_root'] = $data['new']['document_root'].'/'.$web_folder; 164 | $vhost_data['web_document_root_www'] = $web_config['website_basedir'].'/'.$data['new']['domain'].'/'.$web_folder; 165 | $vhost_data['web_basedir'] = $web_config['website_basedir']; 166 | $vhost_data['ssl_domain'] = $data['new']['ssl_domain']; 167 | 168 | /* __ VHOST & VHOSTSUBDOMAIN - section for vhosts and vhostsubdomains //////////////*/ 169 | if ($data['new']['type'] == 'vhost' || $data['new']['type'] == 'vhostsubdomain') { 170 | if ($data['new']['ipv6_address'] != '') { 171 | $tpl->setVar('ipv6_enabled', 1); 172 | } 173 | 174 | $server_alias = array(); 175 | switch($data['new']['subdomain']) { 176 | case 'www': 177 | // if seo-redirect is enabled, this should be placed in separate server block 178 | // to prevent if statement in server/request! 179 | $server_alias[] .= 'www.'. $data['new']['domain'] .' '; 180 | break; 181 | case '*': 182 | $server_alias[] .= '*.'. $data['new']['domain'] .' '; 183 | break; 184 | } 185 | 186 | $alias_result = array(); 187 | $alias_result = $app->dbmaster->queryAllRecords('SELECT * FROM web_domain WHERE parent_domain_id = '.$data['new']['domain_id']." AND active = 'y' AND type != 'vhostsubdomain'"); 188 | 189 | if (count($alias_result) > 0) { 190 | // if alias is redirect type, put in server block with seo-redirect to prevent 191 | // if statement in server/request! 192 | foreach($alias_result as $alias) { 193 | switch($alias['subdomain']) { 194 | case 'www': 195 | $server_alias[] .= 'www.'. $alias['domain'] .' '. $alias['domain'] .' '; 196 | break; 197 | case '*': 198 | $server_alias[] .= '*.'. $alias['domain'] .' '. $alias['domain'] .' '; 199 | break; 200 | default: 201 | $server_alias[] .= $alias['domain'] .' '; 202 | } 203 | 204 | $app->log('Add server alias: '. $alias['domain'], LOGLEVEL_DEBUG); 205 | } 206 | 207 | unset($alias); 208 | } 209 | 210 | if (count($server_alias) > 0) { 211 | $server_alias_str = ''; 212 | 213 | foreach($server_alias as $tmp_alias) { 214 | $server_alias_str .= $tmp_alias; 215 | } 216 | 217 | unset($tmp_alias); 218 | $tpl->setVar('alias', $server_alias_str); 219 | } else { 220 | $tpl->setVar('alias', ''); 221 | } 222 | 223 | if (!isset($rewrite_rules)) { 224 | $rewrite_rules = array(); 225 | } 226 | 227 | if ($data['new']['redirect_type'] != '' && $data['new']['redirect_path'] != '') { 228 | if (substr($data['new']['redirect_path'], -1) != '/') { 229 | $data['new']['redirect_path'] .= '/'; 230 | } 231 | 232 | if (substr($data['new']['redirect_path'], 0, 8) == '[scheme]') { 233 | $rewrite_target = 'http'.substr($data['new']['redirect_path'], 8); 234 | $rewrite_target_ssl = 'https'.substr($data['new']['redirect_path'], 8); 235 | } else { 236 | $rewrite_target = $data['new']['redirect_path']; 237 | $rewrite_target_ssl = $data['new']['redirect_path']; 238 | } 239 | 240 | if (substr($data['new']['redirect_path'], 0, 4) == 'http') { 241 | $data['new']['redirect_type'] = 'permanent'; 242 | } else { 243 | switch($data['new']['redirect_type']) { 244 | case 'no': 245 | $data['new']['redirect_type'] = 'break'; 246 | break; 247 | case 'L': 248 | $data['new']['redirect_type'] = 'break'; 249 | break; 250 | default: 251 | $data['new']['redirect_type'] = 'permanent'; 252 | } 253 | } 254 | 255 | switch($data['new']['subdomain']) { 256 | case 'www': 257 | $rewrite_rules[] = array( 258 | 'rewrite_domain' => '^'.$data['new']['domain'], 259 | 'rewrite_type' => ($data['new']['redirect_type'] == 'no') ? '' : $data['new']['redirect_type'], 260 | 'rewrite_target' => $rewrite_target, 261 | 'rewrite_target_ssl' => $rewrite_target_ssl 262 | ); 263 | $rewrite_rules[] = array( 264 | 'rewrite_domain' => '^www.'.$data['new']['domain'], 265 | 'rewrite_type' => ($data['new']['redirect_type'] == 'no') ? '' : $data['new']['redirect_type'], 266 | 'rewrite_target' => $rewrite_target, 267 | 'rewrite_target_ssl' => $rewrite_target_ssl 268 | ); 269 | break; 270 | case '*': 271 | $rewrite_rules[] = array( 272 | 'rewrite_domain' => '(^|\.)'.$data['new']['domain'], 273 | 'rewrite_type' => ($data['new']['redirect_type'] == 'no') ? '' : $data['new']['redirect_type'], 274 | 'rewrite_target' => $rewrite_target, 275 | 'rewrite_target_ssl' => $rewrite_target_ssl 276 | ); 277 | break; 278 | default: 279 | $rewrite_rules[] = array( 280 | 'rewrite_domain' => '^'.$data['new']['domain'], 281 | 'rewrite_type' => ($data['new']['redirect_type'] == 'no') ? '' : $data['new']['redirect_type'], 282 | 'rewrite_target' => $rewrite_target, 283 | 'rewrite_target_ssl' => $rewrite_target_ssl 284 | ); 285 | } 286 | } 287 | 288 | if ($data['new']['seo_redirect'] != '' && ($data['new']['subdomain'] == 'www' || $data['new']['subdomain'] == '*')) { 289 | $vhost_data['seo_redirect_enabled'] = 1; 290 | 291 | if ($data['new']['seo_redirect'] == 'non_www_to_www') { 292 | $vhost_data['seo_redirect_origin_domain'] = $data['new']['domain']; 293 | $vhost_data['seo_redirect_target_domain'] = 'www.'. $data['new']['domain']; 294 | } 295 | 296 | if ($data['new']['seo_redirect'] == 'www_to_non_www') { 297 | $vhost_data['seo_redirect_origin_domain'] = 'www.'. $data['new']['domain']; 298 | $vhost_data['seo_redirect_target_domain'] = $data['new']['domain']; 299 | } 300 | } else { 301 | $vhost_data['seo_redirect_enabled'] = 0; 302 | } 303 | 304 | $errordocs = !$data['new']['errordocs']; 305 | 306 | $nginx_directives = $data['new']['nginx_directives']; 307 | $nginx_directives = str_replace("\r\n", "\n", $nginx_directives); 308 | $nginx_directives = str_replace("\r", "\n", $nginx_directives); 309 | 310 | $crt_file = escapeshellcmd($data['new']['document_root'] .'/ssl/'. $data['new']['ssl_domain'] .'.crt'); 311 | $key_file = escapeshellcmd($data['new']['document_root'] .'/ssl/'. $data['new']['ssl_domain'] .'.key'); 312 | 313 | if ($data['new']['ssl_domain'] != '' && $data['new']['ssl'] == 'y' && is_file($crt_file) && is_file($key_file) && (filesize($crt_file) > 0) && (filesize($key_file) > 0)) { 314 | $http_to_https = 1; 315 | } else { 316 | $http_to_https = 0; 317 | } 318 | 319 | // non-ssl vhost loop 320 | if (count($rewrite_rules) > 0) { 321 | $vhosts[] = array( 322 | 'ip_address' => $data['new']['ip_address'], 323 | 'ipv6_address' => $data['new']['ipv6_address'], 324 | 'ssl_enabled' => 0, 325 | 'http_to_https' => $http_to_https, 326 | 'nginx_directives' => $nginx_directives, 327 | 'errordocs' => $errordocs, 328 | 'port' => 80 329 | ); 330 | } else { 331 | $vhosts[] = array( 332 | 'ip_address' => $data['new']['ip_address'], 333 | 'ipv6_address' => $data['new']['ipv6_address'], 334 | 'ssl_enabled' => 0, 335 | 'http_to_https' => $http_to_https, 336 | 'nginx_directives' => $nginx_directives, 337 | 'errordocs' => $errordocs, 338 | 'port' => 80 339 | ); 340 | } 341 | 342 | // ssl vhost loop 343 | if ($http_to_https == 1) { 344 | $vhost_data['web_document_root_ssl'] = $data['new']['document_root'] .'/ssl'; 345 | 346 | if (count($rewrite_rules) > 0) { 347 | $vhosts[] = array( 348 | 'ip_address' => $data['new']['ip_address'], 349 | 'ipv6_address' => $data['new']['ipv6_address'], 350 | 'ssl_enabled' => 1, 351 | 'http_to_https' => 0, 352 | 'rewrite_enabled' => 1, 353 | 'nginx_directives' => $nginx_directives, 354 | 'errordocs' => $errordocs, 355 | 'port' => 443 356 | ); 357 | } else { 358 | $vhosts[] = array( 359 | 'ip_address' => $data['new']['ip_address'], 360 | 'ipv6_address' => $data['new']['ipv6_address'], 361 | 'ssl_enabled' => 1, 362 | 'http_to_https' => 0, 363 | 'rewrite_enabled' => 0, 364 | 'nginx_directives' => $nginx_directives, 365 | 'errordocs' => $errordocs, 366 | 'port' => 443 367 | ); 368 | } 369 | } 370 | 371 | $tpl->setLoop('vhosts', $vhosts); 372 | $tpl->setVar($vhost_data); 373 | 374 | if ($this->action == 'insert') { 375 | $this->vhost_helper('insert', $data, $tpl->grab()); 376 | } 377 | 378 | if ($this->action == 'update') { 379 | $vhost_backup = $this->vhost_helper('update', $data, $tpl->grab()); 380 | } 381 | } 382 | 383 | 384 | /** 385 | * Section for aliasdomains. 386 | * 387 | * This section is used for aliasdomains. 388 | */ 389 | if ($data['new']['type'] == 'alias') { 390 | $parent_domain = $app->dbmaster->queryOneRecord('SELECT * FROM web_domain WHERE domain_id = '. intval($data['new']['parent_domain_id']) .''); 391 | 392 | $parent_domain['parent_domain_id'] = $data['new']['parent_domain_id']; 393 | $data['old'] = $parent_domain; 394 | $data['new'] = $parent_domain; 395 | 396 | $this->update($event_name, $data); 397 | } 398 | 399 | /** 400 | * Section for classic subdomains. 401 | * 402 | * This section is used for classic subdomains (non vhost subdomains). 403 | */ 404 | if ($data['new']['type'] == 'subdomain') { 405 | $parent_domain = $app->dbmaster->queryOneRecord('SELECT * FROM web_domain WHERE domain_id = '. intval($data['new']['parent_domain_id']) .''); 406 | 407 | $parent_domain['parent_domain_id'] = $data['new']['parent_domain_id']; 408 | $data['old'] = $parent_domain; 409 | $data['new'] = $parent_domain; 410 | 411 | $this->update($event_name, $data); 412 | } 413 | 414 | exec($final_command); 415 | 416 | if (isset($vhost_backup)) { 417 | $app->system->unlink($vhost_backup['file_new'].'~'); 418 | } 419 | 420 | unset($vhost_backup); 421 | $this->action = ''; 422 | } 423 | 424 | /** 425 | * ISPConfig delete hook. 426 | * 427 | * Called every time, a site get's removed. 428 | * 429 | * @uses update() 430 | * 431 | * @param string $event_name the event/action name 432 | * @param array $data the vhost data 433 | */ 434 | function delete($event_name, $data) { 435 | global $app, $conf; 436 | 437 | $this->action = 'delete'; 438 | 439 | $app->uses('getconf'); 440 | $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); 441 | 442 | if ($data['old']['type'] == 'vhost' || $data['old']['type'] == 'vhostsubdomain') { 443 | $this->vhost_helper('delete', $data); 444 | } 445 | 446 | if ($data['old']['type'] == 'alias') { 447 | $data['new']['type'] == 'alias'; 448 | $this->update($event_name, $data); 449 | } 450 | 451 | if ($data['old']['type'] == 'subdomain') { 452 | $data['new']['type'] == 'subdomain'; 453 | $this->update($event_name, $data); 454 | } 455 | } 456 | 457 | /** 458 | * ISPConfig client delete hook. 459 | * 460 | * Called every time, a client gets deleted. 461 | * 462 | * @uses vhost_helper() 463 | * 464 | * @param string $event_name the event/action name 465 | * @param array $data the vhost data 466 | */ 467 | function client_delete($event_name, $data) { 468 | global $app, $conf; 469 | 470 | $app->uses('getconf'); 471 | $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); 472 | 473 | $client_id = intval($data['old']['client_id']); 474 | $client_vhosts = array(); 475 | $client_vhosts = $app->dbmaster->queryAllRecords('SELECT domain FROM web_domain WHERE sys_userid = '. $client_id .' AND parent_domain_id = 0'); 476 | 477 | if (count($client_vhosts) > 0) { 478 | foreach($client_vhosts as $vhost) { 479 | $data['old']['domain'] = $vhost['domain']; 480 | $this->vhost_helper('delete', $data); 481 | 482 | $app->log('Removing vhost file: '. $data['old']['domain'], LOGLEVEL_DEBUG); 483 | } 484 | } 485 | } 486 | 487 | 488 | /** 489 | * ISPConfig internal debug function. 490 | * 491 | * Function for easier debugging. 492 | * 493 | * @param string $command executable command to debug 494 | */ 495 | private function _exec($command) { 496 | global $app; 497 | 498 | $app->log('exec: '. $command, LOGLEVEL_DEBUG); 499 | exec($command); 500 | } 501 | 502 | 503 | /** 504 | * Helps managing vhost config files. 505 | * 506 | * This functions helps to create/delete and link/unlink vhost configs on disk. 507 | * 508 | * @param string $action the event/action name 509 | * @param array $data the vhost data 510 | * @param mixed $tpl vhost template to proceed 511 | * 512 | * @return $data['vhost'] the vhost data 513 | */ 514 | private function vhost_helper($action, $data, $tpl = '') { 515 | global $app; 516 | 517 | $app->uses('system'); 518 | 519 | //* $VAR: location of nginx vhost dirs 520 | $nginx_vhosts = '/etc/nginx/sites-available'; 521 | $nginx_vhosts_enabled = '/etc/nginx/sites-enabled'; 522 | 523 | $data['vhost'] = array(); 524 | 525 | $data['vhost']['file_old'] = escapeshellcmd($nginx_vhosts .'/'. $data['old']['domain'] .'.vhost'); 526 | $data['vhost']['link_old'] = escapeshellcmd($nginx_vhosts_enabled .'/'. $data['old']['domain'] .'.vhost'); 527 | $data['vhost']['file_new'] = escapeshellcmd($nginx_vhosts .'/'. $data['new']['domain'] .'.vhost'); 528 | $data['vhost']['link_new'] = escapeshellcmd($nginx_vhosts_enabled .'/'. $data['new']['domain'] .'.vhost'); 529 | 530 | if (is_file($data['vhost']['file_old'])) { 531 | $data['vhost']['file_old_check'] = 1; 532 | } 533 | 534 | if (is_file($data['vhost']['file_new'])) { 535 | $data['vhost']['file_new_check'] = 1; 536 | } 537 | 538 | if (is_link($data['vhost']['link_old'])) { 539 | $data['vhost']['link_old_check'] = 1; 540 | } 541 | 542 | if (is_link($data['vhost']['link_new'])) { 543 | $data['vhost']['link_new_check'] = 1; 544 | } 545 | 546 | return $data['vhost'] = call_user_func( 547 | array( 548 | $this, 549 | "vhost_".$action 550 | ), 551 | $data, 552 | $app, 553 | $tpl 554 | ); 555 | } 556 | 557 | /** 558 | * Creates the vhost file and link. 559 | * 560 | * @param array $data the vhost data 561 | * @param object $app ISPConfig app object 562 | * @param mixed $tpl vhost template to proceed 563 | * 564 | * @return $data['vhost'] the vhost data 565 | */ 566 | private function vhost_insert($data, $app, $tpl) { 567 | global $app; 568 | 569 | $app->uses('system'); 570 | 571 | $app->system->file_put_contents($data['vhost']['file_new'], $tpl); 572 | 573 | $data['vhost']['file_new_check'] = 1; 574 | $app->log('Creating vhost file: '. $data['vhost']['file_new'], LOGLEVEL_DEBUG); 575 | unset($tpl); 576 | 577 | if ($data['vhost']['link_new_check'] != 1) { 578 | exec('ln -s '. $data['vhost']['file_new'] .' '. $data['vhost']['link_new']); 579 | $data['vhost']['link_new_check'] = 1; 580 | $app->log('Creating vhost symlink: '. $data['vhost']['link_new_check'], LOGLEVEL_DEBUG); 581 | } 582 | 583 | return $data['vhost']; 584 | } 585 | 586 | /** 587 | * Updates the vhost file and link. 588 | * 589 | * @uses vhost_delete() 590 | * @uses vhost_insert() 591 | * 592 | * @param array $data the vhost data 593 | * @param object $app ISPConfig app object 594 | * @param mixed $tpl vhost template to proceed 595 | * 596 | * @return the vhost data 597 | */ 598 | private function vhost_update($data, $app, $tpl) { 599 | global $app; 600 | 601 | $app->uses('system'); 602 | 603 | $data['vhost']['link_new_check'] = 0; 604 | 605 | if ($data['new']['active'] == 'n') { 606 | $data['vhost']['link_new_check'] = 1; 607 | } 608 | 609 | $data['vhost']['file_new_check'] = 0; 610 | 611 | $this->vhost_delete($data, $app); 612 | return $this->vhost_insert($data, $app, $tpl); 613 | } 614 | 615 | /** 616 | * Deletes the vhost file and link. 617 | * 618 | * @param array $data the vhost data 619 | * @param object $app ISPConfig app object 620 | * @param mixed $tpl vhost template to proceed 621 | */ 622 | private function vhost_delete($data, $app, $tpl = '') { 623 | global $app; 624 | 625 | $app->uses('system'); 626 | 627 | if ($data['vhost']['file_old_check'] == 1) { 628 | $app->system->unlink($data['vhost']['file_old']); 629 | $data['vhost']['file_old_check'] = 0; 630 | $app->log('Removing vhost file: '. $data['vhost']['file_old'], LOGLEVEL_DEBUG); 631 | } 632 | 633 | if ($data['vhost']['link_old_check'] == 1) { 634 | $app->system->unlink($data['vhost']['link_old']); 635 | $data['vhost']['link_old_check'] = 0; 636 | $app->log('Removing vhost symlink: '. $data['vhost']['link_old'], LOGLEVEL_DEBUG); 637 | } 638 | } 639 | 640 | 641 | /** 642 | * Helps managing SSL cert files. 643 | * 644 | * This functions helps to create/delete and link/unlink SSL cert files on disk. 645 | * 646 | * @param string $action the event/action name 647 | * @param array $data the vhost data 648 | * 649 | * @return $data['cert'] the cert data 650 | */ 651 | private function cert_helper($action, $data) { 652 | global $app; 653 | 654 | $app->uses('system'); 655 | 656 | $data['cert'] = array(); 657 | $suffix = 'nginx'; 658 | $ssl_dir = $data['new']['document_root'] .'/ssl'; 659 | 660 | $data['cert']['crt'] = escapeshellcmd($ssl_dir .'/'. $data['new']['ssl_domain'] .'.crt'); 661 | $data['cert']['bundle'] = escapeshellcmd($ssl_dir .'/'. $data['new']['ssl_domain'] .'.bundle'); 662 | $data['cert'][$suffix .'_crt'] = escapeshellcmd($ssl_dir .'/'. $data['new']['ssl_domain'] .'.'. $suffix .'.crt'); 663 | 664 | if (is_file($data['cert']['crt'])) { 665 | $data['cert']['crt_check'] = 1; 666 | } 667 | 668 | if (is_file($data['cert'][$suffix .'_crt'])) { 669 | $data['cert'][$suffix .'_crt_check'] = 1; 670 | } 671 | 672 | if (is_file($data['cert']['bundle'])) { 673 | $data['cert']['bundle_check'] = 1; 674 | } 675 | 676 | return $data['cert'] = call_user_func( 677 | array( 678 | $this, 679 | "cert_".$action 680 | ), 681 | $data, 682 | $app, 683 | $suffix 684 | ); 685 | } 686 | 687 | /** 688 | * Creates the ssl cert files. 689 | * 690 | * @param array $data the vhost data 691 | * @param object $app ISPConfig app object 692 | * @param string $suffix cert filename suffix 693 | */ 694 | private function cert_insert($data, $app, $suffix) { 695 | global $app; 696 | 697 | $app->uses('system'); 698 | 699 | if ($data['cert']['crt_check'] == 1) { 700 | if ($data['cert']['bundle_check'] == 1) { 701 | exec('(cat '. $data['cert']['crt'] .'; echo ""; cat '. $data['cert']['bundle'] .') > '. $data['cert'][$suffix .'_crt']); 702 | $app->log('Merging ssl cert and bundle file: '. $data['cert'][$suffix .'_crt'], LOGLEVEL_DEBUG); 703 | } else { 704 | $app->system->copy($data['cert']['crt'], $data['cert'][$suffix .'_crt']); 705 | $app->log('Copying ssl cert file: '. $data['cert'][$suffix .'_crt'], LOGLEVEL_DEBUG); 706 | } 707 | } else { 708 | $app->log('Creating '. $suffix .' ssl files failed', LOGLEVEL_DEBUG); 709 | } 710 | } 711 | 712 | /** 713 | * Changes the ssl cert files. 714 | * 715 | * @uses cert_delete() 716 | * @uses cert_insert() 717 | * 718 | * @param array $data the vhost data 719 | * @param object $app ISPConfig app object 720 | * @param string $suffix cert filename suffix 721 | */ 722 | private function cert_update($data, $app, $suffix) { 723 | global $app; 724 | 725 | $this->cert_delete($data, $app, $suffix); 726 | $this->cert_insert($data, $app, $suffix); 727 | } 728 | 729 | /** 730 | * Removes the ssl cert files. 731 | * 732 | * @param array $data the vhost data 733 | * @param object $app ISPConfig app object 734 | * @param string $suffix cert filename suffix 735 | */ 736 | private function cert_delete($data, $app, $suffix) { 737 | global $app; 738 | 739 | $app->uses('system'); 740 | 741 | if ($data['cert'][$suffix .'_crt_check'] == 1) { 742 | $app->system->unlink($data['cert']['nginx_crt']); 743 | $app->log('Removing ssl cert file: '. $data['cert'][$suffix .'_crt'], LOGLEVEL_DEBUG); 744 | } 745 | } 746 | 747 | } 748 | --------------------------------------------------------------------------------