Cherrypy VirtualHost dispatcher not working - cherrypy

I've got the following in my cherrypy config, but /foo is not handling my request to http://foo.bar.com ... The cherrypy app is behind nginx which is passing the host header through - I'm outputting the Host header at / and it is returning 'foo.bar.com' so I'd expect /foo to handle this request.
[/]
request.dispatch = cherrypy.dispatch.VirtualHost(**{
'foo.bar.com': '/foo',
})
Nginx is doing a proxy_pass to 127.0.0.1 with:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

I don't understand the problem, but it seems to be an application vs global config problem. I was setting the VirtualHosts in server.cfg which was loaded into the global config and I was mounting without an application config:
cherrypy.config.update("server.cfg")
cherrypy.tree.mount(root, "/")
Setting the application config fixed the problem:
conf = {
"/": {
"request.dispatch": cherrypy.dispatch.VirtualHost(
**{
"foo.domain.com:8000": "/foo",
"bar.domain.com:8000": "/bar"
}
)
}
}
cherrypy.tree.mount(root, "/", conf)
If anyone wants to explain I'll accept their answer. I'm now wondering if any setting I put under [/] in server.cfg (cherrypy.config) will work correctly or if all path specific config needs to be in the application config.

You can't set the dispatcher from the global config, I do think that this is not obvious but the dispatcher itself is responsible of handling the merging of the configurations.
Another reason for confusion is that because if you use the cherryd command it might seem like is something normal.
For example you could deploy an application like this:
cherryd -c server.cfg
Having server.cfg as:
[global]
tree.app = myapp.root
[/]
request.dispatch = cherrypy.dispatch.MethodDispatcher()
With the following implementation on myapp.py:
import cherrypy
class Root(object):
exposed = True
def GET(self):
return "Hi!"
root = cherrypy.Application(Root())
But cherryd have a few trick under his wing.
One is the added namespace "tree" on which you set tree.NAME_OF_APP = INSTANCE_OF_CHERRYPY_APP and more importantly setting the dispatcher on the "global" configuration file works because the cherryd command merges the configuration file into the application when there is only one application mounted on the tree.
Something like:
cherrypy.tree.apps.values()[0].merge(config)
Effectively making the "global" configuration like a "local-per-app" configuration.

Related

Golang htaccess configure without Nginx or Apache

I've created web app and analyzed it with Google site analyzer.
In most cases I need to configure htaccess file. As I understand this file can be used only on Nginx or Apache server, but I don't want to use any of these.
I want to configure htaccess only with golang tools. Currently my app running on VPS server.
This project allows you to support the http auth standard with GO, zero apache code.
You can even use a password file created with the Apache htpasswd (bad) or htdigest (good) commands:
https://github.com/abbot/go-http-auth
You don't need .htaccess as it's only meant for Apache:
http://httpd.apache.org/docs/2.2/howto/htaccess.html
If you use Apache, external services like Google Site Analyzer can't see .htaccess since it's not served by Apache. It's kept private.
Everything Apache can do with .htaccess, Go can do with net/http or with a 3rd package like Gorilla to help.
If you want to do some constraints, then you may reference the following.
package main
import (
"github.com/gorilla/mux"
"io/fs"
"net/http"
"path/filepath"
)
type TxtFileSystem struct {
http.FileSystem
}
func (txtFS TxtFileSystem) Open(path string) (http.File, error) {
if filepath.Ext(path) != ".txt" {
return nil, &fs.PathError{Op: "open", Path: path, Err: fs.ErrNotExist}
}
return txtFS.FileSystem.Open(path)
}
func main() {
m := mux.NewRouter()
m.PathPrefix("/doc/").Handler(http.FileServer(TxtFileSystem{http.Dir("./doc")}))
}
That will only allow you to visit the file extension is .txt

pyramid pserve in different root path than /

