Bei einem vServer kann man selbst wählen, welchen Webserver und welche Datenbanksysteme man verwenden möchte. Ich habe mich daher für Nginx mit PHP5-FPM, sowie MySQL und PostgreSQL entschieden. Um dies alles auf einem Server mit 256 MB RAM zu betreiben sind dann allerdings noch ein paar Modifikationen notwendig.
Zuerst werden die nicht benötigten Pakete entfernt:
1 2 3 |
sudo /etc/init.d/apache2 stop sudo /etc/init.d/samba stop sudo apt-get -y purge apache2 apache2-doc apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common samba-common samba |
Dann kann man die Paketquellen und Schlüssel hinzufügen:
1 2 |
sudo echo "deb http://packages.dotdeb.org squeeze all" > /etc/apt/sources.list.d/squeeze-dotdeb.list sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys --recv-key 89DF5277 |
Anschließend werden die Pakete installiert, wobei PHP-Module natürlich auch später noch nachinstalliert werden können:
1 2 |
sudo apt-get update sudo apt-get -y install nginx mysql-server postgresql php5 php5-fpm php-pear php-apc php5-common php5-mcrypt php5-mysql php5-pgsql php5-cli php5-gd php5-curl php5-xmlrpc |
PostgreSQL einrichten
Als erstes meldet man sich mit dem Systembenutzer postgres
bei PostgreSQL an und vergibt für den Datenbankbenutzer postgres
ein Passwort:
1 2 |
sudo -u postgres psql \password postgres |
Die PostgreSQL-Umgebung kann man anschließend mit \q
verlassen. Nun wird festgelegt, wer auf die Datenbanken zugreifen kann:
1 |
sudo vi /etc/postgresql/8.4/main/pg_hba.conf |
1 2 |
# "local" is for Unix domain socket connections only local all all md5 |
Zudem empfiehlt es sich, die Puffer-Größe anzupassen, sodass sie zum verfügbaren Arbeitsspeicher passt:
1 |
sudo vi /etc/postgresql/8.4/main/postgresql.conf |
1 |
shared_buffers = 16MB |
MySQL einrichten
Während der Installation des MySQL-Servers hat man bereits das Passwort des root-Nutzers festgelegt. Es empfiehlt sich außerdem, die Sicherheit der Installation zu verbessern, in dem man mysql_secure_installation ausführt:
1 |
sudo /usr/bin/mysql_secure_installation |
1 2 3 |
sudo /etc/init.d/mysql stop sudo rm /etc/mysql/my.cnf sudo vi /etc/mysql/my.cnf |
Basierend auf /usr/share/doc/mysql-server-5.5/examples/my-medium.cnf.gz
habe ich für MySQL dann die folgende Konfiguration eingerichtet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld] port = 3306 socket = /var/run/mysqld/mysqld.sock pid-file = /var/run/mysqld/mysqld.pid skip-external-locking key_buffer_size = 16M max_allowed_packet = 1M table_open_cache = 64 sort_buffer_size = 512K net_buffer_length = 8K read_buffer_size = 256K read_rnd_buffer_size = 512K myisam_sort_buffer_size = 8M log-bin=mysql-bin binlog_format=mixed server-id = 1 character-set-server=utf8 collation-server=utf8_general_ci skip-innodb default-storage-engine=MyISAM [mysqldump] quick max_allowed_packet = 16M [mysql] no-auto-rehash [myisamchk] key_buffer_size = 20M sort_buffer_size = 20M read_buffer = 2M write_buffer = 2M [mysqlhotcopy] interactive-timeout |
Um Arbeitsspeicher zu sparen, habe ich dabei unter anderem die Storage-Engine InnoDB deaktiviert. Anschließend kann man alle Dienste neustarten, an denen man Modifikationen durchgeführt hat:
1 2 3 4 |
sudo /etc/init.d/mysql restart sudo /etc/init.d/postgresql restart sudo /etc/init.d/php5-fpm restart sudo /etc/init.d/nginx restart |
PHP-FPM einrichten
Ist anschließend die RAM Nutzung zu hoch, so kann man die Voreinstellungen von PHP-FPM noch modifizieren:
1 |
sudo vi /etc/php5/fpm/pool.d/www.conf |
1 2 3 4 5 6 |
pm = dynamic pm.max_children = 3 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 pm.max_requests = 32 |
Danach ist es wieder notwendig, den Dienst neuzustarten:
1 |
sudo /etc/init.d/php5-fpm restart |
Nginx einrichten
Die Einstellungen in der Server-Konfigurationsdatei nginx.conf
sind die Grundlage für die namensbasierten Virtual Hosts. Ich habe mich hierbei an diesem Artikel von Sergej Müller orientiert:
1 2 |
sudo rm /etc/nginx/nginx.conf sudo vi /etc/nginx/nginx.conf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
user www-data; worker_processes 4; worker_rlimit_nofile 4096; pid /var/run/nginx.pid; # [ debug | info | notice | warn | error | crit ] error_log /var/log/nginx/error.log; #google_perftools_profiles /tmp/profile/; events { worker_connections 2048; # use [ kqueue | rtsig | epoll | /dev/poll | select | poll ] ; use epoll; multi_accept on; } http { server_names_hash_bucket_size 64; ## Size Limits client_max_body_size 10M; client_header_buffer_size 32k; client_body_buffer_size 128k; large_client_header_buffers 64 8k; ## Timeouts client_body_timeout 3m; client_header_timeout 3m; send_timeout 3m; #expires 24h; keepalive_timeout 120 120; ## General Options ignore_invalid_headers on; keepalive_requests 100; limit_conn_zone $binary_remote_addr zone=one:5m; recursive_error_pages on; sendfile on; server_name_in_redirect off; server_names_hash_max_size 512; server_tokens off; set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; ## TCP options #tcp_nopush on; tcp_nodelay off; #send_lowat 12000; include mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; log_format main '$remote_addr - $remote_user [$time_local] $status ' '\"$request\" $body_bytes_sent \"$http_referer\" ' '\"$http_user_agent\" \"http_x_forwarded_for\"'; ## Cache open_file_cache max=1000 inactive=24h; open_file_cache_valid 24h; open_file_cache_min_uses 2; open_file_cache_errors on; ## SSL Settings ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## Compression gzip on; gzip_static on; gzip_disable "MSIE [1-6]\.(?!.*SV1)"; gzip_buffers 16 8k; gzip_comp_level 6; gzip_http_version 1.1; gzip_min_length 0; gzip_proxied any; gzip_types text/plain text/css text/xml text/javascript application/json application/xml application/xml+rss application/x-javascript image/x-icon application/x-perl application/x-httpd-cgi application/javascript text/x-js font/ttf font/opentype application/vnd.ms-fontobject image/svg+xml; gzip_vary on; output_buffers 10 128k; postpone_output 1500; include /etc/nginx/sites-enabled/*.conf; } |
Anschließend kann man pro Domain oder Subdomain jeweils einen eigenen Document-Root-Ordner und eigene Konfigurationen anlegen:
1 2 3 |
sudo mkdir -p /var/www/domain.de/web sudo mkdir -p /var/www/domain.de/log sudo chown -R www-data:www-data /var/www |
Im Verzeichnis sites-available
legt man die Virtual-Host-Konfigurationen an und legt dann einen symbolischen Link darauf in sites-enabled
an:
1 2 |
sudo mkdir -p /etc/nginx/sites-available/ sudo mkdir -p /etc/nginx/sites-enabled/ |
Dies hat den Vorteil, dass man einzelne Konfigurationen aktivieren und deaktivieren kann:
1 2 |
sudo vi /etc/nginx/sites-available/domain.de.conf sudo ln -s /etc/nginx/sites-available/domain.de.conf /etc/nginx/sites-enabled/ |
Exemplarische Virtual-Host-Konfigurationen
Im folgenden ein paar einfache Konfigurationsbeispiele:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
server { listen 80 default_server; #listen [::]:80 default_server; server_name domain.de *.domain.de; root /var/www/domain.de/web; access_log /var/www/domain.de/log/access.log; error_log /var/www/domain.de/log/error.log; location / { index index.php index.html index.htm; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
server { listen 443 default_server ssl spdy; #listen [::]:443 default_server ssl spdy; server_name domain.de *.domain.de; ssl on; ssl_certificate /etc/ssl/certs/domain.de.pem; ssl_certificate_key /etc/ssl/private/domain.de.key; ssl_session_timeout 5m; ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # not possible to do exclusive ssl_ciphers 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA'; add_header Strict-Transport-Security max-age=31556926; # use this only if all subdomains support HTTPS! # add_header Strict-Transport-Security "max-age=31556926; includeSubDomains"; ssl_ecdh_curve secp384r1; ssl_dhparam /etc/nginx/ssl/group16.pem; ssl_session_cache shared:SSL:10m; root /var/www/domain.de/web; access_log /var/www/domain.de/log/access.log; error_log /var/www/domain.de/log/error.log; location / { index index.php index.html index.htm; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } |
1 2 3 4 5 6 7 8 |
server { listen 80; #listen [::]:80; server_name otherdomain.de *.otherdomain.de; #return 301 $scheme://domain.de$request_uri; return 302 $scheme://domain.de$request_uri; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
server { listen 80; #listen [::]:80; server_name download.domain.de; ## ROOT root /var/www/download.domain.de/web; ## LOGS access_log /var/www/download.domain.de/log/access.log; error_log /var/www/download.domain.de/log/error.log; # DEFAULT INDEX index index.php index.html index.htm; ## RESSOURCES location ~ \.(?:ico|png|jpe?g|css|js)$ { expires 31d; add_header Pragma "public"; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; #location ~ \.(?!ico).+$ { # valid_referers none blocked server_names ~(wpseo.|google.|yahoo.|bing.|facebook.|fbcdn.|pinterest.); # if ( $invalid_referer ) { # return 444; # } #} } ## PHP FILES #location ~ \.php$ { # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # include fastcgi_params; #} ## GZIP gzip_static on; ## CHARSET charset utf-8; ## INDEX LOCATION location / { ## Browser-Cache expires 1h; try_files $uri @rewrite; } ## REWRITE LOCATION location @rewrite { #return 301 $scheme://domain.de$request_uri; return 302 $scheme://domain.de$request_uri; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
server { listen 443 ssl spdy; #listen [::]:443 ssl spdy; server_name download.domain.de; ## SSL ssl on; ssl_certificate /etc/ssl/certs/domain.de.pem; ssl_certificate_key /etc/ssl/private/domain.de.key; ssl_session_timeout 5m; ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # not possible to do exclusive ssl_ciphers 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA'; add_header Strict-Transport-Security max-age=31556926; # use this only if all subdomains support HTTPS! # add_header Strict-Transport-Security "max-age=31556926; includeSubDomains"; ssl_ecdh_curve secp384r1; ssl_dhparam /etc/nginx/ssl/group16.pem; ssl_session_cache shared:SSL:10m; ## ROOT root /var/www/download.domain.de/web; ## LOGS access_log /var/www/download.domain.de/log/access.log; error_log /var/www/download.domain.de/log/error.log; # DEFAULT INDEX index index.php index.html index.htm; ## RESSOURCES location ~ \.(?:ico|png|jpe?g|css|js)$ { expires 31d; add_header Pragma "public"; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; #location ~ \.(?!ico).+$ { # valid_referers none blocked server_names ~(wpseo.|google.|yahoo.|bing.|facebook.|fbcdn.|pinterest.); # if ( $invalid_referer ) { # return 444; # } #} } ## PHP FILES #location ~ \.php$ { # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # include fastcgi_params; #} ## GZIP gzip_static on; ## CHARSET charset utf-8; ## INDEX LOCATION location / { ## Browser-Cache expires 1h; try_files $uri @rewrite; } ## REWRITE LOCATION location @rewrite { #return 301 $scheme://domain.de$request_uri; return 302 $scheme://domain.de$request_uri; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
server { ## INIT listen 80 default_server; #listen [::]:80 default_server; server_name domain.de *.domain.de; ## ROOT root /var/www/domain.de/web; ## LOGS access_log /var/www/domain.de/log/access.log; error_log /var/www/domain.de/log/error.log; # DEFAULT INDEX index index.php; ## SECURITY if ( $request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } location ~ /(\.|wp-config.php|liesmich.html|readme.html) { return 444; } ## REWRITES #location ~ ^/(\d+)/$ { # return 301 /?p=$1; #} ## RESSOURCES location ~ \.(?:ico|png|jpe?g|css|js)$ { expires 31d; add_header Pragma "public"; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; #location ~ \.(?!ico).+$ { # valid_referers none blocked server_names ~(wpseo.|google.|yahoo.|bing.|facebook.|fbcdn.|pinterest.); # if ( $invalid_referer ) { # return 444; # } #} } ## REDIRECT INDEX location / { try_files $uri $uri/ /index.php; } ## PHP FILES location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ## AUTH ADMIN location = /wp-login.php { #auth_basic "Restricted"; #auth_basic_user_file /var/www/domain.de/.htpasswd; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
server { ## INIT listen 80 default_server; #listen [::]:80 default_server; server_name domain.de *.domain.de; ## ROOT root /var/www/domain.de/web; ## LOGS access_log /var/www/domain.de/log/access.log; error_log /var/www/domain.de/log/error.log; # DEFAULT INDEX index index.php; ## SECURITY if ( $request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } location ~ /(\.|wp-config.php|liesmich.html|readme.html) { return 444; } ## REWRITES #location ~ ^/(\d+)/$ { # return 301 /?p=$1; #} ## RESSOURCES location ~ \.(?:ico|png|jpe?g|css|js)$ { expires 31d; add_header Pragma "public"; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; #location ~ \.(?!ico).+$ { # valid_referers none blocked server_names ~(wpseo.|google.|yahoo.|bing.|facebook.|fbcdn.|pinterest.); # if ( $invalid_referer ) { # return 444; # } #} } ## PHP FILES location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ## AUTH ADMIN location = /wp-login.php { #auth_basic "Restricted"; #auth_basic_user_file /var/www/domain.de/.htpasswd; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ## GZIP gzip_static on; ## CHARSET charset utf-8; ## INDEX LOCATION location / { if ( $query_string ) { return 405; } if ( $request_method = POST ) { return 405; } if ( $request_uri ~ /wp-admin/ ) { return 405; } if ( $http_cookie ~ (wp-postpass|wordpress_logged_in|comment_author)_ ) { return 405; } error_page 405 = @nocache; ## Browser-Cache expires 1h; try_files /wp-content/cache/cachify/${host}${uri}index.html @nocache; } ## NOCACHE LOCATION location @nocache { try_files $uri $uri/ /index.php?$args; } } |
Zur Aktivierung von IPv6 kommentiert man einfach die Listen-Direktiven mit ipv6only=on
ein. Nach einem Neustart von Nginx sollte die Seite dann unter der entsprechenden Domain verfügbar sein:
1 |
sudo /etc/init.d/nginx restart |
Hat man die Virtual-Host-Konfiguration abgeschlossen, so kann man sofort loslegen und Dateien in den Document-Root-Ordner legen oder beispielsweise eine Datenbank in MySQL anlegen und WordPress konfigurieren.
Links
- HowtoForge: Installing Nginx With PHP5 (And PHP-FPM) And MySQL Support (LEMP) On Ubuntu 12.04 LTS
- Web Hosting Talk: nginx + php-fpm + debian squeeze tutorial – the fastest way to host php
- ubuntuusers.de Wiki: MySQL
- ubuntuusers.de Wiki: PostgreSQL
- Reducing MySQL Memory Usage for Low End Boxes
- Nginx and PHP-FPM Configuration and Optimizing Tips and Tricks
- MySQL 5.5 Reference Manual: mysql_secure_installation – Improve MySQL Installation Security
- WordPress auf Nginx: Performance und Sicherheit optimieren
- Nginx Webserver und MySQL für WordPress konfigurieren
- SUCKUP.de: Nginx + PHP5-fpm auf Debian/Ubuntu
- BetterCrypto.org: Applied Crypto Hardening [PDF]