App Engine matching any "subdomain" to my service - google-app-engine

I have a Strapi application on Google App Engine as the Default service.
The default URL App Engine generates is https://my-project.uc.r.appspot.com
When I create any other version for my default service or deploy another service, the new URLs would be something like: https://[identifier]-dot-my-project.uc.r.appspot.com
My problem is that if I replace [identifier] with anything at all it opens my Strapi Application root page.
I don't think this has anything to do with Strapi at all, it's probably a feature of App Engine.
My question is: How do I stop this from happening? I want only proper URLs to be matched. That is, if I create a "dev" version, I should be able to access it with the following URL: https://dev-dot-my-project.uc.r.appspot.com, but I don't want any other URL to be matched, like: https://12345-dot-my-project.uc.r.appspot.com
I am using a Standard Environment with the default app.yaml from Strapi docs
runtime: nodejs16
instance_class: F2
env_variables:
HOST: '0.0.0.0'
NODE_ENV: 'production'
DATABASE_NAME: 'strapi'
DATABASE_USER: 'postgres'
DATABASE_PASSWORD: '<password>'
INSTANCE_CONNECTION_NAME: '<instance_identifier>'
beta_settings:
cloud_sql_instances: '<instance_identifier>'
When the app is deployed to App Engine, the app.yaml is automatically modified to add some default params.
runtime: nodejs16
env: standard
instance_class: F2
handlers:
- url: .*
script: auto
I thought maybe this url: .* was the cause of this and tried to change it to url: /.* (Docs), but App Engine still add the url: .* again anyway at the end and it will have both handlers.

This is expected behavior. Per the documentation
If a request matches the PROJECT_ID.REGION_ID.r.appspot.com portion of the hostname, but includes a service, version, or instance name that does not exist, then the request is routed to the default service.
In your example, when you hit the url - https://12345-dot-my-project.uc.r.appspot.com and it turns out '12345' is not a valid version, the default service - https://my-project.uc.r.appspot.com will take over.
If you really want to block it, you'll have to write code to read the incoming url (i.e. the original url that came in), determine the version and if it's not in your list of versions, you raise an error (maybe return 404). This is basically what you'd do if you were offering a service built on GAE where each of your users had their own custom domain (version of your app) e.g. a blog hosting platform, an ecommerce site (like Shopify)

Related

Google App Engine routing with dispatch.yaml

I try to deploy a web app on my sandbox GCP project where there is already an app deployed. So I'm trying to play with the path to have the two web apps deployed at the same time.
My dispatch looks like this
dispatch:
- url: "*/wc/api/.*"
service: wc-api
- url: "*/wc/.*"
service: wc-front
- url: "*/.*"
service: default
When I do so, all my calls to mysandbox.appspot.com/wc/ gets redirected to my default service and I don't understand why (I can see the calls in the logs of the default service).
If this helps, here is the app.yaml of my wc-front service.
runtime: python27
api_version: 1
threadsafe: yes
service: wc-front
default_expiration: "10m"
handlers:
- url: /wc/.*
script: app.APP
login: required
secure: always
Do you see any error in this ?
(Calling directly wc-front-dot-mysandbox.appspot.com/wc/ returns the typical App Engine 404 error)
Thanks
It appears the problem was coming from the .* notation. This should only be used for the very general */.* rule.
My new - working - dispatch
dispatch:
- url: "*/wc/api/*"
service: wc-api
- url: "*/wc/*"
service: wc-front
- url: "*/.*"
service: default
Yes, indeed, you need to configure your dispatch.yaml file, for App Engine to route your application based on the URL that you set there. It seems that your service: default it's getting all URLs and redirecting them to the service set there.
Considering that, I would recommend you to take a look at the official documentation about configuring the dispatch.yaml file - you can get some better ideas on how to configure it - and this other post from the Community, where another user has a similar use case as yours, that I believe should help you.
dispatch.yaml Configuration File
How to use GAE's dispatch.yaml with multiple development environments?
Let me know if the information helped you!

503 errors when trying to login on local Google AppEngine server

