This is a config "template" I am using right now:
server {
server_name {:primaryDomain};
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/{:primaryDomain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{:primaryDomain}/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root {:siteRoot};
index index.php index.html;
recursive_error_pages off;
error_page 403 = /HTTP_ERRORS/403.html;
error_page 404 = /HTTP_ERRORS/404.html;
error_page 500 = /HTTP_ERRORS/500.html;
location ^~ /HTTP_ERRORS/ {
alias {:sharedHtmlRoot}/;
internal;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location /manage {
root {:siteRoot}/manage;
try_files $uri $uri/ /manage/index.php?$query_string;
}
location ~* \.php$ {
fastcgi_pass unix:/run/php/php{:phpVer}-fpm-{:user}.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location /assets/ {
alias /public/assets/;
}
}
server {
server_name {:primaryDomain} www.{:primaryDomain};
listen 80;
return 301 https://{:primaryDomain}$request_uri;
}
server {
server_name www.{:primaryDomain};
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/{:primaryDomain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{:primaryDomain}/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
return 301 https://{:primaryDomain}$request_uri;
}
Notice the {:keywords}. These are strings that I replace with a script that is generating the nginx final config.
It works fine, but I have around 300 websites and the script will generate 300 of these configs using this template, so the final nginx .conf file is quite large.
Could I use a single nginx config for all sites somehow?
Here is a all in one configuration i have verified with nginx/1.18.0, but still need to generate a domain list file /etc/nginx/mydomains
/etc/nginx/sites-enabled/default
map $http_host $vhost_config {
hostnames;
default "";
include /etc/nginx/mydomains;
}
map $vhost_config $vhost_root {
default "";
~^([^:]+):([^:]+):([^:]+)$ $1;
}
map $vhost_config $php_version {
default "";
~^([^:]+):([^:]+):([^:]+)$ $2;
}
map $vhost_config $php_user {
default "";
~^([^:]+):([^:]+):([^:]+)$ $3;
}
map $ssl_server_name $my_cert_name {
default "";
~^(www\.)?(.+)$ $2;
}
server {
listen 80 default_server;
listen 443 ssl default_server;
ssl_certificate /etc/letsencrypt/live/$my_cert_name/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$my_cert_name/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
server_name ~^(?<www>(www\.)?)(?<domain>.+)$;
recursive_error_pages off;
error_page 403 = /HTTP_ERRORS/403.html;
error_page 404 = /HTTP_ERRORS/404.html;
error_page 500 = /HTTP_ERRORS/500.html;
location ^~ /HTTP_ERRORS/ {
alias {:sharedHtmlRoot}/;
internal;
}
# redirect www.abc.com to abc.com
if ($www != '') {
return 301 https://$domain$request_uri;
}
# redirect http to https
if ($scheme = 'http') {
return 301 https://$domain$request_uri;
}
# if domain not exist in mydomains, return 404
if ($vhost_root = '') {
return 404;
}
root $vhost_root;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location /manage {
root $vhost_root/manage;
try_files $uri $uri/ /manage/index.php?$query_string;
}
location ~* \.php$ {
fastcgi_pass unix:/run/php/php$php_version-fpm-$php_user.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location /assets/ {
alias /public/assets/;
}
}
content of /etc/nginx/mydomains
# domain.name "<site root>:<php version>:<php user>";
abc.com "/var/www/html/abc:7.4:user1";
efg.com "/var/www/html/efg:7.0:user2";
notes
Nginx support using variable in ssl_certificate directive since 1.15.9, and $ssl_server_name was introdued in nginx/1.70. Because http variable $http_host will not be initialized until the https connection is established, $ssl_server_name is not replace able in this configuration.
You could replace {:sharedHtmlRoot} in server block with your real path.
The all in one server block is delared as a default block, if there's already a default server block in your nginx configuration, you need to overwrite the old one.
Related
I know that there's a lot of similar questions here, but none of them didn't help me, so here's my problem.
I need to redirect all requests from my server ip to my domain.
I tried the return 301 method, it kinda worked, but got me "Too many redirects error".
It wasn't me who wrote the config originally and I'm afraid to break it, it's a live server, so I don't have much time to test things.
Here's my config:
server {
listen xxx.xxx.xxx.xxx:443 ssl;
index index.php;
server_name example.com;
error_log /var/log/nginx/error_example_com.log;
access_log /var/log/nginx/access_example_com.log;
root /var/www/prod/frontend/web;
client_max_body_size 50m;
ssl on;
ssl_certificate /var/lib/dehydrated/certs/example.com/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/example.com/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1.2;
ssl_ciphers EECDH:+AES256:-3DES:RSA+AES:RSA+3DES:!NULL:!RC4;
add_header Strict-Transport-Security "max-age=31536000";
ssl_prefer_server_ciphers on;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location /images {
alias /var/www/prod/frontend/web/images;
}
location /assets {
expires 1d;
}
location /upload {
expires 1d;
alias /var/www/prod/frontend/web/uploads;
}
location /plugins/Global/scripts {
alias /var/www/prod/frontend/web/js2;
}
location /plugins/Global/images {
alias /var/www/prod/frontend/web/images;
}
location /plugins/Global/css {
alias /var/www/prod/frontend/web/css;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/comn/php/php7.3-fpm.sock;
}
location /.well-known/acme-challenge {
alias /var/lib/dehydrated/acme-challenges;
}
}
server {
listen 443 ssl;
ssl_certificate /var/lib/dehydrated/certs/example.com/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/example.com/privkey.pem;
server_name www.example.com;
location / {
return 301 https://example.com$request_uri;
}
location ~ /.git/ {
deny all;
}
}
server {
listen xxx.xxx.xxx.xxx:80;
location / {
return 301 https://example.com$request_uri; # enforce https
}
location /.well-known/acme-challenge {
alias /var/lib/dehydrated/acme-challenges;
}
}
Redirecting from http://xxx.xxx.xxx.xxx to https://example.com works just fine, but I can't figure out how to get https redirecting working. What am I missing?
Also there's an admin panel to this site, it's config stored in another file, not sure if it has to be posted as well.
Strangely adding this on top of my config worked, where even default_server was ignored..
server {
listen 443 ssl http2;
server_name example.com;
return 301 https://example.com$request_uri;
}
Still not sure what is wrong with my setup, but at least it's working now.
nginx/1.14.2
Hi there!
I'am trying to configure Nginx for 2 yii projects, frontend for users and admin for admins with only one domain (no sub domain). I need to configure it in a way such that mydomain.com should refer to frontend and mydomain.com/admin to admin. The problem is I'am being able to configure only one of them at a time, meaning I can use frontend or admin not both of them.
What I have tried
front.conf
server {
listen 80;
server_name api.maim.experiments.uz;
return 301 https://$server_name$request_uri;
}
server {
charset utf-8;
client_max_body_size 128M;
listen 443 ssl;
ssl_certificate_key privkey.pem;
ssl_certificate fullchain.pem;
ssl_protocols TLSv1.2;
set $host_path "/home/itschool/inha_dev/frontend";
server_name api.maim.experiments.uz;
root $host_path/web;
set $yii_bootstrap "index.php";
access_log /var/log/nginx/itschool-access.log;
error_log /var/log/nginx/itschool-error.log;
location / {
index index.html $yii_bootstrap;
try_files $uri $uri/ /index.php;
}
location ~ ^/(protected|framework|themes/\w+/views) {
deny all;
}
location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
try_files $uri =404;
}
location ~ \.php$ {
set $fsn /index.php;
if (-f $document_root$fastcgi_script_name){
set $fsn $fastcgi_script_name;
}
fastcgi_pass 127.0.0.1:9002;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fsn;
}
location ~ /\.(ht|svn|git) {
deny all;
}
location ~* /\. {
deny all;
access_log off;
log_not_found off;
}
}
back.conf
server {
listen 80;
server_name api.maim.experiments.uz;
return 301 https://$server_name$request_uri;
}
server {
charset utf-8;
client_max_body_size 128M;
listen 443 ssl;
ssl_certificate_key privkey.pem;
ssl_certificate fullchain.pem;
ssl_protocols TLSv1.2;
set $host_path "/home/itschool/inha_dev/backend";
server_name api.maim.experiments.uz;
root $host_path/web;
set $yii_bootstrap "index.php";
access_log /var/log/nginx/itschool-access.log;
error_log /var/log/nginx/itschool-error.log;
location ^~ /admin {
alias /home/itschool/inha_dev/backend/web;
if (!-e $request_filename) { rewrite ^ /admin/index.php last; }
location ~ \.php$ {
if (!-f $request_filename) { return 404; }
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass 127.0.0.1:9002;
}
}
location ~ /\.(ht|svn|git) {
deny all;
}
location ~* /\. {
deny all;
access_log off;
log_not_found off;
}
}
I found some questions with answers but they didn't work for me, please help.
I have recently use similar configuration to support web application / mobile application and admin panel on single domain
I hope this could help you out. Below is the configuration
server {
listen 80;
set $root /var/www/html/application;
#here we go
#if backend not found in url then set root url
if ($uri !~ "^(.*)/(backend)(.*)") {
set $root /var/www/html/application/frontend/web;
}
# when request is coming from mobile then display mobile site
# you don't need this one, I just written in order to explain the mobile application navigation.
if ($http_user_agent ~* "android|blackberry|googlebot-mobile|iemobile|ipad|iphone|ipod|opera mobile|palmos|webos") {
set $root /var/www/html/application/mobile/web;
}
root $root;
index index.php index.html index.htm index.nginx-debian.html;
server_name your_domain;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}
location / {
index index.html index.php;
if (!-e $request_filename){
rewrite ^/(.*) /index.php?r=$1 last;
}
}
location ~ /\.ht {
deny all;
}
}
Also have a look in official document of Yii2 to setup yii2-app-advanced on single domain (Apache, Nginx).
CLICK HERE
One more thing that you need to know is if you want to change backend/web to admin then you also have to made some changes in Yii2 application.
One domain will lead all requests to one IP (server). Nginx will use the first server block matching server_name https://nginx.org/en/docs/http/request_processing.html so you need to put all configuration on one file and use location to separate them.
You can move location ^~ /admin at the beginning of the front.conf locations and play with roots;
Or you can create a proxying config file that will contain just a little.
Something like that
location /admin {
proxy_pass http://localhost:8001;
}
location / {
proxy_pass http://localhost:8002;
}
Using the latter one you should change front & back configs to listen to other ports. Also, an SSL certificate was given for a domain, not URL. So you can use it only in the proxying config.
If you follow some of the key instructions from option 1 of Yii2 Single Domain Apache and Nginx you should be able to accomplish what you want.
Per the referenced link, Option 1:
Assuming Linux OS
cd /path/to/project/frontend/web
ln -s ../../backend/web backend
and set your nginx file
server {
charset utf-8;
client_max_body_size 128M;
listen 80; ## listen for ipv4
#listen [::]:80 default_server ipv6only=on; ## listen for ipv6
server_name api.maim.experiments.uz;
root /home/itschool/inha_dev/frontend/web;
index index.php;
access_log /var/log/nginx/itschool-access.log;
error_log /var/log/nginx/itschool-error.log;
location / {
# Redirect everything that isn't a real file to index.php
try_files $uri $uri/ /index.php$is_args$args;
}
# uncomment to avoid processing of calls to non-existing static files by Yii
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
#error_page 404 /404.html;
# deny accessing php files for the /assets directory
location ~ ^/assets/.*\.php$ {
deny all;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;
}
location ~* /\. {
deny all;
}
}
Not: See below link for the Option-2, if the above does not work:
Yii2 Single Domain Apache and Nginx
I want to deny access to few directories, as well as all sub-directories and files, including JS/CSS files.
I have this configuration, and it works for the most part, but it doesn't deny access to .js file I have.
server {
listen 80;
server_name DOMAIN www.DOMAIN;
root /home/me/www/app;
index index.php index.html index.htm;
autoindex on;
client_max_body_size 20m;
fastcgi_read_timeout 600;
#Forbid access to these directories
location ~ /(data|dev|py)/ {
deny all;
return 403;
}
#Force download on PDF files
location ~* /(.*\.pdf) {
types { application/octet-stream .pdf; }
default_type application/octet-stream;
}
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
}
#API
location /api/v1/ {
index index.php;
try_files $uri $uri/ /api/v1/index.php?$args;
}
#php support
location ~ [^/]\.php(/|$) {
include /etc/nginx/conf.d/php_generic;
fastcgi_param DOCUMENT_ROOT /home/me/www/site1;
fastcgi_pass unix:/var/run/php/php-fpm-me.sock;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
error_log /home/me/logs/error.log;
access_log /home/me/logs/access.log;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/DOMAIN/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/DOMAIN/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
Any ideas?
EDIT / RESOLVED
Well, the website is behind CloudFlare, so after 30 minutes of pulling my hair off, link is no longer accessible, which tells me that CloudFlare had it cached and served it, even tho nginx config was changed.
I have an issue as given below.
Say I have a site example.com and I have made modifications to the rewrite logic to remove .php extensions. The code given below works fine in all the cases except for index.php
https://example.com --> Not accessible. This is not correct. It should display contents from index.php page.
https://example.com/index.php --> Displays 404 page. This is correct.
https://example.com/index --> Displays index page. This is not correct.
server {
root /usr/share/nginx/html;
# Add index.php to the list if you are using PHP
index index.php index.html index.htm;
server_name example.com www.example.com;
error_page 404 /error/custom_404;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
index index.php index.html index.htm;
try_files $uri $uri/ #missing;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
expires 365d;
}
location ~* (\.php$|myadmin) {
return 404;
}
location #missing {
if (!-f $document_root$uri.php) { return 404; }
fastcgi_param SCRIPT_FILENAME "$document_root$uri.php";
fastcgi_param PATH_TRANSLATED "$document_root$uri.php";
fastcgi_param QUERY_STRING $args;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~* \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}server {
if ($host = www.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 404; # managed by Certbot
}
Can someone point to where I am doing wrong?
Thanks
Is it possible to optimize/minimize the config posted below?
I feel that it should be possible to merge all the redirects into something more simple.
http:// & http://www & https://www > https://
Though I've had issues and settled.
I understand variables are not supported in NGINX config, so I have to manually define the log locations for example. Would there be a way to set a default location for all vhosts?
I use the same ssl-params.conf file for all vhosts. Can this be defaulted and disabled on a per-vhost basis?
# Redirect http:// & http://www to https://
server {
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# Redirect https://www to https://
server {
listen 443 ssl;
server_name www.example.com;
return 301 https://example.com/$request_uri;
}
# Main config
server {
listen 443 ssl;
server_name example.com;
# SSL config
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
# Error logs
access_log /srv/logs/nginx.access.example.com.log;
error_log srv/logs/nginx.error.example.com.log;
# Root dir
location / {
root /srv/example.com/_site/;
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
}
# Caching
location ~ .php$ {
root /srv/example.com/_site/;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
root /srv/example.com/_site/;
expires 365d;
}
location ~* \.(pdf)$ {
root /srv/example.com/_site/;
expires 30d;
}
# SSL
location /.well-known {
allow all;
}
}
I understand variables are not supported in NGINX config, so I have to manually define the log locations for example. Would there be a way to set a default location for all vhosts?
Yes, just define it in the http context of your config or stick with the default of your distro (e.g. /var/log/nginx/access.log).
I use the same ssl-params.conf file for all vhosts. Can this be defaulted and disabled on a per-vhost basis?
It works the other way around you enable it where you need it through the include directive.
Here is a shorter config (untested):
http {
error_log /srv/logs/nginx.error.example.com.log;
access_log /srv/logs/nginx.access.example.com.log;
index index.php index.html index.htm;
server {
listen 80;
listen 443 ssl;
server_name .example.com;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
root /srv/example.com/_site/;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
location / {
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
}
location ~* \.(jpe?g|png|gif|ico|css|js)$ {
expires 365d;
}
location ~* \.(pdf)$ {
expires 30d;
}
try_files $uri $uri/ /index.php?$args;
}
location /.well-known {
allow all;
}
}
}