When pserve starts by default it runs the pyramid application in http://0.0.0.0:6543 however how can I changed it to http://0.0.0.0:6543/myapp
In the settings I can change the port but I haven't found elsewhere where to change the root path
In any WSGI application the environ['SCRIPT_NAME'] is very important here. It defines the root path for all urls in the app. The full path is environ['SCRIPT_NAME'] + environ['PATH_INFO']. Assuming you have done things properly in your app (for example request.route_url(..) will generate urls using this information) then you can simply remount your application elsewhere (the default SCRIPT_NAME is '') by instructing it that it should be something else.
There are a couple things you can do based on how you're deploying your application (if it's behind a proxy then things are slightly more complex). Let's assume you're just using a simple pyramid app hosted with waitress. You can move your app using the rutter[1] package which will match the /myapp/* path and send all requests to your app with the appropriate SCRIPT_NAME (myapp) and PATH_INFO.
The declarative config is the simplest for a pyramid app. Just install rutter and then update your INI file to mount your application at /myapp prefix:
[app:foo]
use = egg:myapp#main
[composite:main]
use = egg:rutter#urlmap
/myapp = foo
Note I renamed the app:main to app:foo because you can only have one wsgi component named main and we want it to be the composite.
[1] http://rutter.readthedocs.io/en/latest/#declarative-configuration-using-paste-deploy-ini-files

Different urls for development and production

I am trying to set up an CodeIgniter project with NGINX. However, it is an already website which is online, say for example test.com. This means that the project also has $config['base_url'] = 'test.com'. But when I want to setup an NGINX server block I have to define the server name that is the same as the domain in base_url, according to this post. However, I want to have url test.dev for the development and test.com should just link to the online website. How do I achieve this?
Set your ENVIRONMENT variable. https://www.codeigniter.com/user_guide/general/environments.html
For your production
define('ENVIRONMENT','production');
and for development
define('ENVIRONMENT','production');
and in your config file you can check like this or any variables
if(ENVIRONMENT == 'development'){
$config['base_url'] = 'test.dev';
}else{
$config['base_url'] = 'test.com';
}
In CI, you can define a config.php file for each environment you are using.
In your config folder, create a development folder in which you place a config.php file with the base_url you need. Then, in that environment, CI will use that new file instead of the main config.php file.
Create Environments. Handling Multiple Environments
In your index.php Find a line which says
//define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
Under that line place a check on dirname and paste this code
switch(dirname(__FILE__))
{
case 'Path\of\your\live\server\folder':
define('ENVIRONMENT','production');
break;
case 'path\of\your\local\folder':
define('ENVIRONMENT','development');
break;
}
Now you have a global variable ENVIRONMENT which has values production or development. You can place a switch on this variable and give values to base_url in config.php or choose active group in database.php for DB credentials .

nginx: Deny all files inside directory

I have an "upload" directory where users can upload confidential files (jpg, png, pdf). Each user gets assigned a folder inside upload, ex: /001/, /002/, ..., /999/, etc.
I want these files to be accessible only through SFTP, so the url http://example.com/upload/259/image.jpg should return a 403 error message.
I tried many variations, but still the files can be accessed through the url.
location ~ /upload/\.(jpe?g|png|gif|ico)$ {
deny all;
return 403;
}
Any thoughts?
You still need to match that part: '/259/image'
This should work:
location ~ /upload/.*\.(jpe?g|png|gif|ico)$ {
deny all;
return 403;
}
If access to /upload is only via sftp, then this is all you should need:
location ^~ /download/ {return 403;}
By skipping the regex cycle with ^~ you'll improve performance. Also your configuration will scale with fewer problems by not using a regex location. A prefix location can go anywhere, but not a regex location. The first regex match will be used which can lead to confusion down the road.

How run cherrypy app without screen logging?

Hi I looking for some configuration or flag that allows me to silence the requested pages.
When I run python cherrypy_app.py and I join to the 127.0.0.1:8080 in the console where I start the cherrypy app show me
127.0.0.1 - - [09/Oct/2014:19:10:35] "GET / HTTP/1.1" 200 1512 "" "Mozilla/5.0 ..."
127.0.0.1 - - [09/Oct/2014:19:10:35] "GET /static/css/style.css HTTP/1.1" 200 88 "http://127.0.0.1:8080/" "Mozilla/5.0 ..."
127.0.0.1 - - [09/Oct/2014:19:10:36] "GET /favicon.ico HTTP/1.1" 200 1406 "" "Mozilla/5.0 ..."
I do not want to show this info. It is possible?
I as far as I remember in my first attempts with CherryPy I had the same desire. So here's a little more to say besides turning off the stdout logging per se.
CherryPy has some predefined environments: staging, production, embedded, test_suite that are defined here. Each environment has its set of configuration. So while developing stdout logging is in fact quite helpful, whereas in production environment it makes no sense. Setting the environment according to the deployment is the correct way to deal configuration in CherryPy.
In your particular case the stdout logging is controlled by log.screen. It is already disabled in production environment.
Here's the example, but note that setting environment inside your application isn't the best idea. You're better use cherryd's --environment for it instead.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
# Doing it explicity isn't a recommended way
# 'log.screen' : False
}
}
class App:
#cherrypy.expose
def index(self):
return 'Logging example'
if __name__ == '__main__':
# Better use cherryd (http://cherrypy.readthedocs.org/en/latest/install.html#cherryd)
# for setting the environment outside the app
cherrypy.config.update({'environment' : 'production'})
cherrypy.quickstart(App(), '/', config)

Resources