I have a functional Go app which I've been running locally for months. Got setup with Google Cloud, did a test run to a live domain, everything works.
Looking back at my local machine, I want to run a local Google AppEngine server (instead of running my Go app directly). It runs, however I'm trying to use the "login: required" parameter in app.yaml, and I see the login form at localhost:8080, however no matter what email I input, it keeps timing out with 503 errors.
My app.yaml:
application: myapp-dev
env: flex
runtime: go
api_version: go1
handlers:
- url: /
script: _go_app
login: required
Command I use to run the local app:
dev_appserver.py app.yaml
Flexible environment doesn't support 'login' features via app.yaml (external to whatever regular login you'd do in your app).
Standard environment app.yaml doc DOES list 'login' features: https://cloud.google.com/appengine/docs/standard/go/config/appref
Flexible environment app.yaml doc DOES NOT list 'login' features: https://cloud.google.com/appengine/docs/flexible/go/configuring-your-app-with-app-yaml
But more specifically, a page talking about upgrading from Standard-to-Flex, mentions that the login handlers for flex have been deprecated:
https://cloud.google.com/appengine/docs/flexible/go/upgrading
The login setting under handlers is now deprecated for the App Engine
flexible environment. You should follow the guidance for User service
migration.
So basically, with flex environment, there is no project-wide login controls possible outside of your app. You have to let the app initialize and then do normal authentication/authorization.
For my own project, I wanted a quick app-wide level of security so I could provide guest accounts and have them see what a public not-logged-in view of my app would be. Yes I can do the same within my app, I just wanted to save some work.

App Engine - subdomain pointing to particular service

