GyaaniGuy

- self made đŸ’» 😎

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


dated July 2024