Troubleshooting
Nette Is Not Working, White Page Is Displayed
- Try putting
ini_set('display_errors', '1'); error_reporting(E_ALL);
afterdeclare(strict_types=1);
in theindex.php
file to force the display of errors - If you still see a white screen, there is probably an error in the server setup and you will discover the reason in the server
log. To be sure, check if PHP is working at all by trying to print something using
echo 'test';
. - If you see an error Server Error: We're sorry! …, continue with the next section:
Error 500 Server Error: We're sorry! …
This error page is displayed by Nette in production mode. If you see it on your development machine, switch to developer mode and Tracy will display with a detailed report.
You can always find the reason for the error in the log/
directory. However, if the error message shows the phrase
Tracy is unable to log error
, first determine why errors cannot be logged. You can do this, for example, by
temporarily switching to developer
mode and letting Tracy log anything after its launch:
// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // your IP address
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');
Tracy will inform you why it cannot log. The cause might be insufficient
permissions to write to the log/
directory.
One of the most common reasons for a 500 error is outdated cache. While Nette smartly updates the cache automatically in
development mode, in production mode it focuses on maximizing performance, and clearing the cache after each code modification is
up to you. Try deleting temp/cache
.
Error 404, Routing Not Working
When all pages (except the homepage) return a 404 error, it looks like a server configuration problem for pretty URLs.
How to Disable Cache During Development?
Nette is smart, and you don't need to disable caching in it. During development, it automatically updates the cache whenever there's a change in the template or the DI container configuration. Moreover, the development mode is activated by auto-detection, so there's usually no need to configure anything, or just the IP address.
When debugging the router, we recommend disabling the browser cache, where, for example, redirects might be stored: open Developer Tools (Ctrl+Shift+I or Cmd+Option+I) and in the Network panel, check the box to disable the cache.
Error
#[\ReturnTypeWillChange] attribute should be used
This error occurs if you have upgraded PHP to version 8.1 but are using Nette, which is not compatible with it. So the
solution is to update Nette to a newer version using composer update
. Nette has supported PHP 8.1 since version
3.0. If you are using an older version (you can find out by looking in composer.json
), upgrade Nette or stay with PHP 8.0.
Setting Directory Permissions
If you're developing on macOS or Linux (or any other Unix based system), you need to configure write privileges to the web
server. Assuming your application is located in the default directory /var/www/html
(Fedora, CentOS, RHEL)
cd /var/www/html/MY_PROJECT
chmod -R a+rw temp log
On some Linux systems (Fedora, CentOS, …) SELinux may be enabled by default. You may need to update SELinux policies, or set
paths of temp
and log
directories with correct SELinux security context. Directories temp
and log
should be set to httpd_sys_rw_content_t
context; for the rest of the application – mainly
app
folder – httpd_sys_content_t
context will be enough. Run on the server as root:
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MY_PROJECT/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MY_PROJECT/temp(/.*)?'
restorecon -Rv /var/www/html/MY_PROJECT/
Next, the SELinux boolean httpd_can_network_connect_db
needs to be enabled to permit Nette to connect to the
database over network. By default, it is disabled. The command setsebool
can be used to perform this task, and if the
option -P
is specified, this setting will be persistent across reboots.
setsebool -P httpd_can_network_connect_db on
How to Change or Remove www
Directory from URL?
The www/
directory used in the sample projects in Nette is the so-called public directory or document-root of the
project. It is the only directory whose contents are accessible to the browser. And it contains the index.php
file,
the entry point that starts a web application written in Nette.
To run the application on the hosting, you need to set the document-root to this directory in the hosting configuration. Or, if
the hosting has a pre-made folder for the public directory with a different name (for example web
,
public_html
etc.), simply rename www/
.
The solution is not to prevent access to all folders except www/
using rules in the .htaccess
file or in the router. If your hosting does not allow setting the document root to a subdirectory (i.e., creating directories a
level above the public directory), you should look for a different hosting service. Otherwise, you would be exposing yourself to
significant security risks. It would be like living in an apartment where the front door cannot be closed and is always
wide open.
How to Configure a Server for Nice URLs?
Apache: you need to enable and set mod_rewrite rules in the .htaccess
file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz)$ index.php [L]
If you run into problems, make sure that:
- the
.htaccess
file is located in the document-root directory (i.e. next to theindex.php
file) - Apache is processing the files .htaccess
- mod_rewrite is enabled
If you're setting up application in a subfolder, you might have to uncomment the line for the RewriteBase
setting
and set it to the correct folder.
nginx: the try_files
directive should be used in server configuration:
location / {
try_files $uri $uri/ /index.php$is_args$args; # $is_args$args IS IMPORTANT!
}
Block location
must be defined exactly once for each filesystem path in server
block. If you already
have a location /
block in your configuration, add the try_files
directive into the existing block.
Test If .Htaccess
Is Working
The simplest way to test if Apache uses or ignores your .htaccess
file, is to intentionally break it. Put the line
Test
at the beginning of the file and now, if you refresh the page in your browser, you should see an Internal
Server Error.
If you see this error, that's actually good! This means that Apache is parsing the .htaccess
file, and it
encounters the error we've put in there. Remove the line Test
.
If you do not see an Internal Server Error, your Apache setup ignores the .htaccess
file. Generally,
Apache ignores it because of the missing configuration directive AllowOverride All
.
If you are hosting it yourself, it's easy enough to fix. Open your httpd.conf
or apache.conf
in a
text editor, locate the relevant <Directory>
section and add/change the directive:
<Directory "/var/www/htdocs"> # path to your document root
AllowOverride All
...
If your site is hosted elsewhere, check your control panel to see if you can enable .htaccess
there. If not,
contact your hosting provider to do it for you.
Test If mod_rewrite
Is Enabled
If you have verified that .htaccess
works, you can verify that the
mod_rewrite extension is enabled. Put the line RewriteEngine On
at the beginning of the .htaccess
file
and refresh the page in your browser. If you see an Internal Server Error, it means that mod_rewrite is not enabled.
There are a number of ways to enable it. See Stack Overflow for various ways this may be done on different setups.
Links Are Generated Without https:
Nette generates links with the same protocol as the current page is using. So on the https://foo
page, it
generates links starting with https:
and vice versa. If you're behind an HTTPS-stripping reverse proxy (for example,
in Docker), then you need to set up a proxy in configuration to make the protocol
detection work properly.
If you use Nginx as a proxy, you need to have redirection set up like this:
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_pass http://IP-aplikace:80; # IP or hostname of the server/container where the application is running
}
Next, you need to specify the IP proxy and, if applicable, the IP range of your local network where you run the infrastructure:
http:
proxy: IP-proxy/IP-range
Use of Characters { } in JavaScript
Characters {
and }
are used for writing Latte tags. Everything (except space and quotation mark)
following the {
character is considered a tag. If you need to print character {
(often in JavaScript),
you can put a space (or other empty character) right after {
. By this you avoid interpreting it as a tag.
If it's necessary to print these characters in a situation where they would be interpreted as a tag you can use specials tags
to print out these characters – {l}
for {
and {r}
for }
.
{is tag}
{ is not tag }
{l}is not tag{r}
Notice Presenter::getContext() is deprecated
Nette is by far the first PHP framework that switched to dependency injection and led programmers to use it consistently,
starting from the presenters. If a presenter needs a dependency, it will
ask for it. In contrast, the way we pass the entire DI container to a class and it pulls the dependencies from it directly is
considered an antipattern (it's called a service locator). This way was used in Nette 0.x before the advent of dependency
injection, and its relic is the method Presenter::getContext()
, long ago marked as deprecated.
If you port a very old Nette application, you may find that it still uses this method. So since version 3.1 of
nette/application
you will encounter the warning
Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection
, since version 4.0 you will
encounter the error that the method does not exist.
The clean solution, of course, is to redesign the application to pass dependencies using dependency injection. As a workaround,
you can add your own getContext()
method to your base presenter and bypass the message:
abstract BasePresenter extends Nette\Application\UI\Presenter
{
private Nette\DI\Container $context;
public function injectContext(Nette\DI\Container $context)
{
$this->context = $context;
}
public function getContext(): Nette\DI\Container
{
return $this->context;
}
}