Forge alternative. Host a Laravel website on any VPS with ease using dokku
For an introduction to dokku: https://gyaaniguy.top/blog/dokku/
In Brief: dokku is an application to manage hosting websites easily on your own server. It does so by using docker. Automating the tasks of installing servers/databases, configuring various services, running, building, handling ssl etc.
General steps:
First install dokku on your server. Then create a dokku project on the server. Setup ssl, some options, environment variables for laravel.
Next we configure our laravel project
- PHPâs composer.json file. Dokku uses it to install PHP extensions
- add dokku configurations files in our laravel project.
Then we configure sqlite. Which is default database in laravel v11
Finally we have a workaround to deal with viteâs quirk.
Create dokku application
Run on your server.
!! Set the 2 variables below !!
APP_NAME="p2" ; DOMAIN="p2.gyaaniguy.top" ;
# Create the app
dokku apps:create "$APP_NAME"
# Set the domain
dokku domains:set "$APP_NAME" "$DOMAIN"
# Enable Let's Encrypt for SSL
dokku letsencrypt:enable "$APP_NAME"
# Setup Environment Variables
dokku config:set "$APP_NAME" APP_NAME="$APP_NAME" APP_ENV="production"
dokku config:set "$APP_NAME" APP_KEY=$(dokku run "$APP_NAME" php artisan key:generate --show)
Note: environment variables, to configure laravel are passed via dokku config:set KEY_NAME=value
. These are typically stored in .env file
Setup composer.json
Weâll need to explicitly tell dokku to install php extensions, like ext-pdo_sqlite.
Add php extensions to the `require` section in composer.json . Adjust your PHP version appropriately. Note the pdo_sqlite line for sqlite. Mariadb / postgres will require different extensions.
"require": {
"ext-ctype": "*",
"ext-curl": "*",
"ext-exif": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
"ext-openssl": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
"ext-zip": "*",
"ext-pdo_sqlite": "*"
},
Now Run composer update
on local
Local dokku settings
We will add a few more files in your laravel app
.buildpacks
file in root of laravel project
https://github.com/heroku/heroku-buildpack-php
https://github.com/heroku/heroku-buildpack-nodejs
!!! Order is important !!
These instruct dokku to run commands like composer install
nodejs is used to run frontend vite/laravel_mix build commands. Its optional, but laravel uses @vite as a default. If you are not using vite, then of course you can exclude the nodejs build process.
Procfile
file in root of laravel project, to run migrations
release: php artisan migrate --force
web: vendor/bin/heroku-php-apache2 public/
Now push your project to the server. See the Intro article for instructions
Set APP_Key
This is an encryption used by laravel. There should be a better way of generating it. But I canât quite figure it out !
dokku run "$APP_NAME" php artisan key:generate --show
Copy the output - base64:Ng9mTA83j+Y7FZJSj22oSa6zw6r260Y9VRot01xG80U=
Then paste here
dokku config:set "$APP_NAME" APP_KEY="PASTE_HERE"
# dokku config:set "$APP_NAME" APP_KEY="base64:Ng9mTA83j+Y7FZJSj22oSa6zw6r260Y9VRot01xG80U="
Setup Database (sqlite)
Dokku runs in containers, which get destroyed everytime the website is deployed. Hence its important to keep database files outside the container. We do this by creating a directory on the server, then mounting it in the container. Thankfully dokku makes this easy !
# Create a directory for storage
dokku storage:ensure-directory "$APP_NAME"
# Mount it on app container
dokku storage:mount "$APP_NAME" "/var/lib/dokku/data/storage/$APP_NAME:/app/databasedir"
# Set environment variable for laravel
dokku config:set "$APP_NAME" DB_DATABASE=/app/databasedir/database.sqlite DB_CONNECTION=sqlite
PS: More settings are needed for sqlite as shown previously
Fix https error with vite
If you are using Vite, you may get https issues with css/js files. Why ?
Because your dokku app could be behind a âreverse proxyâ
Mixed Content: The page at âdomain.comâ was loaded over HTTPS, but requested an insecure âŠ
Normal: User -> Apache -> site
Dokku: User -> Nginx -> {sends request to} -> Docker_Container(has apache or nginx) -> site
Some headers sent by the user, are lost. Instead nginx manually sends headers to apache, but apache doesnât know who is sending those headers. The user could be naughty ! So we tell apache to trust some headers, as they are being sent by a known proxy.
Add a middleware to bootstrap/app.php
file.
use Symfony\Component\HttpFoundation\Request;
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(headers:
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB
);
$middleware->trustProxies(at: '*');
})
Ideally laravel should handle this automaticallyâŠ
Troubleshooting
dokku logs "$APP_NAME"
- Run
composer update
after modifying composer.json - Enable and set logs. They will log important errors !
# Set the environment variables to enable log.
# set LOG_LEVEL=info to see more entries. Check laravel docs for more.
dokku config:set "$APP_NAME" APP_DEBUG=true
# enter the docker container
docker exec -it $(docker ps | grep "$APP_NAME" | awk 'NR==1 {print $1}') bash
# watch logs
tail -f /app/storage/log/logging.txt
- Check if vite is being used.
@vite()
- .buildpacks and Procfile file names are case-sensitive.
- Order of .buildpacks file
- Is sqlite being installed properly ? Check the
git push
log. It contains a lot of useful info
If log is empty. Then add some logging Log::debug('manual debug message');
References:
https://dev.to/vdsmartin/deploying-a-laravel-app-using-dokku-5bi3 https://laracasts.com/discuss/channels/vite/laravel-vite-assets-blockedmixed-content-issues-in-production-environment