simplify web server configs (#65)
Reviewed-on: https://gitea.subcultureofone.org/greg/tkr/pulls/65 Co-authored-by: Greg Sarjeant <greg@subcultureofone.org> Co-committed-by: Greg Sarjeant <greg@subcultureofone.org>
This commit is contained in:
		
							parent
							
								
									195de75b78
								
							
						
					
					
						commit
						86abf587f6
					
				| @ -7,13 +7,17 @@ declare(strict_types=1); | |||||||
| 
 | 
 | ||||||
| // Define all the important paths
 | // Define all the important paths
 | ||||||
| define('APP_ROOT', dirname(dirname(__FILE__))); | define('APP_ROOT', dirname(dirname(__FILE__))); | ||||||
|  | // Root-level directories
 | ||||||
| define('CONFIG_DIR', APP_ROOT . '/config'); | define('CONFIG_DIR', APP_ROOT . '/config'); | ||||||
|  | define('PUBLIC_DIR', APP_ROOT . '/public'); | ||||||
| define('SRC_DIR', APP_ROOT . '/src'); | define('SRC_DIR', APP_ROOT . '/src'); | ||||||
| define('STORAGE_DIR', APP_ROOT . '/storage'); | define('STORAGE_DIR', APP_ROOT . '/storage'); | ||||||
| define('TEMPLATES_DIR', APP_ROOT . '/templates'); | // Storage subdirectories
 | ||||||
| define('DATA_DIR', STORAGE_DIR . '/db'); |  | ||||||
| define('DB_FILE', DATA_DIR . '/tkr.sqlite'); |  | ||||||
| define('CSS_UPLOAD_DIR', STORAGE_DIR . '/upload/css'); | define('CSS_UPLOAD_DIR', STORAGE_DIR . '/upload/css'); | ||||||
|  | define('DATA_DIR', STORAGE_DIR . '/db'); | ||||||
|  | define('TEMPLATES_DIR', APP_ROOT . '/templates'); | ||||||
|  | // Database file
 | ||||||
|  | define('DB_FILE', DATA_DIR . '/tkr.sqlite'); | ||||||
| 
 | 
 | ||||||
| // Janky autoloader function
 | // Janky autoloader function
 | ||||||
| // This is a bit more consistent with current frameworks
 | // This is a bit more consistent with current frameworks
 | ||||||
|  | |||||||
| @ -1,49 +1,19 @@ | |||||||
| # Example Apache VirtualHost | # Basic .htaccess for tkr on shared hosting | ||||||
| # for serving tkr as a subdirectory path | # For use with included docker-compose.yml | ||||||
| # on shared hosting via .htaccess |  | ||||||
| # |  | ||||||
| # e.g. http://www.my-domain.com/tkr |  | ||||||
| # |  | ||||||
| # This should work without modification if you extract the app |  | ||||||
| # to /tkr from your web document root |  | ||||||
| 
 | 
 | ||||||
| # Enable mod_rewrite | # Enable mod_rewrite | ||||||
| RewriteEngine On | RewriteEngine On | ||||||
| 
 | 
 | ||||||
| # Security headers | # Set directory index | ||||||
| Header always set X-Frame-Options "SAMEORIGIN" |  | ||||||
| Header always set X-XSS-Protection "1; mode=block" |  | ||||||
| Header always set X-Content-Type-Options "nosniff" |  | ||||||
| 
 |  | ||||||
| # Directory index |  | ||||||
| DirectoryIndex public/index.php | DirectoryIndex public/index.php | ||||||
| 
 | 
 | ||||||
| # Security: Block direct access to .php files (except through rewrites) | # Block access to sensitive directories | ||||||
| RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] | RewriteRule ^(storage|src|templates|config)(/.*)?$ - [F,L] | ||||||
| RewriteRule ^.*$ - [R=404,L] |  | ||||||
| 
 | 
 | ||||||
| # Security: Block access to sensitive directories | # Block access to hidden files | ||||||
| RewriteRule ^(storage|src|templates|examples|config)(/.*)?$ - [F,L] |  | ||||||
| 
 |  | ||||||
| # Security: Block access to hidden files |  | ||||||
| RewriteRule ^\..*$ - [F,L] | RewriteRule ^\..*$ - [F,L] | ||||||
| 
 | 
 | ||||||
| # Cache CSS files for 1 hour | # Route everything else through public/index.php | ||||||
| <FilesMatch "\.css$"> |  | ||||||
|     Header set Cache-Control "public, max-age=3600" |  | ||||||
| </FilesMatch> |  | ||||||
| 
 |  | ||||||
| # Serve the one static file that exists: css/tkr.css |  | ||||||
| # (Pass requests to css/custom/ through to the PHP app) |  | ||||||
| RewriteCond %{REQUEST_URI} !^/css/custom/ |  | ||||||
| RewriteRule ^css/tkr\.css$ public/css/tkr.css [L] |  | ||||||
| 
 |  | ||||||
| # 404 all other static files (images, js, fonts, etc.) |  | ||||||
| # so those requests don't hit the PHP app |  | ||||||
| # (this is to reduce load on the PHP app from bots and scanners) |  | ||||||
| RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L] |  | ||||||
| 
 |  | ||||||
| # Everything else goes to the front controller |  | ||||||
| RewriteCond %{REQUEST_FILENAME} !-f | RewriteCond %{REQUEST_FILENAME} !-f | ||||||
| RewriteCond %{REQUEST_FILENAME} !-d | RewriteCond %{REQUEST_FILENAME} !-d | ||||||
| RewriteRule ^(.*)$ public/index.php [L] | RewriteRule ^(.*)$ public/index.php [L] | ||||||
|  | |||||||
| @ -1,19 +1,21 @@ | |||||||
| # Example Apache VirtualHost | # Basic Apache VirtualHost for tkr | ||||||
| # for serving tkr as a subdomain root without SSL | # For use with included docker-compose.yml | ||||||
| # e.g. http://tkr.my-domain.com/ | 
 | ||||||
| # | # HTTP - redirect to HTTPS | ||||||
| # NOTE: Do not use in production. |  | ||||||
| #       This is provided for docker compose |  | ||||||
| #       (The included docker-compose file will mount it in the container image) |  | ||||||
| <VirtualHost *:80> | <VirtualHost *:80> | ||||||
|     ServerName localhost |     ServerName localhost | ||||||
|     DocumentRoot /var/www/tkr/public |     DocumentRoot /var/www/tkr/public | ||||||
| 
 | 
 | ||||||
|     # Security headers |     # Main directory - route everything through index.php | ||||||
|     Header always set X-Frame-Options "SAMEORIGIN" |     <Directory "/var/www/tkr/public"> | ||||||
|     Header always set X-XSS-Protection "1; mode=block" |         AllowOverride None | ||||||
|     Header always set X-Content-Type-Options "nosniff" |         Require all granted | ||||||
|     Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" | 
 | ||||||
|  |         RewriteEngine On | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-d | ||||||
|  |         RewriteRule ^(.*)$ index.php [L] | ||||||
|  |     </Directory> | ||||||
| 
 | 
 | ||||||
|     # Block access to sensitive directories |     # Block access to sensitive directories | ||||||
|     <Directory "/var/www/tkr/storage"> |     <Directory "/var/www/tkr/storage"> | ||||||
| @ -22,59 +24,13 @@ | |||||||
|     <Directory "/var/www/tkr/src"> |     <Directory "/var/www/tkr/src"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
|     <Directory "/var/www/tkr/templates"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
|     <Directory "/var/www/tkr/config"> |     <Directory "/var/www/tkr/config"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
| 
 |     <Directory "/var/www/tkr/templates"> | ||||||
|     # Block access to hidden files |  | ||||||
|     <DirectoryMatch "^\.|/\."> |  | ||||||
|         Require all denied |         Require all denied | ||||||
|     </DirectoryMatch> |  | ||||||
| 
 |  | ||||||
|     # Cache CSS files |  | ||||||
|     <LocationMatch "\.css$"> |  | ||||||
|         Header set Cache-Control "public, max-age=3600" |  | ||||||
|     </LocationMatch> |  | ||||||
| 
 |  | ||||||
|     # Serve static CSS file |  | ||||||
|     Alias /css/tkr.css /var/www/tkr/public/css/tkr.css |  | ||||||
| 
 |  | ||||||
|     # 404 all non-css static files (images, js, fonts, etc.) |  | ||||||
|     # so those requests don't hit the PHP app |  | ||||||
|     # (this is to reduce load on the PHP app from bots and scanners) |  | ||||||
|     <LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$"> |  | ||||||
|         <RequireAll> |  | ||||||
|             Require all denied |  | ||||||
|         </RequireAll> |  | ||||||
|     </LocationMatch> |  | ||||||
| 
 |  | ||||||
|     # Enable rewrite engine |  | ||||||
|     <Directory "/var/www/tkr/public"> |  | ||||||
|         Options -Indexes |  | ||||||
|         AllowOverride None |  | ||||||
|         Require all granted |  | ||||||
| 
 |  | ||||||
|         RewriteEngine On |  | ||||||
| 
 |  | ||||||
|         # Block direct PHP access |  | ||||||
|         RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] |  | ||||||
|         RewriteRule ^.*$ - [R=404,L] |  | ||||||
| 
 |  | ||||||
|         # Serve the one static file that exists: css/tkr.css |  | ||||||
|         # (Pass requests to css/custom/ through to the PHP app) |  | ||||||
|         RewriteCond %{REQUEST_URI} !^/css/custom/ |  | ||||||
|         RewriteRule ^css/tkr\.css$ css/tkr.css [L] |  | ||||||
| 
 |  | ||||||
|         # Everything else to front controller |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-f |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-d |  | ||||||
|         RewriteRule ^(.*)$ index.php [L] |  | ||||||
|     </Directory> |     </Directory> | ||||||
| 
 | 
 | ||||||
|     # Error and access logs |  | ||||||
|     ErrorLog ${APACHE_LOG_DIR}/tkr_error.log |     ErrorLog ${APACHE_LOG_DIR}/tkr_error.log | ||||||
|     CustomLog ${APACHE_LOG_DIR}/tkr_access.log combined |     CustomLog ${APACHE_LOG_DIR}/tkr_access.log combined | ||||||
| </VirtualHost> | </VirtualHost> | ||||||
|  | |||||||
| @ -1,72 +1,38 @@ | |||||||
| # Example Apache VirtualHost | # Basic Apache config for tkr in subfolder | ||||||
| # for serving tkr as a subdirectory path without SSL | # e.g. https://your-domain.com/tkr | ||||||
| # e.g. http://www.my-domain.com/tkr | # For use with included docker-compose.yml | ||||||
| # | 
 | ||||||