I have two subdomains registered in my App Engine application:
service-a.my-app.com
service-b.my-app.com
I have added all the records (CNAME, A) on the server.
I have three services in my GAE:
default
service-a
service-b
And I want each subdomain to point to the correct service. However, each time I access them, only the default service is used.
Side note: the GAE is running a flexible environment for laravel 5.4 and my dispatch.yaml (located in default service is as follows:
dispatch:
-url: "service-a.my-app.com/*"
service: service-a
-url: "service-b.my-app.com/*"
service: service-b
This worked for me. Hope this helps someone.
GAE Standard:
I have an angular project which will load for any subdomain except one subdomain "api".
The backend is written in Go and all services are under a service named "api"
STEP1: Setting local env
Angular project has the following app.yaml
runtime: python27
api_version: 1
instance_class: F1
handlers:
- url: /
static_files: default/index.html
upload: default/index.html
- url: /
static_dir: default
My service.yaml file resides in a separate directory and has the following
runtime: go
api_version: go1
instance_class: F1
service: api
handlers:
- url: /.*
script: _go_app
secure: always
My dispatch.yaml has the following
dispatch:
- url: "api.MYDOMAINNAME.com/*"
service: api
//Add more subdomain : services mapping here
I deployed all these files using gcloud app deploy command
Step 2 - Configure Custom domains in GAE.
In GAE Console, goto Project Settings > Custom Domains
Add your domain
Verify your domainusing one of the methods provided by Google.
Update CNAME, A and AAA records in your domain service provider's DNS Settings
Step 3 - Configure Sub Domain
Add a subdomain api.MYDOMAINNAME.com
Add the CNAME in your domain service provider's settings.
// add more subdomains if required
Add a Wildcard subdomain *.MYDOMAINNAME.com
Add the CNAME in your domain service provider's settings to redirect * to google.
Finally:
Wait for few minutes for the settings to be applied.
Now your application will redirect MYDOMAINNAME.com, www.MYDOMAINNAME.com , *.MYDOMAINNAME.com to the Angular code
and
api.MYDOMAINNAME.com to your api service
Please note that dispatch.yaml is an app-level configuration, not a service-level one and occasionally updating the service containing it doesn't automatically update the app-level configs.
You should use the specific deployment commands for dispatch.yaml, executed from the directory containing the file:
gcloud app deploy dispatch.yaml if you're using the Cloud SDK
appcfg.py update_dispatch . if you're still using the GAE SDK
See also dispatch.yaml not getting updated.
The same is true for other app-level .yaml config files as well, which is probably one reason for each having its own update/deploy command (and also to allow deploying them independently of any particular app service. Somehow related: Why do I need to deploy a "default" app before I can deploy multiple services in GCP?
Actually the answer was really easy: You just need to map a wildcard subdomain and GAE would the use the service corresponding to the prefix.

Mapping subdomain to a service in Google App Engine project

I have a Google App Engine project with following yaml file
handlers:
- url: /web/.*
script: web_server.app
- url: /api/.*
script: rest_server.app
How do I make sure subdomain, of a domain I own, be served by rest_server.app script.
Example: If I own example.com
I want example.com to be served by web_server.app, and api.example.com to be served by rest_server.app
Is it possible to do that using Google App Engine.
Example:
handlers:
- url: example.com/.*
script: web_server.app
- url: api.example.com/.*
script: rest_server.app
Request routing in the app.yaml can not be used to route based on the URL's domain name, see the url table row in the Handlers element doc section.
Because of that you can't really have a single module/service serving your app while simultaneously stripping the filepath portion of the URL you're currently used in your handlers' url configs for routing requests to one script or the other.
You can obtain what you desire by splitting your app into 2 separate services/modules, each handling one script. One of the modules has to be the default module, I'd make the web one the default.
A dispatch.yaml file would be used to route requests to their respective modules based on the URL hostname.
The web.yaml file would contain:
module: default
handlers:
- url: /.*
script: web_server.app
The rest.yaml file would contain:
module: rest
handlers:
- url: /.*
script: rest_server.app
In the dispatch.yaml file you only need routes for the non-default module(s), requests matching no routes are by default routed to the defaut module:
- url: "api.example.com/*"
module: rest
You can find a more complete example here: https://stackoverflow.com/a/34111170/4495081
You'd then map both your example.com naked domain and api.example.com subdomain to your app. Follow the Adding a custom domain for your application procedure, paying extra attention to the sections which are slightly different when configuring a naked domain vs a subdomain. See also https://stackoverflow.com/a/36317462/4495081
There is one problem, tho - dispatch.yaml routing based on hostnames doesn't work with the local development server, the requests destined for the rest module would actually go to the default module.
A simpler workaround would be to direct the rest module clients to the actual localhost:PORT URL where the local devserver's rest module listens (displayed in the terminal at dev server startup), instead.
This might not be possible in all cases or for all apps. For example it's an issue if the app makes cross-module requests with auto-generated URLs.
In such cases, to work around it you can temporarily insert a small path portion in the rest.yaml URL, only during testing on the local dev server the rest module (you'd need matching changes on the client side and/or the cross-module URL generation logic):
module: rest
handlers:
- url: /api/.*
script: rest_server.app
And then you can add a dispatch.yaml rule that is not host-based and would also with the local dev server. This can be left in there permanently, it doesn't hurt if/when deployed in production when the temporary rest.yaml change is reversed:
- url: "api.example.com/*"
module: rest
- url: "*/api/*"
module: rest

Putting a Cloud Endpoints API in a separate App Engine module

I am developing an App Engine app and plan to also provide an API. I would like to separate this API from the main site, so I'm trying to use the "modules" feature to separate both apps. The main site would be the "default" module, and the API would lie in the "api" module. However, I'm having troubles with this.
Right now my main app's YAML file is like this:
application: my-app
module: default
runtime: python27
api_version: 1
...
handlers:
# Root handler
- url: /.*
script: main.app
secure: always
...
And the API module YAML file, like this:
application: my-app
module: api
runtime: python27
api_version: 1
handlers:
# Endpoints handler
- url: /_ah/spi/.*
script: api_main.app
secure: always
...
On the development server, the app is served on port 8000, and the API on port 7998.
With this configuration, my API doesn't work. Whenever I try to access it using localhost:7998/_ah/api/explorer, I don't get any result. If I try to run an API request manually, I get the following error: {"error": {"message": "BackendService.getApiConfigs Error"}}.
What's strange is I'm also seeing the following lines in the development server logs:
INFO 2014-06-15 18:00:32,368 module.py:639] default: "POST /_ah/spi/BackendService.getApiConfigs HTTP/1.1" 500 -
INFO 2014-06-15 18:00:32,368 module.py:639] api: "GET /_ah/api/my-app/v1/events HTTP/1.1" 500 60
It seems like the API module is trying to POST data to the default module (as seen in the first line of logs).
Right now, the only workaround I found is to add the same handlers for /_ah/spi/.* in the default YAML file, but in this situation the separation between the main app and the API is not effective.
Can someone tell me if the configuration I'm trying to achieve is supported by Cloud Endpoints?
Thank you very much!
Same problem, I was able to make it work after may temptatives: the (only) way i found is to make the cloud endopoints module the default module. Then i have: on the dev server the two modules listening at different ports, you can see prot numbers on the log and on xxx.appspot.com: yourprojectid.appspot.com for the cloud endpoints and modulename-dot-yourprojectid.appspot.com for the other module
I had the same problem.
I solved using one file to publish my APIs. This file is indicated in app.yaml. I put my APIs in different files.
\
app.yaml
\apis
publish_api.py
\teacher
teacher_api.py
\student
student_api.py
**app.yaml:**
- url: /_ah/spi/.*
script: apis.publish_api.api
secure: always
**publish_api.py:**
import endpoints
from teacher.teacher_api import TeacherApi
from student.student_api import StudentApi
api = endpoints.api_server([TeacherApi, StudentApi])
**teacher_api.py:**
#endpoints.api( name='teacher',
version='v1',
allowed_client_ids=[WEB_CLIENT_ID, API_EXPLORER_CLIENT_ID],
scopes=[EMAIL_SCOPE])
class TeacherApi(remote.Service):
#endpoints.method(message_types.VoidMessage, StringMessage,
path='teacher', http_method='POST', name='writeTeacher')
**student_api.py:**
...
So, I get to mantain each file separately.

Resources