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-Cookieheader never reaches the browser.Because of that,
/loginand any session-based routes fail silently or throw 419 errors.
Environment
PHP 8.1 (official
php:8.1-apachebase 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=fileRemoving quotes around values
Setting
SESSION_SECURE_COOKIE=falseForcing
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 correctx-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-Cookieheaders (especially withSameSite=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=filehelp 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)
9 Replies
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!
a month ago
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.
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_idandcsrf_tokenexist),
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_DOMAINTrustProxiesset to*withHEADER_X_FORWARDED_ALLCorrect
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!
a month ago
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?
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_tokenexist);But the browser receives no
Set-Cookieheader — 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?
a month ago
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.
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, andVerifyCsrfToken.phpMasked
.envwith 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.
a month ago
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
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