I have a Synology DSM set up for home hosting, and I've been trying to play around with it. My current goal is to assign subdomains to specific services, e.g. the DSM Admin panel, SickBeard, etc.
The only problem with this is the way how Synology manages its services. Some of them are simply webhost-based (and put into the /var/services/web/ folder in their own subfolder), and some of them are running on separate ports (e.g. Sickbeard runs on port 8083, while the admin panel runs on port 5000).
The results are want are quite simple: redirect set subdomains (see below) to these ports, WITHOUT displaying the ports.
admin.fonix232.net -> fonix232.net:5000
sb.fonix232.net -> fonix232.net:8083
home.fonix232.net -> fonix232.net:8085
etc.
I've set up a simple mod_rewrite rule for the subdomain admin.fonix232.net, in the following way (in httpd-vhost.conf-user):
<VirtualHost *:*>
ServerName admin.fonix232.net
RewriteEngine on
RewriteCond %{HTTP_HOST} admin\.fonix232\.net [NC]
RewriteRule ^/(.*)$ http://fonix232.net:5000/$1 [P,QSA,L]
</VirtualHost>
It works fine, except it does not rewrite the port - it stays 5000, but at least on the subdomain.
How could I remove it?
Solution was pretty simple, I had to use mod_proxy and mod_proxy_http.
Thanks to the way how Synology built its Apache system (three separate services for system/webman, user and webdav), the best solution was to create a new config file and extend the existing by slightly modifying the startup script to import that too (for some mysterious reasons, any kind of manual addition to config files gets erased as soon as someone edits the settings from webman).
So after that, I had to create separate VirtualHosts for the separate services I wanted to redirect, the following way:
<VirtualHost *>
ServerName [full subdomain you want to redirect to]
ProxyRequests On
ProxyPreserveHost On
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / [target address and port you want to reach]
ProxyPassReverse / [target address and port you want to reach]
<Location />
Order allow,deny
Allow from all
</Location>
While most of the tutorials show that ProxyRequests should be Off, for me it never worked that way, only by enabling it.
Now one thing remains, the exact reverse. Meaning, if port X is called from *.domain.tld, no matter which, drop me on the assigned subdomain.domain.tld. Harder nut to crack, but getting there.
Related
My team's server is set up in such as way: We have one domain name, which seems like already a subdomain of the company's domain. We want to host multiple applications under this one domain. We'd even like to have a production version and staging version for each of the apps on the server.
Document root is an empty folder. Applications sit outside of the document root.
we are trying to use the first token in the URL path to find out which app we try to access, then somehow redirect to it (internally or externally).
Here is a structure equivalent to how the directories are organized.
/usr/local/var/www <- Document Root
/usr/local/var/app1 <- application 1
------------------/public/index.php
------------------/public/css
/usr/local/var/app2 <- application 2
/usr/local/var/app1.stg <- application 1 staging version, code is exactly the same as application1
/usr/local/var/app2.stg <- application 2 staging version, code is exactly the same as application2
Here are the relevant settings in httpd.conf
DocumentRoot /usr/local/var/www
<Directory "/usr/local/var/www">
AllowOverride None
Require all granted
</Directory>
Alias "/app1" "/usr/local/var/app1"
Alias "/app2" "/usr/local/var/app2"
<VirtualHost *:80>
# rewriting rules to make the routing work
# There is only one vhost so it can actually be removed
</VirtualHost>
When we access https://sub.domain.com/app1, we expect to go to app1
When we access https://sub.domain.com/app1.stg, we expect to go to app1.stg
The applications are written in PHP. This server configuration means we have to include the "path to the application" in the routes and rewrite rules, and use the "full absolute path" in all the resource references.
For example, a route will look like
$router->map("GET", "/app1/action", SomeController);
A css reference will be: (even though relative path is given, it behaves just like a relative path to the DocRoot (with "/" in front). You can see it in this detailed post)
<link href="app1/public/css/style.css" type="text/css" rel="stylesheet"/>
These will be sufficient to make both apps work, but the staging version is not going to work, because it contains EXACTLY THE SAME copy of code (which is how it's intended to be, to test out in staging environment, then push to production environment).
If I want both versions to work, I have to code the paths dynamically, namely using CONTEXT_DOCUMENT_ROOT or some other server variable to figure out which app version it's in, and have two copies of routes, one starting with app1, the other app1.stg. I also have to have separate rewriting rule for each version.
QUESTION
With the server setup restriction applied (one domain name, distinguish apps with the way I described, etc..), is it possible to use only relative paths, write routes with respective to only the app itself? Some like:
<link href="css/style.css" type="text/css" rel="stylesheet"/>
$router->map("GET", "/action", SomeController);
In other words, I have to change the server setup within the constraints, so that the app can be written in a way without caring how the server is set up.
I know one way is to use different ports for each app/version, but apparently the server admin doesn't like the idea.
I've broken down the problem into steps in this question. It's quite long but if you are willing to follow through, it should provide much more details.
If the question is not clear enough, the per-user directory looks quite like what I want to achieve. But instead of user directory, I want the app directory in place of it. Of course I never used per-user directory so I dont know if it actually behaves the way I think it does.
So I understand that we can have multiple hostnames in /etc/hosts mapped to one IP address. Can I just use that hostname as the ServerName in apache config, and access in the browser by typing that hostname? The website is for internal usage so should only be accessed within company's network.
In /etc/hosts:
123.45.67.89 app1.team-server-name app2.team-server-name
In httpd.conf:
<VirtualHost>
ServerName app1.team-server-name
DocumentRoot /usr/local/var/app1/public
</VirtualHost>
<VirtualHost>
ServerName app2.team-server-name
DocumentRoot /usr/local/var/app2/public
</VirtualHost>
This is quite the lengthy question, thank you for providing so much detail.
I would opt for a different approach than you are currently attempting. Instead of trying to serve each of these applications out of a folder, set up each of them as a domain based vhost. Use something like app1.local or whatever for the hostname and be sure to add the entries to your /etc/hosts file under 127.0.0.1. Make sure the listen directive for these vhosts is on the loopback (127.0.0.1:80). Each of these apps should function as if they were installed at the document root of their own server. All the CSS should assume its at 'css/style.css' relative to /.
Now that you have all of the apps setup on the loopback, you can setup a reverse proxy from the vhost listening on the public interface to proxy all of the application locations to their appropriate loopback vhost after you remove the /app1 prefix from the request.
I haven't used Apache 2.x for a very long time, but the concepts are the same as nginx.
location /foo {
rewrite /foo/(.*) /$1 break;
proxy_pass http://app1.local;
proxy_redirect off;
proxy_set_header Host $host;
}
The biggest issue with this approach is that the applications that are being proxied either need to use relative paths everywhere, or they need to have some kind of configurable prefix that is prepended to the urls. Most frameworks will support the prefix option. For Example: https://laravel.com/docs/5.6/urls This prefix can be used for asset (css/js/jpg) loading as well, but only from files that execute PHP.
I end up finding a solution with one compromise.
DocumentRoot "/usr/local/var/www"
Alias /app1 /usr/local/var/app1/public
<Directory "/usr/local/var/www">
RewriteEngine On
RewriteRule ^/?$ /app1/ [R,L]
RewriteRule (.*) /app1/$1 [R,L]
</Directory>
<VirtualHost *:80>
<Directory "/usr/local/var/app1">
Require all granted
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# calls index.php (REQUEST_URI is still the same as before)
RewriteRule ^ index.php [L]
</Directory>
</VirtualHost>
All relative paths can be rewritten normally.
Routes and requests will need to start with app name.
$router->map("GET", "/app1/hello2", SomeController);
// navigation bar. URI for another tab:
<li>Hello 2</li>
If we want to have multiple versions of the app, the main thing to do is to know which version we are in so the app can send the correct request uri. This can be done by checking the REQUEST_URI and remember which version is being called when index.php is called up. Then in the request (e.g. navigation src), append it in front of the action.
There are different ways to do this, such as writing your html templates in php, so you can access php variables. I used twig so I can pass the value to the twig templates from php. But I still don't like to have all these stuff in my static code, so I decided to just get rid of the staging version.
If the project is serious enough to require a staging version, then a better suitable environment should be provided.
I have this strange problem that I can best describe as "namespace leakage". I have setup a vagrant box running Apache2 with VHosts setup to replicate the production server in terms of domains & sub domains. I have edited my local machine's hosts file accordingly, and my VHosts work fine.
I have also created a skeleton/base app coded with PhalconPHP. It's a multi modular app with all the generic features I require to develop my apps (actually redevelop a load of very old, outdated apps). The skeleton app works fine.
The problem I have is that if I go to app1.dev in my browser, it works. Then if I go to app2.dev, app2 is clearly trying to load some components - views etc from app1 and is giving errors. However, close the browser and try again by going to app2.dev and it now works fine. Then go to app1.dev and that is now broken and trying to load components from app2! I managed to track this odd behaviour down to namespace collision.
It has to be namespace collision because my apps are all based on the skeleton app and use it's name spaces, which are obviously the same for generic parts of the app - modules such as App\backend, App\frontend etc. If on a broken app, I navigate in my browser to a part of that app that is unique, and therefore has a unique namespace, it works fine because there is no collision! Also a couple of apps are coded with Codeigniter3 which does not use namespaces, and those apps do not have this issue. It only effects the Phalcon apps with namespaces.
I will add that each app uses .htaccess to direct requests to the front controller located in public/ directory.
Options FollowSymLinks
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
</IfModule>
I wondered if the .htaccess was the issue, but I think I've ruled that out. It is doing what it is supposed to do.
Here's an example of one of my VHost settups in apache - they all follow this pattern.
<VirtualHost *:80>
ServerName app1.dev
ServerAlias www.app1.dev
DocumentRoot /vagrant/www/app1
<Directory "/vagrant/www/app1">
Options Indexes Followsymlinks
AllowOverride All
Order allow,deny
Allow from All
Require all granted
</Directory>
</VirtualHost>
Changing all the namespaces throughout every app would be a pretty major job, and I don't think that should be necessary. I don't think this should be an issue on the production server as that uses CloudLinux/Centos & WHM, but it is a bit of a worry!
Clearly namespaces should not collide across different document routes and VHosts right? What am I missing?
I have solved similar problem in Apache using different local IP's for every app:
/etc/hosts
127.1.0.1 edu.l
127.1.1.1 tech.l
...
/etc/apache2/sites-available/001-blogs.conf
<VirtualHost edu.l:80>
ServerName edu.l
ServerAdmin webmaster#localhost
DocumentRoot /var/www/blog/edu
ErrorLog ${APACHE_LOG_DIR}/edu.error.log
CustomLog ${APACHE_LOG_DIR}/edu.access.log combined
</VirtualHost>
<VirtualHost tech.l:80>
ServerName tech.l
ServerAdmin webmaster#localhost
DocumentRoot /var/www/blog/tech
ErrorLog ${APACHE_LOG_DIR}/tech.error.log
CustomLog ${APACHE_LOG_DIR}/tech.access.log combined
</VirtualHost>
...
You can ommit configuring names in hosts ans use IP's in .conf tho.
It works because if you define few apps on same IP and port, Apache seems to remember directory it is working on and mismatching files.
all. So I'm running Apache 2.2. I have a single VirtualHost that's used for a Django application (by way of mod_wsgi) as well as a PHP one that lives in a subdirectory. Normally, this is no problem. You can just Alias /subdir /path/to/phpapp followed by WSGIScriptAlias / /path/to/django.wsgi.
But, the complication is that this PHP application uses mod_rewrite to implement "Fancy URLs," which just means that '/subdir/foo/bar' will get rewritten to something like '/subdir/index.php?path=foo/bar'.
Here's my configuration:
<VirtualHost *:80>
ServerName [snip]
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
Alias /phpapp/ /home/ubuntu/phpapp/
<Directory /home/ubuntu/phpapp>
Order allow,deny
Allow from all
RewriteEngine on
RewriteCond $1 !^(index\.php|img|bin)
RewriteRule ^(.*)$ index.php?__dingo_page=$1 [PT]
</Directory>
WSGIDaemonProcess foo user=ubuntu
WSGIProcessGroup foo
WSGIScriptAlias / /home/ubuntu/djangoapp/apache/django.wsgi
<Directory /home/ubuntu/djangoapp/apache>
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
The problem is that whenever a rewrite takes place (e.g., I try to go to /phpapp or /phpapp/foo) the request gets handled by WSGI and I see my Django site's 404 page. If the address passes through (e.g., I go to /phpapp/index.php) then it is handled by PHP and works normally. I thought maybe that adding the [PT] flag to my RewriteRule would fix this problem, but it doesn't seem to have any effect on which handler is chosen. I've also tried SetHandler application/x-httpd-php in the Directory section for the PHP app.
I need the Django application to continue to handle any URLs that aren't specifically aliased to something else. There must be a way to make this work! Thanks.
Using /phpapp wouldn't ever work because you have a trailing slash on that path for the Alias directive. Use:
Alias /phpapp /home/ubuntu/phpapp
By rights that Alias directive should then take precedence over WSGIScriptAlias for the sub URL.
I would suggest you enable logging by mod_rewrite and verify what the URL is being written to. So long as the rewritten URL still sits below /phpapp, it should be fine.
The alternative is to not use WSGIScriptAlias, but use the scheme as outline towards the end of:
http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines#The_Apache_Alias_Directive
That allows you to set things up so that the Python web application will only be used as a fallback if no static resource, including PHP, could be mapped.
I have a bunch of subdomains in one single server:
a.example.com
b.example.com
news.example.com
All of them are in the same Apache virtualhost.
I need to use a feed provided by the news subdomain inside the a and b subdomain. The feeds typically look like this:
news.example.com/news/a
news.example.com/news/b
On the a and b subdomains, I'm using jquery's ajax function to load the data from the news feeds, and present it on a and b. This initially didn't work, because of the same-origin policy.
I was able to override this by adding the Access-Control-Allow-Origin "*" to my Apache config file.
... but this works only in Firefox, Chrome and Safari. Internet explorer seems to ignore that directive.
Thus, I need to create a proxy.
What I need is a new directory in all my subcomains (for example /proxy) that Apache detects, and redirects to news.example.com, no matter what the subdomain. So:
a.example.com/proxy/news/a -> return the contents of news.example.com/news/a
b.example.com/proxy/news/b -> return the contents of news.example.com/news/b
Can I do this directly in Apache + submodules (for example, mod_rewrite), or do I need to use a scripting language like PHP for doing this?
You want the ProxyPass Directive.
ProxyPass /proxy/news/a http://news.example.com/news/a
At the end we were able to make the proxy using a combination of two modules: mod_rewrite and mod_proxy.
The syntax was the following:
rewriteEngine on
rewriteRule proxy/(.+)$ http://news.example.com/$1 [P]
The [P] at the end is telling the rule "act as a proxy" and doesn't work without mod_proxy. Without it, apache makes a "redirect" (the url at the top of the page changes) instead of "just serving the page".
Apache can be configured to use apache:
consider this working sample code (proxy part):
<VirtualHost *:80>
ServerAdmin webmaster#localhost
ServerName ci.testserver.com
ServerAlias ci
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPreserveHost on
ProxyPass / http://localhost:8080/
</VirtualHost>
I have 2 "hypothetical" domains. myname.me, and myproduct.co.nz. I have four servers forded to the ports 44, 45, 80 and 90 of my public ip address.
The domains both have their A record set to my ip, so myname.me:44 and myproduct.co.nz:44 bring up the same page.
What I want, is for visitors to myname.me to see the page on the server operating on port 90, but not for them to see ":90" in the address bar.
I also want visitors to a.myproduct.co.nz to see the page on the server operating on port 44, and visitors to b.myproduct.co.nz to see the page on the server operating on port 45, both without seeing the :44 or :45 (e.g. I want the pages all serverd on 80).
The servers are all apache2 with php.
I guess that it would be something related to http://httpd.apache.org/docs/2.2/vhosts/name-based.html, but I am not sure how it would work with 2 servers.
I'd really appreciate any help.
~JJ56
Setup name-virtual-hosts on your "port-80 machine". Then use ProxyPass (from mod_proxy) within each virtual host definition, to pass requests from your "port-80 machine" to the other machines behind your firewall.
It might look something like the following:
(NOTE: The main server (your "port 80 server") has to be able to reach the other servers on your internal network -- I've used numeric addresses (192.168.1.5, and 192.168.1.6)).
<VirtualHost *:80>
DocumentRoot /var/www/myname.me/public_html
ServerName myname.me
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://192.168.1.6/
ProxyPassReverse / http://192.168.1.6/
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /var/www/myproduct.co.nz/public_html
ServerName myproduct.co.nz
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://192.168.1.5/
ProxyPassReverse / http://192.168.1.5/
</VirtualHost>
Setup the virtual hosts without the proxy-related stuff first. Make sure you can successfully resolve a test page in each of the two vhosts. then (and only then) add in the proxy stuff, and start working the kinks out of that.
While I want to answer your question, I have to ask why you would want to configure the server in this way. What it seems you're really trying to do is configure multiple domain (or Name Based Virtual Hosts) on this shared IP address.
If that's the case, then in Apache it's very easy to set up. Each domain will need to be defined in the httpd.conf or vhosts.conf (or inside of the catch-all include directory depending on your installation; see your documentation). A very basic set up would look like the following:
<VirtualHost *:80>
DocumentRoot /var/www/mywordpressblog.co.uk/public_html
ServerName www.mywordpressblog.co.uk
</VirtualHost>
Best of luck.
You run one server on port 80 and use name-based vhosts, and you don't play any games with any other public ports. If you need different domains to hit different physical servers, you set up mod_proxy to proxy the requests to those servers, or you set up squid or varnish on port 80 to do the same thing. PHP doesn't come into it at all.