Cookies / Session not being set in Laravel 8.1 on Railway (works locally)
ddscosta
HOBBYOP

a month ago

Hi everyone,

I'm hosting a Laravel 8.1 application on Railway using a custom Dockerfile.
Everything works perfectly in my local WAMP environment, but on Railway Laravel sessions don’t persist — cookies are never set, and every request returns an empty cookie array.

Issue Summary

  • Locally (APP_ENV=local) everything works fine:

    {"session_id":"ZqZ37PRCiWW8SDin3nDo7Q1VlFjo8z8VjAcEvCSL","cookies":{"XSRF-TOKEN":"...","laravel_session":"..."}}
    
  • On Railway:

    {"session_id":"HvE8zFLPlTy3XBTOEM4oE68l41Rw8gl0vFjAx56m","cookies":[]}
    
  • So Laravel can generate the CSRF token and session ID, but the Set-Cookie header never reaches the browser.

  • Because of that, /login and any session-based routes fail silently or throw 419 errors.

Environment

  • PHP 8.1 (official php:8.1-apache base image)

  • Laravel 8.83.29

  • MySQL (Railway-provided container)

  • HTTPS on https://syrios.up.railway.app

Relevant .env configuration

APP_ENV=production
APP_DEBUG=true
APP_URL=https://syrios.up.railway.app
SESSION_DRIVER=cookie
SESSION_DOMAIN=syrios.up.railway.app
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=None
SESSION_COOKIE=syrios_session

I've also tried:

  • SESSION_DRIVER=file

  • Removing quotes around values

  • Setting SESSION_SECURE_COOKIE=false

  • Forcing APP_ENV=local

None of these worked — cookies still don’t appear in the browser.

Debug endpoints

I added test routes to verify headers and sessions:

  • /debug-headers → shows correct x-forwarded-proto: https

  • /session-debug → always returns "cookies": []

  • /cookie-test → returns 200 OK, but still no cookies are stored.

Dockerfile snippet

RUN a2enmod rewrite headers && \
    echo '\
<IfModule mod_headers.c>\n\
    RequestHeader set X-Forwarded-Proto "https"\n\
    RequestHeader set X-Forwarded-Port "443"\n\
    RequestHeader set X-Forwarded-Host "syrios.up.railway.app"\n\
</IfModule>\n' >> /etc/apache2/apache2.conf

TrustProxies in Laravel is configured as:

protected $proxies = '*';
protected $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;

Still, the browser receives no Set-Cookie headers at all.

What I suspect

It looks like Railway’s proxy layer or Cloudflare (if used internally) might be stripping or blocking Set-Cookie headers when SameSite=None or Secure are set, similar to this older issue:

“Railway stripping cookie headers” — https://community.railway.app/t/railway-stripping-cookie-headers/3855

If that’s the case, maybe Railway’s edge or HTTP forwarding rules need to be adjusted for Set-Cookie.

Question

  • Is there any known limitation or proxy configuration on Railway that could strip Set-Cookie headers (especially with SameSite=None; Secure)?

  • Is there a recommended workaround for Laravel or Apache to make cookies pass correctly through Railway’s edge?

  • Would switching to SESSION_DRIVER=file help persist sessions in this environment, or is there a proxy-safe setup for cookies?

Thanks in advance for your help — I’ve been debugging this for a while and can provide logs or Dockerfile details if needed.

David Costa
(Developer of Syrios, an education management system)

$10 Bounty

9 Replies

Railway
BOT

a month ago

Hey there! We've found the following might help you get unblocked faster:

If you find the answer from one of these, please let us know by solving the thread!


hey, using LLMs/AI is fine, but this is just making it harder for people to help you out as we have to read all of what you've said.

you need to drop SESSION_DOMAIN & let laravel use the request host, then modify to rely on trustproxies vs. using apache x-forward headers. your HTTPS settings should be SESSION_SECURE_COOKIE=true, SESSION_SAME_SITE=None, APP_URL=https://xxxx.com then it should work fine for cookies to pass.


ddscosta
HOBBYOP

a month ago

Thanks for your quick reply!

This is already the third hosting provider I’ve tested with my Laravel app — Render, Koyeb, and now Railway — and all have the same issue:

The Laravel session is created (session_id and csrf_token exist),
but no cookie is returned to the browser ("cookies":[]).

