Der Beste Weg symbolische Links zu erstellen ist ein Out-Of-The-Box Feature seit Laravel Version 5.3+. Hierfür gibt es einen artisan Befehl der den Symlink (symbolischer Link) erzeugt:

php artisan storage:link

Dieser Befehl erstellt einen Symlink in public/storage auf storage/app/public und das war es dann. Jede Datei in /storage/app/public kann dann per Link erreicht werden:

https://deine-domain.de/storage/image.jpg

Sollten, aus welchen Gründen auch immer, keine Symlinks erstellt werden können (ggf. verbietet es der Hoster etc.) oder es soll eine Zugriffslogik für Dateien geben, gibt es alternativ die Möglichkeit eine Route anzulegen für Anhänge oder Dateien. Beispielsweise nachfolgend eine sehr einfache Variante einer Custom storage Route:

Route::get('storage/{filename}', function ($filename) {
  $path = storage_path('public/' . $filename);

  // Prüfe, ob die Datei überhaupt existiert
  if (!File::exists($path)) {
    abort(404);
  }

  // Hole das File Object
  $file = File::get($path);
  $type = File::mimeType($path);

  // Bereite Response vor
  $response = Response::make($file, 200);
  $response->header("Content-Type", $type); // setze korrekte Header

  return $response;
});

Nun können ebenfalls Dateien erreicht werden, wie als ob ein Symlink existiert:

https://deine-domain.de/storage/image.jpg

Bei der Verwendung der Intervention Image Library kann auch die eingebaute Response Funktion genutzt werden:

Route::get('storage/{filename}', function ($filename) {
  return Image::make(storage_path('public/' . $filename))->response();
});
Manuelles bereitstellen von Dateien durch eine Funktion wirkt sich auf die Performance aus, weil der gesamte Laravel Request Lebenszyklus durchlaufen werden muss! Normalerweise stellt der Server die Dateien direkt bereit ohne Laravel.