Any .htaccess geniuses out there?

Discussion in 'Server Operation' started by thisiszeev, Jul 26, 2024.

  1. thisiszeev

    thisiszeev Member HowtoForge Supporter

    I am building my first full API which I need for internal use in my business. Sadly, due to the nature of how I am going to utilize it, I have to have it on a public server. I am 6 hours in to parts of it being live and the log files show that there are already hundreds of access attemps in my log file. Considering that 6 hours ago the domain didn't even exist, it is astounding how many people are trying to access api.somedomain.tld/index.php /index.pl /index.html /index.py even. I want to curb it.

    So I want to setup that if someone types api.somedomain.tld/some/folder and that folder exists then I want to just serve the output of /index.php which just spits out a JSON data format with the string {"error":"Invalid API Endpoint"}

    Already I have it that if you type api.somedomain.tld/some/folder/ it automatically runs index.php in that folder. But that is a default.

    But I also want to set it up that if you try access any non-existing endpoint or file then I want to again, output /index.php

    All this without doing a 30x redirect.

    Currently I have /some/folder/endpoint and that effortlessly runs /some/folder/endpoint.php with out changing the URL.

    Anyone got some solid advice?

    Here is my current .htaccess in the webroot

    Code:
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /$1.php [L]
    
     
    G. Gibson likes this.
  2. thisiszeev

    thisiszeev Member HowtoForge Supporter

    Okay, after much reading I found how to define error pages...

    I have added the following lines to the end of the .htaccess
    Code:
    ErrorDocument 301 /index.php
    ErrorDocument 302 /index.php
    ErrorDocument 307 /index.php
    ErrorDocument 400 /index.php
    ErrorDocument 401 /index.php
    ErrorDocument 403 /index.php
    ErrorDocument 404 /index.php
    It solved my 30x troubles, but when a folder or file does not exist, I am getting an error 500 not 404. And adding ErrorDocument 500 /index.php does nothing to help.
     
    G. Gibson likes this.
  3. till

    till Super Moderator Staff Member ISPConfig Developer

    Your problem arises because your API design does not allow you to control and handle incoming requests correctly. I would design and implement such an API differently.

    1) You have a single entrypoint for all requests, e.g. named index.php.
    2) You have a .htaccess file like this:

    Code:
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteRule . /index.php [L]
    3) In that index.php file, you either handle the API requests directly. Or if you have the API functions in separate files, you simply include them based on the requested URL. Basically like this (simplified example):

    Code:
    <?php
    if(file_exists($_SERVER["REQUEST_URI"])) {
     // do all kind of security checks to prevent directory traversal etc. If everything is ok, include API file using PHP include function
    } else {
     // handle error, as there is no such API file or function
    }
    
    
    
     
    G. Gibson, ahrasis and thisiszeev like this.
  4. thisiszeev

    thisiszeev Member HowtoForge Supporter

    So after a lot more reading and clawing at the ceiling I now have an .htaccess file that kind of works.
    Code:
    # Enable mod_rewrite
    RewriteEngine On
    
    # 1. If the endpoint is not a file or directory, and it does not contain forbidden characters, rewrite to .php
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} ^[A-Za-z0-9/_-]+$
    RewriteRule ^(.*)$ /$1.php [L]
    
    # 2. If the .php file does not exist, rewrite to /index.php
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} ^[A-Za-z0-9/_-]+\.php$
    RewriteRule ^(.*)$ /index.php [L]
    
    # 3. If the endpoint contains forbidden characters, rewrite to /index.php
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^[A-Za-z0-9/_-]+$
    RewriteRule ^(.*)$ /index.php [L]
    
    # 4. If the endpoint exists as a file or directory, rewrite to /index.php
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^(.*)$ /index.php [L]
    
    # 5. Serve /index.php as the error page for 30x and 40x errors
    ErrorDocument 301 /index.php
    ErrorDocument 302 /index.php
    ErrorDocument 404 /index.php
    The only issue I have is I do not want someone calling /path/to/end/point.php I only want it to work with /path/to/end/point
     
    ahrasis likes this.
  5. ztk.me

    ztk.me Well-Known Member HowtoForge Supporter

    The usual access.log does not really show with what Host-Request the access attempt was done. It's just what the webserver decided to deliver, though yes, welcome to the internet haha.

    Till is absolutely right, ideally you'd only have public information and a decision maker what to show ( if authenticated ) in web/ folder.
    Everything else, code, configuration .... belongs to the upper directory, or private/.

    This should not make a difference in terms of preventing anything. Also the file shouldn't even be there.

    Though maybe PHP development is not one of your companies most important skills, if your resources allow, https://symfony.com/doc/current/routing.html is an excellent web-framework, stable for years and upgrading, especially for light usages, is very easy.

    One thing many people new to this do not understand at first:
    you have a folder src/Controller/ where you can simply put a EndPointController.php which simply has
    Code similar to the one shown in the linked Example for Routing ( BlogController )
    and the https-request to /blog would be "routed" to that specific function and you go from there.

    however
    according to chatgpt :)
    Basically if the request matches anything .php ( if anything, still, after your previous rules as you use [L] )
    it gets rewritten with the matching part before \.php
     
    thisiszeev likes this.
  6. thisiszeev

    thisiszeev Member HowtoForge Supporter

    I used to code a lot back in the days of PHP 4.x

    Only recently got back into and learned 8.1, then brushed up on 8.2 and now I need to brush up on 8.3

    I am specifically using this methodology because it's not one API, but lots of small ones for different problems as well as I will be hosting APIs for my clients. TLDR - I am going to start offering solutions to sync data between platforms.

    In order to make my life easier, I just keep everything apart.

    I did solve my problems in the end. One key was to not use .php as the extension, but rather something else and just setup that vhost to pass that file extension to php.
     
  7. thisiszeev

    thisiszeev Member HowtoForge Supporter

    But error.log does, and I keep seperate log files for each domain on each of my servers.
     
  8. ztk.me

    ztk.me Well-Known Member HowtoForge Supporter

    There's still the possibility to have subfolders with different defaultindex file using a different project outside the public web though.
    seperation is a good thing security wise. If I had different services, I'd not use subfolders but subdomains maybe.
    Also better to organize. Though not insisting of course, more like wondering :)

    Thanks for your reply you solved your issue :)

    real seperate vhost subdomains and ideally with their seperate client to have real isolation, otherwise the files would be theoretically accessible by the same group member which can be bad.
     
  9. Taleman

    Taleman Well-Known Member HowtoForge Supporter

    You should not hijack threads. It seems to me your question is not relevant to the discussion on this thread.
    The .htaccess file is a hidden file, it may well be it is not copied in the usual copy.
    To see if there are any .htaccess files on the host, try this command
    It should work if command locate is installed.
    To see if there is .htacces file in a directory, use -a option in ls command, it means to show even hidden files.
    Now that I have your attention, can you explain why you reasked on Howtoforge years old questions from other forums? Like these:
     
    thisiszeev, ahrasis and ztk.me like this.

Share This Page