So the Set-Cookie header seems to be blocked or stripped in transit — Laravel generates it, but it never reaches the client.

I’ve already applied all common fixes:

  • SESSION_SECURE_COOKIE=true

  • SESSION_SAME_SITE=None

  • Removed SESSION_DOMAIN

  • TrustProxies set to * with HEADER_X_FORWARDED_ALL

  • Correct APP_URL=https://syrios.up.railway.app

Yet the cookie still doesn’t appear in the response.

Could you confirm if Railway’s proxy filters or removes Set-Cookie headers (e.g., those with SameSite=None or without an explicit domain)?
Or if any extra configuration is needed to allow cookies on .up.railway.app apps?

Thanks in advance for your help and great platform!


ddscosta

Thanks for your quick reply!This is already the third hosting provider I’ve tested with my Laravel app — Render, Koyeb, and now Railway — and all have the same issue:The Laravel session is created (session_id and csrf_token exist),but no cookie is returned to the browser ("cookies":[]).So the Set-Cookie header seems to be blocked or stripped in transit — Laravel generates it, but it never reaches the client.I’ve already applied all common fixes:SESSION_SECURE_COOKIE=trueSESSION_SAME_SITE=NoneRemoved SESSION_DOMAINTrustProxies set to * with HEADER_X_FORWARDED_ALLCorrect APP_URL=https://syrios.up.railway.appYet the cookie still doesn’t appear in the response.Could you confirm if Railway’s proxy filters or removes Set-Cookie headers (e.g., those with SameSite=None or without an explicit domain)?Or if any extra configuration is needed to allow cookies on .up.railway.app apps?Thanks in advance for your help and great platform!

i'm not a railway employee, but do you have CORS with Access-Control-Allow-Credentials: true added, or Access-Control-Allow-Origin? can you attempt to implement Access-Control-Allow-Origins with a middleware?


ddscosta
HOBBYOP

a month ago

Thanks again for the support!

After debugging my Laravel app hosted on Railway, I confirmed that:

  • Laravel successfully creates the session (session_id + csrf_token exist);

  • But the browser receives no Set-Cookie header — cookies are never stored;

  • HTTPS and all X-Forwarded-* headers are correct.

This means the Set-Cookie header seems to be stripped by Railway’s edge proxy before reaching the client.

I’ve already implemented the following fixes:

.htaccess

<IfModule mod_headers.c>
  Header always edit Set-Cookie "(?i)^((?!; SameSite).*)$" "$1; SameSite=None; Secure"
  Header always set Access-Control-Allow-Origin "https://syrios.up.railway.app"
  Header always set Access-Control-Allow-Credentials "true"
</IfModule>

Custom Middleware (CorsHeaders)

$response->headers->set('Access-Control-Allow-Origin', 'https://syrios.up.railway.app');
$response->headers->set('Access-Control-Allow-Credentials', 'true');
if ($response->headers->has('Set-Cookie')) {
    $cookie = $response->headers->get('Set-Cookie');
    if ($cookie && !str_contains($cookie, 'SameSite')) {
        $response->headers->set('Set-Cookie', $cookie . '; SameSite=None; Secure');
    }
}

Dockerfile

RUN a2enmod rewrite headers \
    && sed -i '/DocumentRoot \/var\/www\/html\/public/a<Directory /var/www/html/public>\n\tAllowOverride All\n\tRequire all granted\n</Directory>' \
        /etc/apache2/sites-available/000-default.conf

Debug output

"session_value": "2025-11-02 10:41:54",
"cookies_received": []

Everything works locally and over HTTPS.

Is it possible that Railway’s edge proxy removes or rewrites Set-Cookie headers (especially with SameSite=None; Secure) even for same-origin responses?


your issue lies with the fact that youre doing cookie rewrites, which you need to remove. so delete apache header edits, your middleware is setting your cookies.


ddscosta
HOBBYOP

a month ago

Following your suggestion, I removed all cookie rewrites and allowed Railway to handle HTTPS and proxy headers natively.

The app now uses only Laravel’s trusted proxies and middleware-level CORS handling. No Header edit Set-Cookie or manual HTTPS enforcement remains in Apache.

Despite that, the session is still created (session_id and csrf_token exist) but the browser receives no Set-Cookie header at all.

For full transparency, I’ve published a masked public diagnostics page showing all relevant configuration files currently in use:
https://syrios.up.railway.app/diag/configs