| # NOTE: Do not use in production. | # Alias for tkr subfolder | ||||||
| #       This is provided for docker compose |  | ||||||
| #       (The included docker-compose file will mount it in the container image) |  | ||||||
| <VirtualHost *:80> | <VirtualHost *:80> | ||||||
|     ServerName localhost |     ServerName localhost | ||||||
|     DocumentRoot /var/www/html |  | ||||||
| 
 |  | ||||||
|     # Security headers |  | ||||||
|     Header always set X-Frame-Options "SAMEORIGIN" |  | ||||||
|     Header always set X-XSS-Protection "1; mode=block" |  | ||||||
|     Header always set X-Content-Type-Options "nosniff" |  | ||||||
|     Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" |  | ||||||
| 
 |  | ||||||
|     # tkr Application at /tkr |  | ||||||
|     # NOTE: If you change the directory name, |  | ||||||
|     # remember to update all instances of /var/www/tkr in this file to match |  | ||||||
|     Alias /tkr /var/www/tkr/public |     Alias /tkr /var/www/tkr/public | ||||||
| 
 | 
 | ||||||
|     # Block access to sensitive TKR directories |     <Directory "/var/www/tkr/public"> | ||||||
|  |         AllowOverride None | ||||||
|  |         Require all granted | ||||||
|  | 
 | ||||||
|  |         # Front controller pattern | ||||||
|  |         RewriteEngine On | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-d | ||||||
|  |         RewriteRule ^(.*)$ /tkr/index.php [L] | ||||||
|  |     </Directory> | ||||||
|  | 
 | ||||||
|  |     # Block access to sensitive directories | ||||||
|     <Directory "/var/www/tkr/storage"> |     <Directory "/var/www/tkr/storage"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
|     <Directory "/var/www/tkr/src"> |     <Directory "/var/www/tkr/src"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
|     <Directory "/var/www/tkr/templates"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
|     <Directory "/var/www/tkr/config"> |     <Directory "/var/www/tkr/config"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
| 
 |     <Directory "/var/www/tkr/templates"> | ||||||
|     # 404 all non-css static files in /tkr (images, js, fonts, etc.) |         Require all denied | ||||||
|     # so those requests don't hit the PHP app |  | ||||||
|     # (this is to reduce load on the PHP app from bots and scanners) |  | ||||||
|     <LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$"> |  | ||||||
|         <RequireAll> |  | ||||||
|             Require all denied |  | ||||||
|         </RequireAll> |  | ||||||
|     </LocationMatch> |  | ||||||
| 
 |  | ||||||
|     # tkr application directory |  | ||||||
|     <Directory "/var/www/tkr/public"> |  | ||||||
|         Options -Indexes |  | ||||||
|         AllowOverride None |  | ||||||
|         Require all granted |  | ||||||
| 
 |  | ||||||
|         RewriteEngine On |  | ||||||
| 
 |  | ||||||
|         # Block direct PHP access |  | ||||||
|         RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] |  | ||||||
|         RewriteRule ^.*$ - [R=404,L] |  | ||||||
| 
 |  | ||||||
|         # Serve the one static file that exists: css/tkr.css |  | ||||||
|         # (Pass requests to css/custom/ through to the PHP app) |  | ||||||
|         RewriteCond %{REQUEST_URI} !^/tkr/css/custom/ |  | ||||||
|         RewriteRule ^css/tkr\.css$ css/tkr.css [L] |  | ||||||
| 
 |  | ||||||
|         # Send everything else to the front controller |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-f |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-d |  | ||||||
|         RewriteRule ^(.*)$ index.php [L] |  | ||||||
|     </Directory> |     </Directory> | ||||||
| 
 | 
 | ||||||
|     # Error and access logs |     # Error and access logs | ||||||
|     ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log |     ErrorLog ${APACHE_LOG_DIR}/tkr_error.log | ||||||
|     CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined |     CustomLog ${APACHE_LOG_DIR}/tkr_access.log combined | ||||||
| </VirtualHost> | </VirtualHost> | ||||||
| @ -1,100 +1,45 @@ | |||||||
| # Example nginx config | # Basic nginx config for tkr | ||||||
| # for serving tkr as a subdomain without SSL | # Replace "your-domain.com" with your actual domain | ||||||
| # e.g. http://tkr.my-domain.com/ | # Replace "/var/www/tkr" with your installation path | ||||||
| # | 
 | ||||||
