With regards to Mohammad's answer, permissions should never be set to 777.
The problem here is that newly generated files are owned by the user and group who issues the command
$USER:$USER, where they should belong to
$USER:apache. Because apache2 does not have access to the group
$USER, the website cannot be properly served.
In order to retain proper permissions, magento commands should be executed as the apache user.
$ sudo -u www-data php bin/magento setup:upgrade
$ sudo -u apache php bin/magento setup:upgrade
This way, new files are owned by
www-data:www-data (in the case of ubuntu).
So long as you have properly followed Magento's documentation with regards to permissions and added the cli user to the apache2 group, then you will have proper access to the files.
If you did not follow this documentation then you can execute the following command to do so:
$ sudo usermod -a -G www-data $USER
$ sudo usermod -a -G apache $USER
In order that commands can be executed without declaring the apache2 user, Daniel's answer explains that we can modify how the Magento framework sets permissions for new files.
If you are having trouble installing/updating via composer or deploying to production, then you can simply grant ownership of any inaccessible files (these are highlighted yellow in the terminal) to
www-data by issuing the following command:
sudo chown www-data:www-data "/absolute/path/to/file.json"
Then, follow BrunoBueno's answer, applying the above fix:
$ sudo -u www-data bin/magento setup:upgrade
$ sudo -u www-data bin/magento indexer:reindex
$ sudo -u www-data bin/magento deploy:mode:set production -s
$ sudo -u www-data bin/magento setup:di:compile (Here was the secret, to run the di:compile after production)
$ sudo -u www-data bin/magento setup:static-content:deploy