It includes:

  • .htaccess (no cookie rewriting)

  • Dockerfile (PHP 8.1 + Apache on port 8080)

  • AppServiceProvider.php (forces HTTPS only in production)

  • CorsHeaders.php (Access-Control-Allow-* headers)

  • Kernel.php, TrustProxies.php, and VerifyCsrfToken.php

  • Masked .env with session and cache configs

The diagnostic endpoints (/diag/headers, /diag/cookies, /diag/set-cookie) confirm that no cookie ever reaches the browser.

Any insights on what could still be blocking the Set-Cookie header on Railway’s proxy layer would be greatly appreciated.


ddscosta

Following your suggestion, I removed all cookie rewrites and allowed Railway to handle HTTPS and proxy headers natively.The app now uses only Laravel’s trusted proxies and middleware-level CORS handling. No Header edit Set-Cookie or manual HTTPS enforcement remains in Apache.Despite that, the session is still created (session_id and csrf_token exist) but the browser receives no Set-Cookie header at all.For full transparency, I’ve published a masked public diagnostics page showing all relevant configuration files currently in use:https://syrios.up.railway.app/diag/configsIt includes:.htaccess (no cookie rewriting)Dockerfile (PHP 8.1 + Apache on port 8080)AppServiceProvider.php (forces HTTPS only in production)CorsHeaders.php (Access-Control-Allow-* headers)Kernel.php, TrustProxies.php, and VerifyCsrfToken.phpMasked .env with session and cache configsThe diagnostic endpoints (/diag/headers, /diag/cookies, /diag/set-cookie) confirm that no cookie ever reaches the browser.Any insights on what could still be blocking the Set-Cookie header on Railway’s proxy layer would be greatly appreciated.

thanks! so a couple of things that are incorrect in your setup:

your .env is running local/localhost for app_url, you need to change those to be prod

APP_ENV=production

APP_URL=https://syrios.up.railway.app

otherwise itll continue to block the cookies. your Dockerfile is adding a .env into the image. Instead, you should be setting these vars in railway, and don't set SESSION_DOMAIN as laravel can directly use the request host. your APP_KEY needs to be set via railway's env. Railway's docs expand on this, but you're using them as runtime configs - I'm not entirely sure if the baked .env in the dockerfile can pass as real runtime values, so perhaps someone else can clarify that. I've only ever used variables by railway instead of adding an .env in my dockerfile.

remove this from docker

# ================================
# 🔑 CHAVE DO APP (.env)
# ================================
RUN if [ ! -f .env ]; then cp .env.example .env || touch .env; fi \
    && php artisan key:generate --force || true

your corsheaders.php is still doing a header rewrite, remove the custom CorsHeaders from the global stack and use config/cors.php with one origin and credentials.

// config/cors.php
'paths' => ['api/*','cookie-test','login','sanctum/csrf-cookie'],

'allowed_origins' => ['https://syrios.up.railway.app'],

'supports_credentials' => true,

remove corsheaders from the kernal, and then clear caches at boot. you can read this that helps explain laravel cors

php artisan config:clear && php artisan route:clear

your probe that contains the cookies and sessions run only in the web middleware group, the api group doesn't include those, so laravel will emit the Set-Cookies

// routes/web.php
Route::get('/cookie-test', function () {
    return response('ok')->cookie('probe','1',0,null,null,true,true,false,'None');
});

then just verify the cookies exist

curl -I https://syrios.up.railway.app/cookie-test

Attachments


ddscosta
HOBBYOP

a month ago

We ran these tests:

curl -I https://syrios.up.railway.app/cookie-test
curl -I https://syrios.up.railway.app/cookie-test-alt

Both return 200 OK but with no Set-Cookie header at all:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: railway-edge
X-Powered-By: PHP/8.1.33

However, locally (php artisan serve) the Set-Cookie header appears correctly:

Set-Cookie: probe=1; Path=/; Secure; HttpOnly; SameSite=None

We even tried a raw header:

return response('manual cookie')->header('Set-Cookie', 'manual_cookie=OK_FROM_SERVER; Path=/; Secure; SameSite=None');

but it’s still stripped by the Railway edge proxy.

This means the cookies never reach the browser — the proxy removes the header completely.

Full sanitized diagnostics available at:
https://syrios.up.railway.app/diag


Loading...