| # NOTE: Do not use in production. | # HTTP - redirect to HTTPS | ||||||
| #       This is provided for docker compose |  | ||||||
| #       (The included docker-compose file will mount it in the container image) |  | ||||||
| server { | server { | ||||||
|     listen 80; |     listen 80 default_server; | ||||||
|     server_name localhost; |     server_name localhost; | ||||||
| 
 | 
 | ||||||
|     root /var/www/tkr/public; |     root /var/www/tkr/public; | ||||||
|     index index.php; |     index index.php; | ||||||
| 
 | 
 | ||||||
|     # Security headers |     # Block access to sensitive directories | ||||||
|     # The first rule is to prevent including in a frame on a different domain. |     location ~ ^/(storage|src|templates|config) { | ||||||
|     # Remove it if you want to do that. |         deny all; | ||||||
|     add_header X-Frame-Options "SAMEORIGIN" always; |         return 404; | ||||||
|     add_header X-XSS-Protection "1; mode=block" always; |     } | ||||||
|     add_header X-Content-Type-Options "nosniff" always; |  | ||||||
| 
 | 
 | ||||||
|     # Deny access to hidden files |     # Block access to hidden files | ||||||
|     location ~ /\. { |     location ~ /\. { | ||||||
|         deny all; |         deny all; | ||||||
|         access_log off; |  | ||||||
|         log_not_found off; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     # PHP routing - everything goes through index.php |     # Handle PHP files | ||||||
|     location / { |     location ~ \.php$ { | ||||||
|         # Cache static files |  | ||||||
|         # Note that I don't actually serve most of this (just css) |  | ||||||
|         # but this prevents requests for static content from getting to the PHP handler. |  | ||||||
|         # |  | ||||||
|         # I've excluded /css/custom so that requests for uploaded css can be handled by the PHP app. |  | ||||||
|         # That lets me store uploaded content outside of the document root, |  | ||||||
|         # so it isn't served directly. |  | ||||||
| 
 |  | ||||||
|         # CSS files - 1 hour cache |  | ||||||
|         location ~* ^/(?!css/custom/).+\.css$ { |  | ||||||
|             expires 1h; |  | ||||||
|             add_header Cache-Control "public"; |  | ||||||
|             try_files $uri =404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Other static assets - 1 year cache |  | ||||||
|         location ~* ^/.+\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { |  | ||||||
|             expires 1y; |  | ||||||
|             add_header Cache-Control "public, immutable"; |  | ||||||
|             try_files $uri =404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # index.php is the entry point |  | ||||||
|         # It needs to be sent to php-fpm |  | ||||||
|         # But if someone tries to directly access index.php, that file will throw a 404 |  | ||||||
|         # so bots and scanners can't tell this is a php app |  | ||||||
|         location = /index.php { |  | ||||||
|             # If you're running php-fpm on the same server as nginx, |  | ||||||
|             # then change this to the local php-fpm socket |  | ||||||
|             # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; |  | ||||||
|             fastcgi_pass php:9000; |  | ||||||
|             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |  | ||||||
|             include fastcgi_params; |  | ||||||
| 
 |  | ||||||
|             fastcgi_param REQUEST_METHOD $request_method; |  | ||||||
|             fastcgi_param REQUEST_URI $request_uri; |  | ||||||
|             fastcgi_param QUERY_STRING $query_string; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Block attempts to access all other .php files directly |  | ||||||
|         # (these are bots and scanners) |  | ||||||
|         location ~ ^/.+\.php$ { |  | ||||||
|             return 404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # forward other requests to the fallback block, |  | ||||||
|         # which sends them to php-fpm for handling |  | ||||||
|         try_files $uri $uri/ @tkr_fallback; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     # Fallback for /tkr routing - all non-file requests (e.g. /login) go to index.php |  | ||||||
|     location @tkr_fallback { |  | ||||||
|         # If you're running php-fpm on the same server as nginx, |  | ||||||
|         # then change this to the local php-fpm socket |  | ||||||
|         # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; |  | ||||||
|         fastcgi_pass php:9000; |         fastcgi_pass php:9000; | ||||||
|         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|         include fastcgi_params; |         include fastcgi_params; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     # Front controller pattern - route everything else through index.php | ||||||
|  |     location / { | ||||||
|  |         try_files $uri $uri/ @tkr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # Handle PHP requests | ||||||
|  |     location @tkr { | ||||||
|  |         fastcgi_pass php:9000; | ||||||
|  |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |         include fastcgi_params; | ||||||
|         fastcgi_param REQUEST_METHOD $request_method; |         fastcgi_param REQUEST_METHOD $request_method; | ||||||
|         fastcgi_param REQUEST_URI $request_uri; |         fastcgi_param REQUEST_URI $request_uri; | ||||||
|         fastcgi_param QUERY_STRING $query_string; |         fastcgi_param QUERY_STRING $query_string; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     # Deny access to sensitive directories |  | ||||||
|     location ~ ^/(storage|src|templates|uploads|config) { |  | ||||||
|         deny all; |  | ||||||
|         return 404; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,101 +1,47 @@ | |||||||
| # Example nginx config | # Basic nginx config for tkr in subfolder | ||||||
| # for serving tkr as a subdfolder without SSL | # e.g. https://your-domain.com/tkr | ||||||
| # e.g. http://my-domain.com/tkr | # For use with included docker-compose.yml | ||||||
| # | 
 | ||||||
| # NOTE: Do not use in production. |  | ||||||
| #       This is provided for docker compose |  | ||||||
| #       (The included docker-compose file will mount it in the container image) |  | ||||||
| server { | server { | ||||||
|     listen 80 default_server; |     listen 80 default_server; | ||||||
|     listen [::]:80 default_server; |  | ||||||
| 
 |  | ||||||
|     # replace localhost with your subdomain |  | ||||||
|     # e.g. tkr.my-domain.com |  | ||||||
|     server_name localhost; |     server_name localhost; | ||||||
| 
 | 
 | ||||||
|     root /var/www/html; |     root /var/www/html; | ||||||
|     index index.html; |     index index.html; | ||||||
| 
 | 
 | ||||||
|     # Security headers |  | ||||||
|     # The first rule is to prevent including in a frame on a different domain. |  | ||||||
|     # Remove it if you want to do that. |  | ||||||
|     add_header X-Frame-Options "SAMEORIGIN" always; |  | ||||||
|     add_header X-XSS-Protection "1; mode=block" always; |  | ||||||
|     add_header X-Content-Type-Options "nosniff" always; |  | ||||||
| 
 |  | ||||||
|     # Deny access to hidden files |  | ||||||
|     location ~ /\. { |  | ||||||
|         deny all; |  | ||||||
|         access_log off; |  | ||||||
|         log_not_found off; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     # PHP routing - everything under /tkr goes through index.php |  | ||||||
|     location /tkr { |     location /tkr { | ||||||
|         alias /var/www/tkr/public; |         alias /var/www/tkr/public; | ||||||
|         index index.php; |         index index.php; | ||||||
| 
 | 
 | ||||||
|         # Cache static files |         # Block access to sensitive directories | ||||||
|         # Note that I don't actually serve most of this (just css) |         location ~ ^/tkr/(storage|src|templates|config) { | ||||||
|         # but this prevents requests for static content from getting to the PHP handler. |             deny all; | ||||||
|         # |  | ||||||
|         # I've excluded /css/custom so that requests for uploaded css can be handled by the PHP app. |  | ||||||
|         # That lets me store uploaded content outside of the document root, |  | ||||||
|         # so it isn't served directly. |  | ||||||
| 
 |  | ||||||
|         # CSS files - 1 hour cache |  | ||||||
|         location ~* ^/tkr/(?!css/custom/).+\.css$ { |  | ||||||
|             expires 1h; |  | ||||||
|             add_header Cache-Control "public"; |  | ||||||
|             try_files $uri =404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Other static assets - 1 year cache |  | ||||||
|         location ~* ^/tkr/.+\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { |  | ||||||
|             expires 1y; |  | ||||||
|             add_header Cache-Control "public, immutable"; |  | ||||||
|             try_files $uri =404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # index.php is the entry point |  | ||||||
|         # It needs to be sent to php-fpm |  | ||||||
|         # But if someone tries to directly access index.php, that file will throw a 404 |  | ||||||
|         # so bots and scanners can't tell this is a php app |  | ||||||
|         location = /tkr/index.php { |  | ||||||
|             fastcgi_pass php:9000; |  | ||||||
|             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |  | ||||||
|             include fastcgi_params; |  | ||||||
| 
 |  | ||||||
|             fastcgi_param REQUEST_METHOD $request_method; |  | ||||||
|             fastcgi_param REQUEST_URI $request_uri; |  | ||||||
|             fastcgi_param QUERY_STRING $query_string; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Block attempts to access all other .php files directly |  | ||||||
|         # (these are bots and scanners) |  | ||||||
|         location ~ ^/tkr/.+\.php$ { |  | ||||||
|             return 404; |             return 404; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         # forward other requests to the fallback block, |         # Block access to hidden files | ||||||
|         # which sends them to php-fpm for handling |         location ~ /\. { | ||||||
|         try_files $uri $uri/ @tkr_fallback; |             deny all; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # Handle PHP files | ||||||
|  |         location ~ \.php$ { | ||||||
|  |             fastcgi_pass php:9000; | ||||||
|  |             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |             include fastcgi_params; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # Front controller pattern | ||||||
|  |         # Send everything else to index.php | ||||||
|  |         try_files $uri $uri/ @tkr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     # Fallback for /tkr routing - all non-file requests (e.g. /login) go to index.php |     location @tkr { | ||||||
|     location @tkr_fallback { |  | ||||||
|         fastcgi_pass php:9000; |         fastcgi_pass php:9000; | ||||||
|         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|         include fastcgi_params; |         include fastcgi_params; | ||||||
| 
 |  | ||||||
|         fastcgi_param REQUEST_METHOD $request_method; |         fastcgi_param REQUEST_METHOD $request_method; | ||||||
|         fastcgi_param REQUEST_URI $request_uri; |         fastcgi_param REQUEST_URI $request_uri; | ||||||
|         fastcgi_param QUERY_STRING $query_string; |         fastcgi_param QUERY_STRING $query_string; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     # Deny access to sensitive directories |  | ||||||
|     location ~ ^/tkr/(storage|src|templates|uploads|config) { |  | ||||||
|         deny all; |  | ||||||
|         return 404; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @ -1,49 +1,20 @@ | |||||||
| # Example Apache VirtualHost | # Basic .htaccess for tkr on shared hosting | ||||||
| # for serving tkr as a subdirectory path | # Place this file inside the tkr directory | ||||||
| # on shared hosting via .htaccess | # e.g. if tkr is at /public_html/tkr/, this goes in /public_html/tkr/ | ||||||
| # |  | ||||||
| # e.g. http://www.my-domain.com/tkr |  | ||||||
| # |  | ||||||
| # This should work without modification if you extract the app |  | ||||||
| # to /tkr from your web document root |  | ||||||
| 
 | 
 | ||||||
| # Enable mod_rewrite | # Enable mod_rewrite | ||||||
| RewriteEngine On | RewriteEngine On | ||||||
| 
 | 
 | ||||||
| # Security headers | # Set directory index | ||||||
| Header always set X-Frame-Options "SAMEORIGIN" |  | ||||||
| Header always set X-XSS-Protection "1; mode=block" |  | ||||||
| Header always set X-Content-Type-Options "nosniff" |  | ||||||
| 
 |  | ||||||
| # Directory index |  | ||||||
| DirectoryIndex public/index.php | DirectoryIndex public/index.php | ||||||
| 
 | 
 | ||||||
| # Security: Block direct access to .php files (except through rewrites) | # Block access to sensitive directories | ||||||
| RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] | RewriteRule ^(storage|src|templates|config)(/.*)?$ - [F,L] | ||||||
| RewriteRule ^.*$ - [R=404,L] |  | ||||||
| 
 | 
 | ||||||
| # Security: Block access to sensitive directories | # Block access to hidden files | ||||||
| RewriteRule ^(storage|src|templates|examples|config)(/.*)?$ - [F,L] |  | ||||||
| 
 |  | ||||||
| # Security: Block access to hidden files |  | ||||||
| RewriteRule ^\..*$ - [F,L] | RewriteRule ^\..*$ - [F,L] | ||||||
| 
 | 
 | ||||||
| # Cache CSS files for 1 hour | # Route everything else through the front controller | ||||||
| <FilesMatch "\.css$"> |  | ||||||
|     Header set Cache-Control "public, max-age=3600" |  | ||||||
| </FilesMatch> |  | ||||||
| 
 |  | ||||||
| # Serve the one static file that exists: css/tkr.css |  | ||||||
| # (Pass requests to css/custom/ through to the PHP app) |  | ||||||
| RewriteCond %{REQUEST_URI} !^/css/custom/ |  | ||||||
| RewriteRule ^css/tkr\.css$ public/css/tkr.css [L] |  | ||||||
| 
 |  | ||||||
| # 404 all other static files (images, js, fonts, etc.) |  | ||||||
| # so those requests don't hit the PHP app |  | ||||||
| # (this is to reduce load on the PHP app from bots and scanners) |  | ||||||
| RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L] |  | ||||||
| 
 |  | ||||||
| # Everything else goes to the front controller |  | ||||||
| RewriteCond %{REQUEST_FILENAME} !-f | RewriteCond %{REQUEST_FILENAME} !-f | ||||||
| RewriteCond %{REQUEST_FILENAME} !-d | RewriteCond %{REQUEST_FILENAME} !-d | ||||||
| RewriteRule ^(.*)$ public/index.php [L] | RewriteRule ^(.*)$ public/index.php [L] | ||||||
|  | |||||||
| @ -1,39 +1,34 @@ | |||||||
| # Example Apache VirtualHost | # Basic Apache VirtualHost for tkr | ||||||
| # for serving tkr as a subdomain root with SSL | # Replace "your-domain.com" with your actual domain | ||||||
| # e.g. https://tkr.my-domain.com/ | # Replace "/var/www/tkr" with your installation path | ||||||
| # | 
 | ||||||
| # Use SSL in production. | # HTTP - redirect to HTTPS | ||||||
| # This is a minimal SSL confiuration |  | ||||||
| # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ |  | ||||||
| <VirtualHost *:80> | <VirtualHost *:80> | ||||||
|     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com |     ServerName your-domain.com | ||||||
|     ServerName localhost |     Redirect permanent / https://your-domain.com/ | ||||||
|     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com |  | ||||||
|     DocumentRoot /var/www/tkr/public |  | ||||||
|     # Redirect HTTP to HTTPS |  | ||||||
|     Redirect permanent / https://tkr.my-domain.com/ |  | ||||||
| </VirtualHost> | </VirtualHost> | ||||||
| 
 | 
 | ||||||
|  | # HTTPS | ||||||
| <VirtualHost *:443> | <VirtualHost *:443> | ||||||
|     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com |     ServerName your-domain.com | ||||||
|     ServerName localhost |  | ||||||
|     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com |  | ||||||
|     DocumentRoot /var/www/tkr/public |     DocumentRoot /var/www/tkr/public | ||||||
| 
 |      | ||||||
|     # SSL Configuration |     # SSL Configuration (using Let's Encrypt) | ||||||
|     SSLEngine on |     SSLEngine on | ||||||
| 
 |     SSLCertificateFile /etc/letsencrypt/live/your-domain.com/fullchain.pem | ||||||
|     # Assumes you're using letsencrypt for cert generation |     SSLCertificateKeyFile /etc/letsencrypt/live/your-domain.com/privkey.pem | ||||||
|     # Replace with the actual paths to your cert and key |      | ||||||
|     SSLCertificateFile /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem |     # Main directory - route everything through index.php | ||||||
|     SSLCertificateKeyFile /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem |     <Directory "/var/www/tkr/public"> | ||||||
| 
 |         AllowOverride None | ||||||
|     # Security headers |         Require all granted | ||||||
|     Header always set X-Frame-Options "SAMEORIGIN" |          | ||||||
|     Header always set X-XSS-Protection "1; mode=block" |         RewriteEngine On | ||||||
|     Header always set X-Content-Type-Options "nosniff" |         RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|     Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" |         RewriteCond %{REQUEST_FILENAME} !-d | ||||||
| 
 |         RewriteRule ^(.*)$ index.php [L] | ||||||
|  |     </Directory> | ||||||
|  |      | ||||||
|     # Block access to sensitive directories |     # Block access to sensitive directories | ||||||
|     <Directory "/var/www/tkr/storage"> |     <Directory "/var/www/tkr/storage"> | ||||||
|         Require all denied |         Require all denied | ||||||
| @ -41,59 +36,13 @@ | |||||||
|     <Directory "/var/www/tkr/src"> |     <Directory "/var/www/tkr/src"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
|     <Directory "/var/www/tkr/templates"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
|     <Directory "/var/www/tkr/config"> |     <Directory "/var/www/tkr/config"> | ||||||
|         Require all denied |         Require all denied | ||||||
|     </Directory> |     </Directory> | ||||||
| 
 |     <Directory "/var/www/tkr/templates"> | ||||||
|     # Block access to hidden files |  | ||||||
|     <DirectoryMatch "^\.|/\."> |  | ||||||
|         Require all denied |         Require all denied | ||||||
|     </DirectoryMatch> |  | ||||||
| 
 |  | ||||||
|     # Cache CSS files |  | ||||||
|     <LocationMatch "\.css$"> |  | ||||||
|         Header set Cache-Control "public, max-age=3600" |  | ||||||
|     </LocationMatch> |  | ||||||
| 
 |  | ||||||
|     # Serve static CSS file |  | ||||||
|     Alias /css/tkr.css /var/www/tkr/public/css/tkr.css |  | ||||||
| 
 |  | ||||||
|     # 404 all non-css static files (images, js, fonts, etc.) |  | ||||||
|     # so those requests don't hit the PHP app |  | ||||||
|     # (this is to reduce load on the PHP app from bots and scanners) |  | ||||||
|     <LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$"> |  | ||||||
|         <RequireAll> |  | ||||||
|             Require all denied |  | ||||||
|         </RequireAll> |  | ||||||
|     </LocationMatch> |  | ||||||
| 
 |  | ||||||
|     # Enable rewrite engine |  | ||||||
|     <Directory "/var/www/tkr/public"> |  | ||||||
|         Options -Indexes |  | ||||||
|         AllowOverride None |  | ||||||
|         Require all granted |  | ||||||
| 
 |  | ||||||
|         RewriteEngine On |  | ||||||
| 
 |  | ||||||
|         # Block direct PHP access |  | ||||||
|         RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] |  | ||||||
|         RewriteRule ^.*$ - [R=404,L] |  | ||||||
| 
 |  | ||||||
|         # Serve the one static file that exists: css/tkr.css |  | ||||||
|         # (Pass requests to css/custom/ through to the PHP app) |  | ||||||
|         RewriteCond %{REQUEST_URI} !^/css/custom/ |  | ||||||
|         RewriteRule ^css/tkr\.css$ css/tkr.css [L] |  | ||||||
| 
 |  | ||||||
|         # Everything else to front controller |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-f |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-d |  | ||||||
|         RewriteRule ^(.*)$ index.php [L] |  | ||||||
|     </Directory> |     </Directory> | ||||||
| 
 |      | ||||||
|     # Error and access logs |  | ||||||
|     ErrorLog ${APACHE_LOG_DIR}/tkr_error.log |     ErrorLog ${APACHE_LOG_DIR}/tkr_error.log | ||||||
|     CustomLog ${APACHE_LOG_DIR}/tkr_access.log combined |     CustomLog ${APACHE_LOG_DIR}/tkr_access.log combined | ||||||
| </VirtualHost> | </VirtualHost> | ||||||
|  | |||||||
| @ -1,91 +1,31 @@ | |||||||
| # Example Apache VirtualHost | # Basic Apache config for tkr in subfolder | ||||||
| # for serving tkr as a subdirectory path with SSL | # e.g. https://your-domain.com/tkr | ||||||
| # e.g. https://www.my-domain.com/tkr | # Add this to your existing VirtualHost configuration | ||||||
| # |  | ||||||
| # Use SSL in production. |  | ||||||
| # This is a minimal SSL confiuration |  | ||||||
| # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ |  | ||||||
| <VirtualHost *:80> |  | ||||||
|     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com |  | ||||||
|     ServerName localhost |  | ||||||
|     # CONFIG: Replace  with your subdomain, e.g. tkr.my-domain.com |  | ||||||
|     DocumentRoot /var/www/tkr |  | ||||||
|     # Redirect HTTP to HTTPS |  | ||||||
|     Redirect permanent / https://my-domain.com/ |  | ||||||
| </VirtualHost> |  | ||||||
| 
 | 
 | ||||||
| <VirtualHost *:443> | # Alias for tkr subfolder | ||||||
|     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | Alias /tkr /var/www/tkr/public | ||||||
|     ServerName localhost |  | ||||||
|     # CONFIG: Replace  with your subdomain, e.g. tkr.my-domain.com |  | ||||||
|     DocumentRoot /var/www/tkr/ |  | ||||||
| 
 | 
 | ||||||
|     # SSL Configuration | <Directory "/var/www/tkr/public"> | ||||||
|     SSLEngine on |     AllowOverride None | ||||||
|  |     Require all granted | ||||||
|  |      | ||||||
|  |     # Front controller pattern | ||||||
|  |     RewriteEngine On | ||||||
|  |     RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  |     RewriteCond %{REQUEST_FILENAME} !-d | ||||||
|  |     RewriteRule ^(.*)$ /tkr/index.php [L] | ||||||
|  | </Directory> | ||||||
| 
 | 
 | ||||||
|     # Assumes you're using letsencrypt for cert generation | # Block access to sensitive directories | ||||||
|     # Replace with the actual paths to your cert and key | <Directory "/var/www/tkr/storage"> | ||||||
|     SSLCertificateFile /etc/letsencrypt/live/my-domain.com/fullchain.pem |     Require all denied | ||||||
|     SSLCertificateKeyFile /etc/letsencrypt/live/my-domain.com/privkey.pem | </Directory> | ||||||
| 
 | <Directory "/var/www/tkr/src"> | ||||||
|     # Security headers |     Require all denied | ||||||
|     Header always set X-Frame-Options "SAMEORIGIN" | </Directory> | ||||||
|     Header always set X-XSS-Protection "1; mode=block" | <Directory "/var/www/tkr/config"> | ||||||
|     Header always set X-Content-Type-Options "nosniff" |     Require all denied | ||||||
|     Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" | </Directory> | ||||||
| 
 | <Directory "/var/www/tkr/templates"> | ||||||
|     # tkr Application at /tkr |     Require all denied | ||||||
|     # NOTE: If you change the directory name, | </Directory> | ||||||
|     # remember to update all instances of /var/www/tkr in this file to match |  | ||||||
|     Alias /tkr /var/www/tkr/public |  | ||||||
| 
 |  | ||||||
|     # Block access to sensitive TKR directories |  | ||||||
|     <Directory "/var/www/tkr/storage"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
|     <Directory "/var/www/tkr/src"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
|     <Directory "/var/www/tkr/templates"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
|     <Directory "/var/www/tkr/config"> |  | ||||||
|         Require all denied |  | ||||||
|     </Directory> |  | ||||||
| 
 |  | ||||||
|     # 404 all non-css static files in /tkr (images, js, fonts, etc.) |  | ||||||
|     # so those requests don't hit the PHP app |  | ||||||
|     # (this is to reduce load on the PHP app from bots and scanners) |  | ||||||
|     <LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$"> |  | ||||||
|         <RequireAll> |  | ||||||
|             Require all denied |  | ||||||
|         </RequireAll> |  | ||||||
|     </LocationMatch> |  | ||||||
| 
 |  | ||||||
|     # tkr application directory |  | ||||||
|     <Directory "/var/www/tkr/public"> |  | ||||||
|         Options -Indexes |  | ||||||
|         AllowOverride None |  | ||||||
|         Require all granted |  | ||||||
| 
 |  | ||||||
|         RewriteEngine On |  | ||||||
| 
 |  | ||||||
|         # Block direct PHP access |  | ||||||
|         RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] |  | ||||||
|         RewriteRule ^.*$ - [R=404,L] |  | ||||||
| 
 |  | ||||||
|         # Serve the one static file that exists: css/tkr.css |  | ||||||
|         # (Pass requests to css/custom/ through to the PHP app) |  | ||||||
|         RewriteCond %{REQUEST_URI} !^/tkr/css/custom/ |  | ||||||
|         RewriteRule ^css/tkr\.css$ css/tkr.css [L] |  | ||||||
| 
 |  | ||||||
|         # Send everything else to the front controller |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-f |  | ||||||
|         RewriteCond %{REQUEST_FILENAME} !-d |  | ||||||
|         RewriteRule ^(.*)$ index.php [L] |  | ||||||
|     </Directory> |  | ||||||
| 
 |  | ||||||
|     # Error and access logs |  | ||||||
|     ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log |  | ||||||
|     CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined |  | ||||||
| </VirtualHost> |  | ||||||
| @ -1,117 +1,51 @@ | |||||||
| # Example nginx config | # Basic nginx config for tkr | ||||||
| # for serving tkr as a subdomain with SSL | # Replace "your-domain.com" with your actual domain | ||||||
| # e.g. https://tkr.my-domain.com/ | # Replace "/var/www/tkr" with your installation path | ||||||
| # | 
 | ||||||
| # Use SSL in production. | # HTTP - redirect to HTTPS | ||||||
| # This is a minimal SSL confiuration | server { | ||||||
| # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ |     listen 80; | ||||||
|  |     listen [::]:80; | ||||||
|  |     server_name your-domain.com; | ||||||
|  |     return 301 https://$host$request_uri; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # HTTPS | ||||||
| server { | server { | ||||||
|     listen 443 ssl; |     listen 443 ssl; | ||||||
|     listen [::]:443 ssl; |     listen [::]:443 ssl; | ||||||
| 
 |      | ||||||
|     # CONFIG: replace "localhost" with your subdomain (e.g. tkr.my-domain.com) |     server_name your-domain.com; | ||||||
|     server_name localhost; |  | ||||||
| 
 |  | ||||||
|     # CONFIG: |  | ||||||
|     # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) |  | ||||||
|     root /var/www/tkr/public; |     root /var/www/tkr/public; | ||||||
|     index index.php; |     index index.php; | ||||||
| 
 |      | ||||||
|     # CONFIG: |     # SSL Configuration (using Let's Encrypt) | ||||||
|     # Assumes you're using letsencrypt for cert generation |     ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; | ||||||
|     # Replace with the actual paths to your cert and key |     ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; | ||||||
|     ssl_certificate /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem; |      | ||||||
|     ssl_certificate_key /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem; |     # Block access to sensitive directories | ||||||
| 
 |     location ~ ^/(storage|src|templates|config) { | ||||||
|     # Security headers |         deny all; | ||||||
|     # The first rule is to prevent including in a frame on a different domain. |         return 404; | ||||||
|     # Remove it if you want to do that. |     } | ||||||
|     add_header X-Frame-Options "SAMEORIGIN" always; |      | ||||||
|     add_header X-XSS-Protection "1; mode=block" always; |     # Block access to hidden files | ||||||
|     add_header X-Content-Type-Options "nosniff" always; |  | ||||||
| 
 |  | ||||||
|     # Deny access to hidden files |  | ||||||
|     location ~ /\. { |     location ~ /\. { | ||||||
|         deny all; |         deny all; | ||||||
|         access_log off; |  | ||||||
|         log_not_found off; |  | ||||||
|     } |     } | ||||||
| 
 |      | ||||||
|     # PHP routing - everything goes through index.php |     # Front controller pattern - route everything through index.php | ||||||
|     location / { |     location / { | ||||||
|         # Cache static files |         try_files $uri $uri/ @tkr; | ||||||
|         # Note that I don't actually serve most of this (just css) |  | ||||||
|         # but this prevents requests for static content from getting to the PHP handler. |  | ||||||
|         # |  | ||||||
|         # I've excluded /css/custom so that requests for uploaded css can be handled by the PHP app. |  | ||||||
|         # That lets me store uploaded content outside of the document root, |  | ||||||
|         # so it isn't served directly. |  | ||||||
|         location ~* ^/(?!css/custom/).+\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { |  | ||||||
|             expires 1y; |  | ||||||
|             add_header Cache-Control "public, immutable"; |  | ||||||
|             try_files $uri =404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # index.php is the entry point |  | ||||||
|         # It needs to be sent to php-fpm |  | ||||||
|         # But if someone tries to directly access index.php, that file will throw a 404 |  | ||||||
|         # so bots and scanners can't tell this is a php app |  | ||||||
|         location = /index.php { |  | ||||||
|             # CONFIG: |  | ||||||
|             # If you're running php-fpm on the same server as nginx, |  | ||||||
|             # then change this to the local php-fpm socket |  | ||||||
|             # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; |  | ||||||
|             fastcgi_pass php:9000; |  | ||||||
| 
 |  | ||||||
|             # CONFIG: |  | ||||||
|             # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) |  | ||||||
|             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |  | ||||||
|             include fastcgi_params; |  | ||||||
| 
 |  | ||||||
|             fastcgi_param REQUEST_METHOD $request_method; |  | ||||||
|             fastcgi_param REQUEST_URI $request_uri; |  | ||||||
|             fastcgi_param QUERY_STRING $query_string; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Block attempts to access all other .php files directly |  | ||||||
|         # (these are bots and scanners) |  | ||||||
|         location ~ ^/.+\.php$ { |  | ||||||
|             return 404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # forward other requests to the fallback block, |  | ||||||
|         # which sends them to php-fpm for handling |  | ||||||
|         try_files $uri $uri/ @tkr_fallback; |  | ||||||
|     } |     } | ||||||
| 
 |      | ||||||
|     # Fallback for /tkr routing - all non-file requests (e.g. /login) go to index.php |     # Handle PHP requests | ||||||
|     location @tkr_fallback { |     location @tkr { | ||||||
|         # CONFIG: |         fastcgi_pass unix:/run/php/php8.2-fpm.sock;  # Adjust PHP version as needed | ||||||
|         # If you're running php-fpm on the same server as nginx, |  | ||||||
|         # then change this to the local php-fpm socket |  | ||||||
|         # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; |  | ||||||
|         fastcgi_pass php:9000; |  | ||||||
| 
 |  | ||||||
|         # CONFIG: |  | ||||||
|         # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) |  | ||||||
|         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|         include fastcgi_params; |         include fastcgi_params; | ||||||
| 
 |  | ||||||
|         fastcgi_param REQUEST_METHOD $request_method; |         fastcgi_param REQUEST_METHOD $request_method; | ||||||
|         fastcgi_param REQUEST_URI $request_uri; |         fastcgi_param REQUEST_URI $request_uri; | ||||||
|         fastcgi_param QUERY_STRING $query_string; |         fastcgi_param QUERY_STRING $query_string; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     # Deny access to sensitive directories |  | ||||||
|     location ~ ^/(storage|src|templates|uploads|config) { |  | ||||||
|         deny all; |  | ||||||
|         return 404; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| server { |  | ||||||
|     listen 80 default_server; |  | ||||||
|     listen [::]:80 default_server; |  | ||||||
| 
 |  | ||||||
|     return 301 https://$host$request_uri; |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,118 +1,38 @@ | |||||||
| # Example nginx config | # Basic nginx config for tkr in subfolder | ||||||
| # for serving tkr as a subdfolder with SSL | # e.g. https://your-domain.com/tkr | ||||||
| # e.g. https://my-domain.com/tkr | # Add this location block to your existing server configuration | ||||||
| # |  | ||||||
| # Use SSL in production. |  | ||||||
| # This is a minimal SSL confiuration |  | ||||||
| # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ |  | ||||||
| server { |  | ||||||
|     listen 443 ssl; |  | ||||||
|     listen [::]:443 ssl; |  | ||||||
| 
 | 
 | ||||||
|     # CONFIG: Replace localhost with your domain e.g. my-domain.com | location /tkr { | ||||||
|     server_name localhost; |     alias /var/www/tkr/public; | ||||||
|  |     index index.php; | ||||||
| 
 | 
 | ||||||
|     # CONFIG: |     # Handle PHP files | ||||||
|     # Assumes you're using letsencrypt for cert generation |     location ~ \.php$ { | ||||||
|     # Replace with the actual paths to your cert and key |         fastcgi_pass unix:/run/php/php8.2-fpm.sock;  # Adjust PHP version/socket as needed | ||||||
|     ssl_certificate /etc/letsencrypt/live/my-domain.com/fullchain.pem; |  | ||||||
|     ssl_certificate_key /etc/letsencrypt/live/my-domain.com/privkey.pem; |  | ||||||
| 
 |  | ||||||
|     # Security headers |  | ||||||
|     # The first rule is to prevent including in a frame on a different domain. |  | ||||||
|     # Remove it if you want to do that. |  | ||||||
|     add_header X-Frame-Options "SAMEORIGIN" always; |  | ||||||
|     add_header X-XSS-Protection "1; mode=block" always; |  | ||||||
|     add_header X-Content-Type-Options "nosniff" always; |  | ||||||
| 
 |  | ||||||
|     # Deny access to hidden files |  | ||||||
|     location ~ /\. { |  | ||||||
|         deny all; |  | ||||||
|         access_log off; |  | ||||||
|         log_not_found off; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     # PHP routing - everything under /tkr goes through index.php |  | ||||||
|     location /tkr { |  | ||||||
|         # CONFIG: |  | ||||||
|         # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) |  | ||||||
|         alias /var/www/tkr/public; |  | ||||||
|         index index.php; |  | ||||||
| 
 |  | ||||||
|         # Cache static files |  | ||||||
|         # Note that I don't actually serve most of this (just css) |  | ||||||
|         # but this prevents requests for static content from getting to the PHP handler. |  | ||||||
|         # |  | ||||||
|         # I've excluded /css/custom so that requests for uploaded css can be handled by the PHP app. |  | ||||||
|         # That lets me store uploaded content outside of the document root, |  | ||||||
|         # so it isn't served directly. |  | ||||||
|         location ~* ^/tkr/(?!css/custom/).+\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { |  | ||||||
|             expires 1y; |  | ||||||
|             add_header Cache-Control "public, immutable"; |  | ||||||
|             try_files $uri =404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # index.php is the entry point |  | ||||||
|         # It needs to be sent to php-fpm |  | ||||||
|         # But if someone tries to directly access index.php, that file will throw a 404 |  | ||||||
|         # so bots and scanners can't tell this is a php app |  | ||||||
|         location = /tkr/index.php { |  | ||||||
|             # CONFIG: |  | ||||||
|             # If you're running php-fpm on the same server as nginx, |  | ||||||
|             # then change this to the local php-fpm socket |  | ||||||
|             # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; |  | ||||||
|             fastcgi_pass php:9000; |  | ||||||
| 
 |  | ||||||
|             # CONFIG: |  | ||||||
|             # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) |  | ||||||
|             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |  | ||||||
|             include fastcgi_params; |  | ||||||
| 
 |  | ||||||
|             fastcgi_param REQUEST_METHOD $request_method; |  | ||||||
|             fastcgi_param REQUEST_URI $request_uri; |  | ||||||
|             fastcgi_param QUERY_STRING $query_string; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Block attempts to access all other .php files directly |  | ||||||
|         # (these are bots and scanners) |  | ||||||
|         location ~ ^/tkr/.+\.php$ { |  | ||||||
|             return 404; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # forward other requests to the fallback block, |  | ||||||
|         # which sends them to php-fpm for handling |  | ||||||
|         try_files $uri $uri/ @tkr_fallback; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     # Fallback for /tkr routing - all non-file requests (e.g. /login) go to index.php |  | ||||||
|     location @tkr_fallback { |  | ||||||
|         # CONFIG: |  | ||||||
|         # If you're running php-fpm on the same server as nginx, |  | ||||||
|         # then change this to the local php-fpm socket |  | ||||||
|         # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; |  | ||||||
|         fastcgi_pass php:9000; |  | ||||||
| 
 |  | ||||||
|         # CONFIG: |  | ||||||
|         # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) |  | ||||||
|         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |  | ||||||
|         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|         include fastcgi_params; |         include fastcgi_params; | ||||||
| 
 |  | ||||||
|         fastcgi_param REQUEST_METHOD $request_method; |  | ||||||
|         fastcgi_param REQUEST_URI $request_uri; |  | ||||||
|         fastcgi_param QUERY_STRING $query_string; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     # Deny access to sensitive directories |     # Block access to sensitive directories | ||||||
|     location ~ ^/tkr/(storage|src|templates|uploads|config) { |     location ~ ^/tkr/(storage|src|templates|config) { | ||||||
|         deny all; |         deny all; | ||||||
|         return 404; |         return 404; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     # Block access to hidden files | ||||||
|  |     location ~ /\. { | ||||||
|  |         deny all; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # Front controller pattern | ||||||
|  |     try_files $uri $uri/ @tkr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| server { | location @tkr { | ||||||
|     listen 80 default_server; |     fastcgi_pass unix:/run/php/php8.2-fpm.sock;  # Adjust PHP version as needed | ||||||
|     listen [::]:80 default_server; |     fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
| 
 |     include fastcgi_params; | ||||||
|     return 301 https://$host$request_uri; |     fastcgi_param REQUEST_METHOD $request_method; | ||||||
| } |     fastcgi_param REQUEST_URI $request_uri; | ||||||
|  |     fastcgi_param QUERY_STRING $query_string; | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								examples/production/apache/.htaccess
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								examples/production/apache/.htaccess
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | # Example Apache VirtualHost | ||||||
|  | # for serving tkr as a subdirectory path | ||||||
|  | # on shared hosting via .htaccess | ||||||
|  | # | ||||||
|  | # e.g. http://www.my-domain.com/tkr | ||||||
|  | # | ||||||
|  | # This should work without modification if you extract the app | ||||||
|  | # to /tkr from your web document root | ||||||
|  | 
 | ||||||
|  | # Enable mod_rewrite | ||||||
|  | RewriteEngine On | ||||||
|  | 
 | ||||||
|  | # Security headers | ||||||
|  | Header always set X-Frame-Options "SAMEORIGIN" | ||||||
|  | Header always set X-XSS-Protection "1; mode=block" | ||||||
|  | Header always set X-Content-Type-Options "nosniff" | ||||||
|  | 
 | ||||||
|  | # Directory index | ||||||
|  | DirectoryIndex public/index.php | ||||||
|  | 
 | ||||||
|  | # Security: Block direct access to .php files (except through rewrites) | ||||||
|  | RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] | ||||||
|  | RewriteRule ^.*$ - [R=404,L] | ||||||
|  | 
 | ||||||
|  | # Security: Block access to sensitive directories | ||||||
|  | RewriteRule ^(storage|src|templates|examples|config)(/.*)?$ - [F,L] | ||||||
|  | 
 | ||||||
|  | # Security: Block access to hidden files | ||||||
|  | RewriteRule ^\..*$ - [F,L] | ||||||
|  | 
 | ||||||
|  | # Cache CSS files for 1 hour | ||||||
|  | <FilesMatch "\.css$"> | ||||||
|  |     Header set Cache-Control "public, max-age=3600" | ||||||
|  | </FilesMatch> | ||||||
|  | 
 | ||||||
|  | # Serve the one static file that exists: css/default.css | ||||||
|  | # (Pass requests to css/custom/ through to the PHP app) | ||||||
|  | RewriteCond %{REQUEST_URI} !^/css/custom/ | ||||||
|  | RewriteRule ^css/default\.css$ public/css/default.css [L] | ||||||
|  | 
 | ||||||
|  | # 404 all other static files (images, js, fonts, etc.) | ||||||
|  | # so those requests don't hit the PHP app | ||||||
|  | # (this is to reduce load on the PHP app from bots and scanners) | ||||||
|  | RewriteRule \.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$ - [R=404,L] | ||||||
|  | 
 | ||||||
|  | # Everything else goes to the front controller | ||||||
|  | RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  | RewriteCond %{REQUEST_FILENAME} !-d | ||||||
|  | RewriteRule ^(.*)$ public/index.php [L] | ||||||
							
								
								
									
										91
									
								
								examples/production/apache/subfolder.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								examples/production/apache/subfolder.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | |||||||
|  | # Example Apache VirtualHost | ||||||
|  | # for serving tkr as a subdirectory path with SSL | ||||||
|  | # e.g. https://www.my-domain.com/tkr | ||||||
|  | # | ||||||
|  | # Use SSL in production. | ||||||
|  | # This is a minimal SSL confiuration | ||||||
|  | # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ | ||||||
|  | <VirtualHost *:80> | ||||||
|  |     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     ServerName localhost | ||||||
|  |     # CONFIG: Replace  with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     DocumentRoot /var/www/tkr | ||||||
|  |     # Redirect HTTP to HTTPS | ||||||
|  |     Redirect permanent / https://my-domain.com/ | ||||||
|  | </VirtualHost> | ||||||
|  | 
 | ||||||
|  | <VirtualHost *:443> | ||||||
|  |     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     ServerName localhost | ||||||
|  |     # CONFIG: Replace  with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     DocumentRoot /var/www/tkr/ | ||||||
|  | 
 | ||||||
|  |     # SSL Configuration | ||||||
|  |     SSLEngine on | ||||||
|  | 
 | ||||||
|  |     # Assumes you're using letsencrypt for cert generation | ||||||
|  |     # Replace with the actual paths to your cert and key | ||||||
|  |     SSLCertificateFile /etc/letsencrypt/live/my-domain.com/fullchain.pem | ||||||
|  |     SSLCertificateKeyFile /etc/letsencrypt/live/my-domain.com/privkey.pem | ||||||
|  | 
 | ||||||
|  |     # Security headers | ||||||
|  |     Header always set X-Frame-Options "SAMEORIGIN" | ||||||
|  |     Header always set X-XSS-Protection "1; mode=block" | ||||||
|  |     Header always set X-Content-Type-Options "nosniff" | ||||||
|  |     Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" | ||||||
|  | 
 | ||||||
|  |     # tkr Application at /tkr | ||||||
|  |     # NOTE: If you change the directory name, | ||||||
|  |     # remember to update all instances of /var/www/tkr in this file to match | ||||||
|  |     Alias /tkr /var/www/tkr/public | ||||||
|  | 
 | ||||||
|  |     # Block access to sensitive TKR directories | ||||||
|  |     <Directory "/var/www/tkr/storage"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  |     <Directory "/var/www/tkr/src"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  |     <Directory "/var/www/tkr/templates"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  |     <Directory "/var/www/tkr/config"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  | 
 | ||||||
|  |     # 404 all non-css static files in /tkr (images, js, fonts, etc.) | ||||||
|  |     # so those requests don't hit the PHP app | ||||||
|  |     # (this is to reduce load on the PHP app from bots and scanners) | ||||||
|  |     <LocationMatch "^/tkr/.*\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$"> | ||||||
|  |         <RequireAll> | ||||||
|  |             Require all denied | ||||||
|  |         </RequireAll> | ||||||
|  |     </LocationMatch> | ||||||
|  | 
 | ||||||
|  |     # tkr application directory | ||||||
|  |     <Directory "/var/www/tkr/public"> | ||||||
|  |         Options -Indexes | ||||||
|  |         AllowOverride None | ||||||
|  |         Require all granted | ||||||
|  | 
 | ||||||
|  |         RewriteEngine On | ||||||
|  | 
 | ||||||
|  |         # Block direct PHP access | ||||||
|  |         RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] | ||||||
|  |         RewriteRule ^.*$ - [R=404,L] | ||||||
|  | 
 | ||||||
|  |         # Serve the one static file that exists: css/default.css | ||||||
|  |         # (Pass requests to css/custom/ through to the PHP app) | ||||||
|  |         RewriteCond %{REQUEST_URI} !^/tkr/css/custom/ | ||||||
|  |         RewriteRule ^css/default\.css$ css/tkr.css [L] | ||||||
|  | 
 | ||||||
|  |         # Send everything else to the front controller | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-d | ||||||
|  |         RewriteRule ^(.*)$ index.php [L] | ||||||
|  |     </Directory> | ||||||
|  | 
 | ||||||
|  |     # Error and access logs | ||||||
|  |     ErrorLog ${APACHE_LOG_DIR}/my-domain_error.log | ||||||
|  |     CustomLog ${APACHE_LOG_DIR}/my-domain_access.log combined | ||||||
|  | </VirtualHost> | ||||||
							
								
								
									
										99
									
								
								examples/production/apache/tkr.my-domain.com.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								examples/production/apache/tkr.my-domain.com.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | |||||||
|  | # Example Apache VirtualHost | ||||||
|  | # for serving tkr as a subdomain root with SSL | ||||||
|  | # e.g. https://tkr.my-domain.com/ | ||||||
|  | # | ||||||
|  | # Use SSL in production. | ||||||
|  | # This is a minimal SSL confiuration | ||||||
|  | # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ | ||||||
|  | <VirtualHost *:80> | ||||||
|  |     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     ServerName localhost | ||||||
|  |     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     DocumentRoot /var/www/tkr/public | ||||||
|  |     # Redirect HTTP to HTTPS | ||||||
|  |     Redirect permanent / https://tkr.my-domain.com/ | ||||||
|  | </VirtualHost> | ||||||
|  | 
 | ||||||
|  | <VirtualHost *:443> | ||||||
|  |     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     ServerName localhost | ||||||
|  |     # CONFIG: Replace localhost with your subdomain, e.g. tkr.my-domain.com | ||||||
|  |     DocumentRoot /var/www/tkr/public | ||||||
|  | 
 | ||||||
|  |     # SSL Configuration | ||||||
|  |     SSLEngine on | ||||||
|  | 
 | ||||||
|  |     # Assumes you're using letsencrypt for cert generation | ||||||
|  |     # Replace with the actual paths to your cert and key | ||||||
|  |     SSLCertificateFile /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem | ||||||
|  |     SSLCertificateKeyFile /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem | ||||||
|  | 
 | ||||||
|  |     # Security headers | ||||||
|  |     Header always set X-Frame-Options "SAMEORIGIN" | ||||||
|  |     Header always set X-XSS-Protection "1; mode=block" | ||||||
|  |     Header always set X-Content-Type-Options "nosniff" | ||||||
|  |     Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" | ||||||
|  | 
 | ||||||
|  |     # Block access to sensitive directories | ||||||
|  |     <Directory "/var/www/tkr/storage"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  |     <Directory "/var/www/tkr/src"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  |     <Directory "/var/www/tkr/templates"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  |     <Directory "/var/www/tkr/config"> | ||||||
|  |         Require all denied | ||||||
|  |     </Directory> | ||||||
|  | 
 | ||||||
|  |     # Block access to hidden files | ||||||
|  |     <DirectoryMatch "^\.|/\."> | ||||||
|  |         Require all denied | ||||||
|  |     </DirectoryMatch> | ||||||
|  | 
 | ||||||
|  |     # Cache CSS files | ||||||
|  |     <LocationMatch "\.css$"> | ||||||
|  |         Header set Cache-Control "public, max-age=3600" | ||||||
|  |     </LocationMatch> | ||||||
|  | 
 | ||||||
|  |     # Serve static CSS file | ||||||
|  |     Alias /css/tkr.css /var/www/tkr/public/css/tkr.css | ||||||
|  | 
 | ||||||
|  |     # 404 all non-css static files (images, js, fonts, etc.) | ||||||
|  |     # so those requests don't hit the PHP app | ||||||
|  |     # (this is to reduce load on the PHP app from bots and scanners) | ||||||
|  |     <LocationMatch "\.(js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|mp3|mp4|avi|mov)$"> | ||||||
|  |         <RequireAll> | ||||||
|  |             Require all denied | ||||||
|  |         </RequireAll> | ||||||
|  |     </LocationMatch> | ||||||
|  | 
 | ||||||
|  |     # Enable rewrite engine | ||||||
|  |     <Directory "/var/www/tkr/public"> | ||||||
|  |         Options -Indexes | ||||||
|  |         AllowOverride None | ||||||
|  |         Require all granted | ||||||
|  | 
 | ||||||
|  |         RewriteEngine On | ||||||
|  | 
 | ||||||
|  |         # Block direct PHP access | ||||||
|  |         RewriteCond %{THE_REQUEST} \s/[^?\s]*\.php[\s?] [NC] | ||||||
|  |         RewriteRule ^.*$ - [R=404,L] | ||||||
|  | 
 | ||||||
|  |         # Serve the one static file that exists: css/default.css | ||||||
|  |         # (Pass requests to css/custom/ through to the PHP app) | ||||||
|  |         RewriteCond %{REQUEST_URI} !^/css/custom/ | ||||||
|  |         RewriteRule ^css/default\.css$ css/default.css [L] | ||||||
|  | 
 | ||||||
|  |         # Everything else to front controller | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-f | ||||||
|  |         RewriteCond %{REQUEST_FILENAME} !-d | ||||||
|  |         RewriteRule ^(.*)$ index.php [L] | ||||||
|  |     </Directory> | ||||||
|  | 
 | ||||||
|  |     # Error and access logs | ||||||
|  |     ErrorLog ${APACHE_LOG_DIR}/tkr_error.log | ||||||
|  |     CustomLog ${APACHE_LOG_DIR}/tkr_access.log combined | ||||||
|  | </VirtualHost> | ||||||
							
								
								
									
										117
									
								
								examples/production/nginx/nginx.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								examples/production/nginx/nginx.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | |||||||
|  | # Example nginx config | ||||||
|  | # for serving tkr as a subdomain with SSL | ||||||
|  | # e.g. https://tkr.my-domain.com/ | ||||||
|  | # | ||||||
|  | # Use SSL in production. | ||||||
|  | # This is a minimal SSL confiuration | ||||||
|  | # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ | ||||||
|  | server { | ||||||
|  |     listen 443 ssl; | ||||||
|  |     listen [::]:443 ssl; | ||||||
|  | 
 | ||||||
|  |     # CONFIG: replace "localhost" with your subdomain (e.g. tkr.my-domain.com) | ||||||
|  |     server_name localhost; | ||||||
|  | 
 | ||||||
|  |     # CONFIG: | ||||||
|  |     # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) | ||||||
|  |     root /var/www/tkr/public; | ||||||
|  |     index index.php; | ||||||
|  | 
 | ||||||
|  |     # CONFIG: | ||||||
|  |     # Assumes you're using letsencrypt for cert generation | ||||||
|  |     # Replace with the actual paths to your cert and key | ||||||
|  |     ssl_certificate /etc/letsencrypt/live/tkr.my-domain.com/fullchain.pem; | ||||||
|  |     ssl_certificate_key /etc/letsencrypt/live/tkr.my-domain.com/privkey.pem; | ||||||
|  | 
 | ||||||
|  |     # Security headers | ||||||
|  |     # The first rule is to prevent including in a frame on a different domain. | ||||||
|  |     # Remove it if you want to do that. | ||||||
|  |     add_header X-Frame-Options "SAMEORIGIN" always; | ||||||
|  |     add_header X-XSS-Protection "1; mode=block" always; | ||||||
|  |     add_header X-Content-Type-Options "nosniff" always; | ||||||
|  | 
 | ||||||
|  |     # Deny access to hidden files | ||||||
|  |     location ~ /\. { | ||||||
|  |         deny all; | ||||||
|  |         access_log off; | ||||||
|  |         log_not_found off; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # PHP routing - everything goes through index.php | ||||||
|  |     location / { | ||||||
|  |         # Cache static files | ||||||
|  |         # Note that I don't actually serve most of this (just css) | ||||||
|  |         # but this prevents requests for static content from getting to the PHP handler. | ||||||
|  |         # | ||||||
|  |         # I've excluded /css/custom so that requests for uploaded css can be handled by the PHP app. | ||||||
|  |         # That lets me store uploaded content outside of the document root, | ||||||
|  |         # so it isn't served directly. | ||||||
|  |         location ~* ^/(?!css/custom/).+\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { | ||||||
|  |             expires 1y; | ||||||
|  |             add_header Cache-Control "public, immutable"; | ||||||
|  |             try_files $uri =404; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # index.php is the entry point | ||||||
|  |         # It needs to be sent to php-fpm | ||||||
|  |         # But if someone tries to directly access index.php, that file will throw a 404 | ||||||
|  |         # so bots and scanners can't tell this is a php app | ||||||
|  |         location = /index.php { | ||||||
|  |             # CONFIG: | ||||||
|  |             # If you're running php-fpm on the same server as nginx, | ||||||
|  |             # then change this to the local php-fpm socket | ||||||
|  |             # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; | ||||||
|  |             fastcgi_pass php:9000; | ||||||
|  | 
 | ||||||
|  |             # CONFIG: | ||||||
|  |             # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) | ||||||
|  |             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |             include fastcgi_params; | ||||||
|  | 
 | ||||||
|  |             fastcgi_param REQUEST_METHOD $request_method; | ||||||
|  |             fastcgi_param REQUEST_URI $request_uri; | ||||||
|  |             fastcgi_param QUERY_STRING $query_string; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # Block attempts to access all other .php files directly | ||||||
|  |         # (these are bots and scanners) | ||||||
|  |         location ~ ^/.+\.php$ { | ||||||
|  |             return 404; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # forward other requests to the fallback block, | ||||||
|  |         # which sends them to php-fpm for handling | ||||||
|  |         try_files $uri $uri/ @tkr_fallback; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # Fallback for /tkr routing - all non-file requests (e.g. /login) go to index.php | ||||||
|  |     location @tkr_fallback { | ||||||
|  |         # CONFIG: | ||||||
|  |         # If you're running php-fpm on the same server as nginx, | ||||||
|  |         # then change this to the local php-fpm socket | ||||||
|  |         # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; | ||||||
|  |         fastcgi_pass php:9000; | ||||||
|  | 
 | ||||||
|  |         # CONFIG: | ||||||
|  |         # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) | ||||||
|  |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |         include fastcgi_params; | ||||||
|  | 
 | ||||||
|  |         fastcgi_param REQUEST_METHOD $request_method; | ||||||
|  |         fastcgi_param REQUEST_URI $request_uri; | ||||||
|  |         fastcgi_param QUERY_STRING $query_string; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # Deny access to sensitive directories | ||||||
|  |     location ~ ^/(storage|src|templates|uploads|config) { | ||||||
|  |         deny all; | ||||||
|  |         return 404; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | server { | ||||||
|  |     listen 80 default_server; | ||||||
|  |     listen [::]:80 default_server; | ||||||
|  | 
 | ||||||
|  |     return 301 https://$host$request_uri; | ||||||
|  | } | ||||||
							
								
								
									
										118
									
								
								examples/production/nginx/subfolder.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								examples/production/nginx/subfolder.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | # Example nginx config | ||||||
|  | # for serving tkr as a subdfolder with SSL | ||||||
|  | # e.g. https://my-domain.com/tkr | ||||||
|  | # | ||||||
|  | # Use SSL in production. | ||||||
|  | # This is a minimal SSL confiuration | ||||||
|  | # For more robust SSL configuration, refer to https://ssl-config.mozilla.org/ | ||||||
|  | server { | ||||||
|  |     listen 443 ssl; | ||||||
|  |     listen [::]:443 ssl; | ||||||
|  | 
 | ||||||
|  |     # CONFIG: Replace localhost with your domain e.g. my-domain.com | ||||||
|  |     server_name localhost; | ||||||
|  | 
 | ||||||
|  |     # CONFIG: | ||||||
|  |     # Assumes you're using letsencrypt for cert generation | ||||||
|  |     # Replace with the actual paths to your cert and key | ||||||
|  |     ssl_certificate /etc/letsencrypt/live/my-domain.com/fullchain.pem; | ||||||
|  |     ssl_certificate_key /etc/letsencrypt/live/my-domain.com/privkey.pem; | ||||||
|  | 
 | ||||||
|  |     # Security headers | ||||||
|  |     # The first rule is to prevent including in a frame on a different domain. | ||||||
|  |     # Remove it if you want to do that. | ||||||
|  |     add_header X-Frame-Options "SAMEORIGIN" always; | ||||||
|  |     add_header X-XSS-Protection "1; mode=block" always; | ||||||
|  |     add_header X-Content-Type-Options "nosniff" always; | ||||||
|  | 
 | ||||||
|  |     # Deny access to hidden files | ||||||
|  |     location ~ /\. { | ||||||
|  |         deny all; | ||||||
|  |         access_log off; | ||||||
|  |         log_not_found off; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # PHP routing - everything under /tkr goes through index.php | ||||||
|  |     location /tkr { | ||||||
|  |         # CONFIG: | ||||||
|  |         # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) | ||||||
|  |         alias /var/www/tkr/public; | ||||||
|  |         index index.php; | ||||||
|  | 
 | ||||||
|  |         # Cache static files | ||||||
|  |         # Note that I don't actually serve most of this (just css) | ||||||
|  |         # but this prevents requests for static content from getting to the PHP handler. | ||||||
|  |         # | ||||||
|  |         # I've excluded /css/custom so that requests for uploaded css can be handled by the PHP app. | ||||||
|  |         # That lets me store uploaded content outside of the document root, | ||||||
|  |         # so it isn't served directly. | ||||||
|  |         location ~* ^/tkr/(?!css/custom/).+\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { | ||||||
|  |             expires 1y; | ||||||
|  |             add_header Cache-Control "public, immutable"; | ||||||
|  |             try_files $uri =404; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # index.php is the entry point | ||||||
|  |         # It needs to be sent to php-fpm | ||||||
|  |         # But if someone tries to directly access index.php, that file will throw a 404 | ||||||
|  |         # so bots and scanners can't tell this is a php app | ||||||
|  |         location = /tkr/index.php { | ||||||
|  |             # CONFIG: | ||||||
|  |             # If you're running php-fpm on the same server as nginx, | ||||||
|  |             # then change this to the local php-fpm socket | ||||||
|  |             # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; | ||||||
|  |             fastcgi_pass php:9000; | ||||||
|  | 
 | ||||||
|  |             # CONFIG: | ||||||
|  |             # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) | ||||||
|  |             fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |             include fastcgi_params; | ||||||
|  | 
 | ||||||
|  |             fastcgi_param REQUEST_METHOD $request_method; | ||||||
|  |             fastcgi_param REQUEST_URI $request_uri; | ||||||
|  |             fastcgi_param QUERY_STRING $query_string; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # Block attempts to access all other .php files directly | ||||||
|  |         # (these are bots and scanners) | ||||||
|  |         location ~ ^/tkr/.+\.php$ { | ||||||
|  |             return 404; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         # forward other requests to the fallback block, | ||||||
|  |         # which sends them to php-fpm for handling | ||||||
|  |         try_files $uri $uri/ @tkr_fallback; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # Fallback for /tkr routing - all non-file requests (e.g. /login) go to index.php | ||||||
|  |     location @tkr_fallback { | ||||||
|  |         # CONFIG: | ||||||
|  |         # If you're running php-fpm on the same server as nginx, | ||||||
|  |         # then change this to the local php-fpm socket | ||||||
|  |         # e.g. fastcgi_pass unix:/run/php/php8.2-fpm.sock; | ||||||
|  |         fastcgi_pass php:9000; | ||||||
|  | 
 | ||||||
|  |         # CONFIG: | ||||||
|  |         # replace "/var/www/tkr" with the directory you extracted the .zip file to (if different) | ||||||
|  |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |         fastcgi_param SCRIPT_FILENAME /var/www/tkr/public/index.php; | ||||||
|  |         include fastcgi_params; | ||||||
|  | 
 | ||||||
|  |         fastcgi_param REQUEST_METHOD $request_method; | ||||||
|  |         fastcgi_param REQUEST_URI $request_uri; | ||||||
|  |         fastcgi_param QUERY_STRING $query_string; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     # Deny access to sensitive directories | ||||||
|  |     location ~ ^/tkr/(storage|src|templates|uploads|config) { | ||||||
|  |         deny all; | ||||||
|  |         return 404; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | server { | ||||||
|  |     listen 80 default_server; | ||||||
|  |     listen [::]:80 default_server; | ||||||
|  | 
 | ||||||
|  |     return 301 https://$host$request_uri; | ||||||
|  | } | ||||||
| @ -50,7 +50,7 @@ class AdminController extends Controller { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $result = $this->saveSettings($_POST, false); |         $result = $this->saveSettings($_POST, false); | ||||||
|         header('Location: ' . $_SERVER['PHP_SELF']); |         header('Location: ' . $_SERVER['REQUEST_URI']); | ||||||
|         exit; |         exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -58,7 +58,7 @@ class AdminController extends Controller { | |||||||
|         // for setup, we don't care if they're logged in
 |         // for setup, we don't care if they're logged in
 | ||||||
|         // (because they can't be until setup is complete)
 |         // (because they can't be until setup is complete)
 | ||||||
|         $result = $this->saveSettings($_POST, true); |         $result = $this->saveSettings($_POST, true); | ||||||
|         header('Location: ' . $_SERVER['PHP_SELF']); |         header('Location: ' . $_SERVER['REQUEST_URI']); | ||||||
|         exit; |         exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ class AuthController extends Controller { | |||||||
|                     } catch (Exception $e) { |                     } catch (Exception $e) { | ||||||
|                         Log::error("Failed to create login session for {$username}: " . $e->getMessage()); |                         Log::error("Failed to create login session for {$username}: " . $e->getMessage()); | ||||||
|                         Session::setFlashMessage('error', 'Login failed - session error'); |                         Session::setFlashMessage('error', 'Login failed - session error'); | ||||||
|                         header('Location: ' . $_SERVER['PHP_SELF']); |                         header('Location: ' . $_SERVER['REQUEST_URI']); | ||||||
|                         exit; |                         exit; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
| @ -47,13 +47,13 @@ class AuthController extends Controller { | |||||||
| 
 | 
 | ||||||
|                     // Set a flash message and reload the login page
 |                     // Set a flash message and reload the login page
 | ||||||
|                     Session::setFlashMessage('error', 'Invalid username or password'); |                     Session::setFlashMessage('error', 'Invalid username or password'); | ||||||
|                     header('Location: ' . $_SERVER['PHP_SELF']); |                     header('Location: ' . $_SERVER['REQUEST_URI']); | ||||||
|                     exit; |                     exit; | ||||||
|                 } |                 } | ||||||
|             } catch (Exception $e) { |             } catch (Exception $e) { | ||||||
|                 Log::error("Database error during login for {$username}: " . $e->getMessage()); |                 Log::error("Database error during login for {$username}: " . $e->getMessage()); | ||||||
|                 Session::setFlashMessage('error', 'Login temporarily unavailable'); |                 Session::setFlashMessage('error', 'Login temporarily unavailable'); | ||||||
|                 header('Location: ' . $_SERVER['PHP_SELF']); |                 header('Location: ' . $_SERVER['REQUEST_URI']); | ||||||
|                 exit; |                 exit; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -20,32 +20,54 @@ class CssController extends Controller { | |||||||
|         global $app; |         global $app; | ||||||
|         $cssModel = new CssModel($app['db']); |         $cssModel = new CssModel($app['db']); | ||||||
|         $filename = "$baseFilename.css"; |         $filename = "$baseFilename.css"; | ||||||
|  |         Log::debug("Attempting to serve custom css: {$filename}"); | ||||||
| 
 | 
 | ||||||
|  |         // Make sure the file exists in the database
 | ||||||
|         $cssRow = $cssModel->getByFilename($filename); |         $cssRow = $cssModel->getByFilename($filename); | ||||||
| 
 |  | ||||||
|         if (!$cssRow){ |         if (!$cssRow){ | ||||||
|             http_response_code(404); |             http_response_code(404); | ||||||
|             exit("CSS file not found: $filename"); |             Log::error("Custom css file not in database: {$filename}"); | ||||||
|  |             exit; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // Make sure the file exists on the filesystem and is readable
 | ||||||
|         $filePath = CSS_UPLOAD_DIR . "/$filename"; |         $filePath = CSS_UPLOAD_DIR . "/$filename"; | ||||||
| 
 |  | ||||||
|         if (!file_exists($filePath) || !is_readable($filePath)) { |         if (!file_exists($filePath) || !is_readable($filePath)) { | ||||||
|             http_response_code(404); |             http_response_code(404); | ||||||
|             exit("CSS file not found: $filePath"); |             Log::error("Custom css file not found or not readable: $filePath"); | ||||||
|  |             exit; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // This shouldn't be possible, but I'm being extra paranoid
 |         // Make sure the file has a .css extension
 | ||||||
|         // about user input
 |  | ||||||
|         $ext = strToLower(pathinfo($filename, PATHINFO_EXTENSION)); |         $ext = strToLower(pathinfo($filename, PATHINFO_EXTENSION)); | ||||||
|         if($ext != 'css'){ |         if($ext != 'css'){ | ||||||
|             http_response_code(400); |             http_response_code(400); | ||||||
|             exit("Invalid file type requested: $ext"); |             Log::error("Invalid file type requested: $ext"); | ||||||
|  |             exit; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // If we get here, serve the file
 | ||||||
|  |         Log::debug("Serving custom css: {$filename}"); | ||||||
|         header('Content-type: text/css'); |         header('Content-type: text/css'); | ||||||
|         header('Cache-control: public, max-age=3600'); |         header('Cache-control: public, max-age=3600'); | ||||||
|  |         readfile($filePath); | ||||||
|  |         exit; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     public function serveDefaultCss(){ | ||||||
|  |         $filePath = PUBLIC_DIR . '/css/default.css'; | ||||||
|  |         Log::debug("Serving default css: {$filePath}"); | ||||||
|  | 
 | ||||||
|  |         // Make sure the default CSS file exists and is readable
 | ||||||
|  |         if (!file_exists($filePath) || !is_readable($filePath)) { | ||||||
|  |             http_response_code(404); | ||||||
|  |             Log::error("Default CSS file not found"); | ||||||
|  |             exit; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //  Serve the file
 | ||||||
|  |         header('Content-type: text/css'); | ||||||
|  |         header('Cache-control: public, max-age=3600'); | ||||||
|         readfile($filePath); |         readfile($filePath); | ||||||
|         exit; |         exit; | ||||||
|     } |     } | ||||||
| @ -64,7 +86,7 @@ class CssController extends Controller { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // redirect after handling to avoid resubmitting form
 |         // redirect after handling to avoid resubmitting form
 | ||||||
|         header('Location: ' . $_SERVER['PHP_SELF']); |         header('Location: ' . $_SERVER['REQUEST_URI']); | ||||||
|         exit; |         exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -129,7 +151,7 @@ class CssController extends Controller { | |||||||
|         try { |         try { | ||||||
|             if ($_POST['selectCssFile']){ |             if ($_POST['selectCssFile']){ | ||||||
|                 // Set custom theme
 |                 // Set custom theme
 | ||||||
|                 $app['settings']->cssId = $_POST['selectCssFile']; |                 $app['settings']->cssId = (int)($_POST['selectCssFile']); | ||||||
|             } else { |             } else { | ||||||
|                 // Set default theme
 |                 // Set default theme
 | ||||||
|                 $app['settings']->cssId = null; |                 $app['settings']->cssId = null; | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ class Router { | |||||||
|         ['tick/{id}', 'TickController'], |         ['tick/{id}', 'TickController'], | ||||||
|         ['tick/{id}/delete', 'TickController@handleDelete', ['POST']], |         ['tick/{id}/delete', 'TickController@handleDelete', ['POST']], | ||||||
|         ['css/custom/{filename}.css', 'CssController@serveCustomCss'], |         ['css/custom/{filename}.css', 'CssController@serveCustomCss'], | ||||||
|  |         ['css/default.css', 'CssController@serveDefaultCss'], | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user