Ça n'a pas dû échapper à une bonne partie des Linuxfrisés, le FOSDEM 2027 se tiendra samedi 30 et dimanche 31 janvier 2027, sur le campus de l'Université libre de Bruxelles (ULB). L'appel à conférences du programme principal est ouvert jusqu'au 16 novembre, et les 77 devrooms sélectionnées il y a quelques jours ont déjà commencé à leur tour à recruter des intervenants. Parmi ces dernières, et en tant qu'ambassadeur du projet Software Heritage, j'aimerai mettre en valeur la devroom Archives, Libraries, and Digital Memory qui propose notamment de discuter des infrastructures nécessaires à la préservation de notre patrimoine numérique.

Pour ceux qui l'ignorent, le FOSDEM a une particularité : les devrooms (ce que d'aucuns appellent des tracks, ou sessions en bon français) sont organisées de manière indépendante par les communautés elles-mêmes. Les organisateurs du FOSDEM font un appel à Devrooms et une fois sélectionnées, l'équipe qui a vu sa Devroom retenue a une grande autonomie et est responsable de son propre appel à participation et de la construction de son programme.
Et comme chaque année, l'accès au FOSDEM est gratuit. Pas de billet à acheter pour venir écouter des conférences, retrouver des contributeurs ou troller débattre de vos distros et/ou éditeur préféré autour d'un jus de houblon.
Le 5 octobre dernier, les organisateurs du FOSDEM ont publié leur appel à conférences pour le programme principal (Main Track).
Ces conférences s'adressent à un public assez large, au-delà des communautés techniques réunies dans les différentes devrooms. Elles peuvent porter sur des sujets transversaux, des problématiques communes aux projets libres ou des questions qui méritent une salle plus grande.
Pas besoin pour autant d'éviter les sujets techniques : les organisateurs recherchent aussi bien des présentations pointues que des réflexions plus générales intéressant les communautés du logiciel libre.
Quelques informations pratiques :
Les propositions sont à déposer sur leur plateforme de soumission du FOSDEM (basée du Pretalx).
Le 21 octobre, les organisateurs ont annoncé les devrooms retenues. Sur 128 propositions, 77 ont été sélectionnées. Ces salles thématiques, organisées directement par les communautés donc, constituent une part importante du FOSDEM. On y retrouve des sujets historiques comme notre noyau préféré, les distributions, PostgreSQL, Rust ou la virtualisation, mais aussi des sujets plus d'actualité autour de la souveraineté numérique, de l'accessibilité, de la recherche ouverte ou des communications décentralisées (aka le Fediverse).
La plupart des appels à participation sont maintenant ouverts. Attention : chaque devroom possède son propre calendrier et ses propres modalités de soumission.
Full disclosure : je suis ambassadeur de Software Heritage, le projet qui vise à collecter, préserver et rendre accessible le code source des logiciels. C'est une des raisons pour laquelle je souhaite mettre en avant cette devroom, organisée avec Software Heritage et d'autres initiatives de préservation numérique (https://Safeguar.de / https://SciOp.net et https://ecosyste.ms).
La devroom Archives, Libraries, and Digital Memory s'intéresse à une question souvent moins visible que le développement de nouveaux logiciels (ou de leur maintenance, elle aussi parfois négligée, mais c'est un autre sujet) : comment préserver durablement les ressources numériques et permettre aux générations futures d'y accéder ?
Codes sources, logiciels, publications scientifiques, collections numériques, documents historiques… Ces ressources ne resteront accessibles que si nous disposons des formats, des outils, des infrastructures et des compétences nécessaires pour les conserver. L'enjeu dépasse donc largement la simple sauvegarde de fichiers. Préserver une ressource implique de pouvoir la retrouver, vérifier son intégrité, comprendre son contexte et assurer son accessibilité dans la durée.
Et les logiciels libres ont évidemment un rôle à jouer : formats ouverts, infrastructures maîtrisées, outils réutilisables et possibilité de maintenir les logiciels sans dépendre exclusivement d'un fournisseur.
La devroom se tiendra le samedi 30 janvier 2027, de 15h à 19h CET.
La devroom s'articulera autour d'une table ronde intitulée « Managing Infrastructure for Archives and Libraries » (Gérer les infrastructures informatiques des archives et des bibliothèques en bon français). Et les sujets de discussion possibles ne manquent pas : stockage à long terme, réplication, supervision, intégrité des données, gestion des métadonnées, interopérabilité, maintien en condition opérationnelle (aka MCO) des services ou encore pérennisation des plateformes logicielles. Et avec l'explosion des contenus générés par IA, comment conserver des pétaoctets de données sans exploser les coûts ? Comment migrer des infrastructures ? Comment éviter qu'une archive ne devienne inaccessible parce que le logiciel permettant de l'exploiter a disparu ? Autant de questions auxquelles sont confrontés les responsables d'infrastructures, administrateurs système, développeurs et mainteneurs (ne les oublions pas, c'est mon combat !) de ces plateformes documentaires et, osons le mot, patrimoniales !
Comme d'habitude, l'idée est de partager des retours d'expérience concrets, des difficultés rencontrées et des solutions libres que d'autres organisations pourraient réutiliser. L'appel à participation propose trois possibilités :
Les organisateurs restent ouverts à d'autres formats, à condition de pouvoir les intégrer au programme.
Pour participer, il faut soumettre une proposition sur la plateforme Pretalx du FOSDEM, sélectionner la piste Archives, Libraries, and Digital Memory, puis indiquer dans le champ « Submission Notes » le format souhaité.
Et si les archives numériques ne sont pas votre tasse de thé, il reste la main track et 76 autres devrooms. Parmi celles-ci, oserais-je vous recommander :
Chacune a ses propres dates de clôture, mais la soumission se fait sur la même plateforme du FOSDEM et la date de publication du programme pour toutes les devroom est fixée au 7 décembre. Et dans tous les cas, la liste de diffusion du FOSDEM est votre amie. Ne procrastinez pas.
Télécharger ce contenu au format EPUBCommentaires : voir le flux Atom ouvrir dans le navigateur
Cette revue de presse sur Internet fait partie du travail de veille mené par l’April dans le cadre de son action de défense et de promotion du logiciel libre. Les positions exposées dans les articles sont celles de leurs auteurs et ne rejoignent pas forcément celles de l’April.
✍ Thierry Noisette, le samedi 31 octobre 2026.
En bref. L’open source a besoin de financements et d’entreprises qui participent, alertent l’EFF et la fondation Linux. Alternatives à la Big Tech. Une distribution Linux controversée.
✍ Elise Viniacourt, le samedi 31 octobre 2026.
La semaine dernière, des milliers de sites, dont celui des impôts ou de préfectures, ont dû être débranchés en urgence. En cause: deux failles découvertes grâce à l’IA dans PHP, un langage informatique. Retour sur un «effet boule de neige» qui a semé la panique.
✍ Louise Costa, le mercredi 28 octobre 2026.
Lors d’un test de cybersécurité mené par l’AI Security Institute britannique, Mythos 5, le modèle d’Anthropic, a tenté de faire accepter du code malveillant dans un dépôt GitHub. Malgré un premier refus, l’IA a renouvelé sa tentative.
✍ Vincent Hermann, le mardi 27 octobre 2026.
Quel effet produit l’IA sur le développement open source ? Selon un rapport de la Linux Foundation, il est conséquent, entre augmentation de la production brute, abaissement du ticket d’entrée, obligation plus intense de relecture et épuisement d’une partie des personnes impliquées.
✍ Philippe Rioux, le mardi 27 octobre 2026.
Parler de souveraineté numérique, c’est bien; la mettre en pratique, c’est mieux. Et cela est d’autant plus vrai en ce qui concerne l’État. Telle est la vision de la Cour des comptes qui vient de publier un rapport sur “Les outils bureautiques et collaboratifs au sein de l’État”. À la suite d’une campagne d’initiative citoyenne menée en septembre 2024 par l’institution de la rue Cambon, celle-ci s’est intéressée aux suites bureautiques (traitement de texte, tableur, supports de présentation) et aux logiciels collaboratifs (messageries électroniques ou instantanées, visioconférences, partages de documents, etc.) dans les administrations centrales et déconcentrées de l’État. Ce qui représente rien moins que 860 000 postes de travail informatique.
✍ Thomas Estimbre, le mardi 27 octobre 2026.
Télécharger ce contenu au format EPUBAnnoncé en grande pompe l’an dernier, le test d’une suite bureautique open source au ministère danois de la Numérisation a été arrêté sans bruit. Faute d’évaluation, personne ne saura si le ministère pouvait vraiment se passer de Microsoft.
Commentaires : voir le flux Atom ouvrir dans le navigateur
Le Capitole du Libre est un week-end dédié au Logiciel Libre et à la culture libre en Occitanie. Cette année, la treizième édition se tiendra les samedi 14 et dimanche 15 novembre 2026 à l’INP-N7 en centre‐ville de Toulouse.
Comme chaque année, Toulouse va connaitre les 14 et 15 novembre un week-end placé sous le signe du partage communautaire, autour du numérique et des solutions libres. L’entrée est gratuite, sur simple inscription en ligne.
Sous le slogan « L’événement du Logiciel Libre et de la culture libre en Occitanie », le Capitole du Libre s’adresse à toute personne : novice curieuse, bidouilleuse confirmée, passionnée, ou simple flâneuse numérique.
Le libre ne se limite pas au code : c’est d'abord une culture et des valeurs partagées, des projets humains qui se construisent ensemble.
Nous avons la chance de vivre dans une région peuplée de passionnés de technologie libre, et comme le Capitole du Libre attire aussi des visiteurs·ses de bien au delà de l'Occitanie, c'est un rendez-vous à ne pas manquer pour aller à leur rencontre.
Que l'on souhaite y passer par simple curiosité, découvrir de nouvelles choses, ou bien retrouver d'autres passionné·e·s, toutes et tous sont les bienvenues !
Et en plus c'est gratuit, alors pourquoi se priver ?

Avec le Capitole du Libre, plongez dans l’univers du libre sous toutes ses formes : un lieu de découvertes, de rencontres et de partages.
Réservez votre week-end : inscrivez-vous gratuitement et venez vivre le numérique autrement !
Commentaires : voir le flux Atom ouvrir dans le navigateur
Beaucoup de Rust par-ci… Un peu de Go par-là… Saupoudrez de LLM selon vos goûts et vous aurez une bonne photographie des sujets qui préoccupent les développeurs sur l'Internet d'aujourd'hui.
Alors, n'est-ce pas le meilleur moment pour se rafraîchir l'esprit avec des langages plus discrets ?
Je vous propose ici une présentation accélérée d'Elixir.
Ceux qui ont déjà fait de la programmation orientée objet organisent principalement leur code autour d'objets et d'instances. Cette approche a ses avantages, mais cela nécessite d'encapsuler la donnée et la gestion des changements d'état peut parfois devenir complexe.
De son côté, la programmation fonctionnelle privilégie les fonctions qui, au lieu de masquer les données, transforment simplement des entrées en sorties.
Elixir s'appuie essentiellement sur ce paradigme.
En Elixir, le signe égal n'est pas une affectation mais plutôt une assertion.
Ainsi, on n'affecte ou ne modifie la valeur que de la variable située à gauche du signe égal. À droite, la variable est remplacée par sa valeur. Exemple avec iex, la console interactive :
iex> a = 2
2
iex> 2 = a
2
iex> 1 = a
** (MatchError) no match of right hand side value: 2
Cette ligne de code échoue car elle équivaut à 1 = 2, ce qui provoque une erreur.
À noter que le caractère _ sert à ignorer une valeur, ainsi :
iex> [1, _, _] = [1, 2, 3]
[1, 2, 3]
La correspondance de motifs en Elixir est similaire à celle d'Erlang (ces deux langages utilisent la même VM).
Joe Armstrong, le créateur d'Erlang, compare ce signe égal à celui utilisé en algèbre : lorsque vous écrivez l'équation x = a + 1, vous n'attribuez pas la valeur de a + 1 à x.
Cette correspondance sert essentiellement à vérifier la forme d'une valeur, à en extraire des éléments et à traiter différemment les résultats d'une opération selon qu'elle réussit ou échoue.
Tout cela est un peu déroutant au début mais très puissant.
Dès qu'un programme dépasse quelques lignes, il devient nécessaire de le structurer.
En Elixir, les fonctions nommées doivent être écrites à l'intérieur de modules :
defmodule BestMovie do
def ever(name) do
IO.puts "Le meilleur film de tous les temps est `#{name}`."
end
end
BestMovie.ever("La cité de la peur") #=> Le meilleur film de tous les temps est `La cité de la peur`.
De son côté, la macro defp définit une fonction privée, c'est-à-dire une fonction qui ne peut être appelée qu'au sein du module qui la déclare :
defmodule MonModule do
def fonction_publique do
fonction_privée()
end
defp fonction_privée do
IO.puts "Je suis appelé depuis une fonction privée"
end
end
MonModule.fonction_privée() #=> ** (UndefinedFunctionError) function MonModule.fonction_privée/0 is undefined or private.
MonModule.fonction_publique() #=> Je suis appelé depuis une fonction privée
En Elixir, la correspondance de motifs s'applique aux arguments des fonctions : plusieurs peuvent porter le même nom mais le langage choisira la fonction dont les motifs correspondent aux arguments.
Au moyen du mot clé when, les clauses de garde permettent d'étendre cette correspondance de motifs à des vérifications plus complexes comme la distinction des types d'arguments ou un test portant sur leurs valeurs :
defmodule GuardClause do
def what_is(x) when is_number(x) and x > 0 do
IO.puts "#{x} est un nombre positif"
end
def what_is(x) when is_list(x) do
IO.puts "#{inspect(x)} est une liste"
end
end
GuardClause.what_is(99) #=> 99 est un nombre positif
GuardClause.what_is([1,2,3]) #=> [1,2,3] est une liste
Toutes les expressions ne sont pas autorisées dans les clauses de garde, mais seulement quelques-unes.
Il s'agit d'un choix délibéré du langage pour garantir une exécution efficace.
En Elixir, une liste peut être vide ou se composer d'une tête et d'une queue. La tête (head) contient une valeur et la queue (tail) est elle-même une liste :
iex> [ head | tail ] = [ 1, 2, 3 ]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
Ainsi, une liste à un seul élément (que nous écririons habituellement sous la forme [4]) peut s'écrire comme la valeur 4 jointe à une liste vide, soit [ 4 | [ ] ].
Cette définition permet d'aborder certains problèmes de manière récursifs et donc sans s'appuyer sur une variable de boucle et/ou les traditionnels if et else :
defmodule MyList do
def flip([]), do: []
def flip([ head | tail ]) do
flip(tail) ++ [head] # `++` permet de concaténer des listes
end
end
MyList.flip([1, 2, 3, 4, 5]) #=> [5, 4, 3, 2, 1]
# Explication pas à pas :
# flip([1, 2, 3, 4, 5])
# ↳ flip([2, 3, 4, 5]) ++ [1]
# ↳ flip([3, 4, 5]) ++ [2] ++ [1]
# ↳ flip([4, 5]) ++ [3] ++ [2] ++ [1]
# ↳ flip([5]) ++ [4] ++ [3] ++ [2] ++ [1]
# ↳ flip([]) ++ [5] ++ [4] ++ [3] ++ [2] ++ [1]
# ↳ [] ++ [5] ++ [4] ++ [3] ++ [2] ++ [1]
# ↳ [5, 4, 3, 2, 1]
Note : l'usage de ++ est moins efficace qu'une version utilisant une variable pour accumuler le résultat mais cette approche reste plus didactique pour découvrir la récursion.
Nous avons tous déjà croisé du code séquentiel où chaque étape dépend du résultat de la précédente :
cart = ShoppingCart.for_user(user_id)
items = Inventory.check_availability(cart)
total = Pricing.calculate_total(items, tax: 1.2)
L'ordre des opérations est clair, mais au final les variables intermédiaires sont là pour éviter des appels imbriqués :
Pricing.calculate_total(
Inventory.check_availability(
ShoppingCart.for_user(user_id)
),
tax: 1.2
)
Elixir propose d'écrire ce type de code d'une façon fluide et sans variable intermédiaire :
user_id
|> ShoppingCart.for_user()
|> Inventory.check_availability()
|> Pricing.calculate_total(tax: 1.2)
L'opérateur |> prend le résultat de l'expression située précédemment et l'insère en tant que premier paramètre de l'appel de la fonction suivante.
Maintenant que vous avez les bases, je vous propose un exercice qui m'avait bien plu lorsque j'ai découvert le langage au travers le livre de Dave Thomas : trouver un nombre compris dans un intervalle donné (ex : 1..100 dans une expression ou 1..100//1 pour effectuer une correspondance de motifs, //1 correspondant au pas).
Il existe plusieurs façon de résoudre le problème mais voici ma solution :
defmodule Devine do
def en_tatonnant(cible, min..max//1) when is_integer(cible) and is_integer(min) and is_integer(max) and cible > min and cible < max do
estimation = div(min + max, 2)
IO.puts "Est-ce #{estimation} ?"
guess(cible, min..max, estimation)
end
def en_tatonnant(cible, min..max//1) when not is_integer(cible) or not is_integer(min) or not is_integer(max) or cible < min or cible > max do
IO.puts "Très drôle…"
end
defp guess(cible, min.._//1, estimation) when estimation > cible do
IO.puts "Non, c'est plus petit… Maintenant on va rechercher entre #{min} et #{estimation}"
en_tatonnant(cible, min..estimation)
end
defp guess(cible, _..max//1, estimation) when estimation < cible do
IO.puts "Non, c'est plus grand… Maintenant on va rechercher entre #{estimation} et #{max}"
en_tatonnant(cible, estimation..max)
end
defp guess(cible, _, estimation) when estimation == cible do
IO.puts "Mais oui, c'est bien #{estimation} 🤩"
end
end
Devine.en_tatonnant(273, 1..1000)
#=> Est-ce 500 ?
#=> Non, c'est plus petit… Maintenant on va rechercher entre 1 et 500
#=> Est-ce 250 ?
#=> Non, c'est plus grand… Maintenant on va rechercher entre 250 et 500
#=> Est-ce 375 ?
#=> Non, c'est plus petit… Maintenant on va rechercher entre 250 et 375
#=> Est-ce 312 ?
#=> Non, c'est plus petit… Maintenant on va rechercher entre 250 et 312
#=> Est-ce 281 ?
#=> Non, c'est plus petit… Maintenant on va rechercher entre 250 et 281
#=> Est-ce 265 ?
#=> Non, c'est plus grand… Maintenant on va rechercher entre 265 et 281
#=> Est-ce 273 ?
#=> Mais oui, c'est bien 273 🤩
Vous vous doutez bien que je n'ai fait qu'effleurer le sujet mais j'ai trouvé le langage Elixir tellement singulier que je n'ai pas résisté à l'envie de vous le présenter.
Je continue ma découverte de ce langage, à mon rythme ; en ce moment, j'aborde la programmation concurrente.
À n'en pas douter, j'enchaînerai sur le framework Phoenix !
Commentaires : voir le flux Atom ouvrir dans le navigateur
Joyeux anniversaire Emacs ! Comme Slashdot l’a opportunément relevé, ce bel éditeur a maintenant un demi-siècle, ce qui semble complètement dingue.
J’avais déjà clamé mon admiration ici il y a quelques années, alors c’est l’occasion de revenir sur ce beau morceau de logiciel, qui ne fait pas son âge (comme moi, donc), et sur ce qu’on peut encore faire avec aujourd’hui.
Il a eu une vie un poil mouvementée, né à partir de TECO, réécrit complètement par Richard Stallman pour devenir GNU Emacs, forké vers XEmacs… On pourra bien entendu rappeler les innombrables flame wars avec Vim, les aphorismes usuels (Eight megs and constantly swapping, Emacs est un système d’exploitation auquel il manque un bon éditeur de texte…). C’était le bon temps.
Emacs a perdu de sa superbe aux grands moments des IDE tout intégrés, mais finalement c’est de là qu’est venue la libération, et ironiquement on peut remercier Microsoft. Avec l’apparition du Language Server Protocol, qui a découplé le langage de l’éditeur et permis le lint, l’auto-complétion, les erreurs en ligne et autres, Emacs est redevenu tout à fait productif, et j’aurais envie de dire, tout du moins dans mon cas, un meilleur éditeur C++ que les VScode et CLion, proposant des fonctionnalités similaires, voire supérieures (Mode tramp ssh + docker par exemple), pour une bien plus grande légèreté et stabilité. Et à chaque fois que je dois écrire ou lire quelque chose, que ce soit du texte, ma TODO list, du C++, du shell, du Latex, du Yaml, ou, Cthulhu me protège, du Python, eh bien Emacs reste l’endroit le plus pratique pour tout ça, avec dans le pire des cas un petit paquet melpa à installer rapidos pour être complètement dans le bain.
Emacs est surprenamment encore pertinent en ces jours de vibe coding: les LLMs sont plutôt doués en LISP, et faire écrire son propre mode devient trivial. Il y a tout un tas de modes pour s’intégrer avec un agent, dont agent-shell est l’un des plus aboutis. J’ai ainsi codé un petit mode très spécialisé qui m’affiche ma liste de projets, et me permet de créer un nouveau workspace git en m’ouvrant une fenêtre magit, une fenêtre agent-shell, et une fenêtre dired, le tout à travers un tramp - Me donnant un espace de travail complet et intégré pour travailler sur une machine de dev à distance comme si j’y étais.
Prochaine étape, le centenaire !
Ce texte a bien entendu été tapé dans Emacs. On ne se refait pas.
Télécharger ce contenu au format EPUBCommentaires : voir le flux Atom ouvrir dans le navigateur

My homelab runs on 5 machines with around 30 Docker containers. For a long time, the way I reached them was a bookmarks folder full of entries like http://100.101.12.4:8096.
Tailscale took care of getting me into my network from anywhere, but once I was in, I was back to remembering which box ran what on which port.
The usual fixes each have a catch. A reverse proxy with your own domain works, but it's one more thing to maintain, and every new app means touching two config files instead of one. Giving each container its own Tailscale sidecar gets you nice names, but it also turns the Machines page into a list of containers, each with its own auth key and state volume.
When Tailscale released Services, it looked like the thing I had actually wanted: names for apps, not for machines. I've been running my containers that way since, and this is a write-up of how it works, how to set it up by hand, and the two things worth knowing before you start.
A Service is a name plus a virtual IP on your tailnet, for example jellyfin.your-tailnet.ts.net. It doesn't belong to a device. Instead, one or more of your machines advertise it, and Tailscale routes clients to them.
So your Docker host stays a single machine in the tailnet, and the apps on it become Services. Access rules can point at a Service directly, so you can let someone reach Jellyfin without giving them the whole host.
Here is what a request looks like once it's set up:

Two details in that picture matter later: tailscaled on the host terminates HTTPS and talks plain HTTP to your app, and it adds an X-Forwarded-For header. To your app, Tailscale behaves like a reverse proxy.
Before automating anything, it's worth doing it manually once for a single container. You need three things.
1. A tagged host. Services are advertised by tagged machines, so give your Docker host a tag:
sudo tailscale up --advertise-tags=tag:server --reset
2. A policy that allows it. In the admin console under Access controls, the tags must exist, and an auto-approver saves you from clicking "Approve" for every Service:
{
"tagOwners": {
"tag:server": ["autogroup:admin"],
"tag:container": ["tag:server"]
},
"autoApprovers": {
"services": {
"tag:container": ["tag:server"]
}
}
}
3. The Service itself. On the Services page of the admin console, choose Advertise, then Define a Service, name it jellyfin and give it the tag:container tag. Then, on the host, point it at the app:
tailscale serve --service=svc:jellyfin --https=443 127.0.0.1:8096
This assumes Jellyfin publishes port 8096 on the host. If HTTPS certificates are enabled for your tailnet (DNS page in the admin console), https://jellyfin.your-tailnet.ts.net now works from every device that runs Tailscale.
For one app, that's fine. For 30, it gets old quickly: one definition in the console and one serve command per app, plus published ports again. And nothing updates by itself when you add, remove or move a container.
The part that bothered me most was that the configuration lived in two places. The app was defined in a Compose file, and how to reach it was defined somewhere in the admin console and in tailscaled's state. Remove a container and its Service just stays there.
Traefik solved the same problem for reverse proxies years ago with Docker labels, and I didn't find anything like that for Tailscale Services. So I wrote a small Go program that does it, DockTail. It runs as one container per host, watches Docker events, and turns labels like these into the steps above:
services:
docktail:
image: ghcr.io/marvinvr/docktail:latest
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/run/tailscale:/var/run/tailscale
environment:
- TAILSCALE_OAUTH_CLIENT_ID=${TAILSCALE_OAUTH_CLIENT_ID}
- TAILSCALE_OAUTH_CLIENT_SECRET=${TAILSCALE_OAUTH_CLIENT_SECRET}
jellyfin:
image: jellyfin/jellyfin:latest
restart: unless-stopped
volumes:
- ./config:/config
- ./cache:/cache
- /path/to/media:/media:ro
labels:
- "docktail.service.enable=true"
- "docktail.service.name=jellyfin"
- "docktail.service.port=8096"
- "docktail.service.service-port=443"
With an OAuth client (Services: Write, Devices Core: Write, scoped to tag:server) it also creates the Service definition, so the manual console step goes away. Note that Jellyfin has no ports: section: the traffic goes straight to the container's IP on its Docker network.
That's also why this needs something that watches Docker. If you skip published ports and point serve at a container IP by hand, it breaks the next time the container is recreated:

DockTail is open source (AGPL-3.0). You don't need it to use Services, though, and everything in the next section applies either way.
If a Service doesn't show up, it's almost always the tag. The host needs to be tagged (check tailscale status), and if you haven't set up an auto-approver, the Service waits for you on the Services page.
Apps that check proxy headers may complain at first, because Tailscale adds an X-Forwarded-For header. Home Assistant answers with "400: Bad Request" until you trust the proxy in configuration.yaml:
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
On a Docker bridge network, use the address Home Assistant names in its log instead of 127.0.0.1. Jellyfin has the same setting under Dashboard → Networking → Known proxies, but it works fine without it.
For me, yes. What I like most is that the network config now sits right next to the app in the same Compose file. Adding an app means adding labels, removing it takes its Service with it, and my Machines page shows machines again.
I'd still use a reverse proxy for anything public with my own domain. Tailscale Funnel is great for a webhook or sharing one thing with a friend, but it's not a replacement for that. And if you run a handful of containers that rarely change, the manual tailscale serve route above is perfectly fine and needs no extra tool.
If you want to try the label approach, the code and docs (including complete guides for Jellyfin and Home Assistant) are at github.com/marvinvr/docktail and docktail.org/docs.
And if you've solved this differently, I'd honestly like to hear how. Leave a comment, I'll read all of them.
✍️The article is contributed by Marvin von Rappard, creator of open source project Docktail.

Building a Fedora release means tracking an enormous amount of formal change proposals planned for each release cycle on a public Change Set page, where every entry carries an owner and a status.
These proposals undergo community review and require approval from the Fedora Engineering Steering Committee (FESCo), either in batches or individually, depending on their scope.
But approval only means a change is accepted for the planned release, not that it is guaranteed to ship. The beta for Fedora 45 came out last month, and several proposals that were meant for the stable release were pushed to Fedora 46.
What we have now is a release that was initially set for October 20, but was pushed back to October 27, and then again, to today, November 3, because there were some late-stage teething issues with the release.
If you have ever hit a kernel panic on Fedora, you might have spotted a QR code on the screen. The DRM Panic component has shown it by default since Fedora 42, but scanning it only got you a raw trace that not many people can read.
Fedora 45 changes that with a web frontend for DRM Panic. Scanning the QR code with your phone now takes you to a Fedora-hosted page that walks you through what went wrong.
From there, you can start a Bugzilla report with your system details and the trace already filled in.

Similarly, if you have pressed Ctrl+Alt+F3 and landed on a full-screen text login, you have seen the Linux virtual console. That screen is drawn by the kernel's fbcon, and Fedora 45 swaps it for a userspace program called kmscon.
The switch brings back scrolling, adds basic mouse support, and a crash no longer results in a kernel panic. You also get resizable fonts, better Unicode support, and the ability to use the same keyboard layout as your desktop.
Don't worry about things breaking. If kmscon fails to launch, Fedora falls back to the old getty and fbcon setup automatically, and you can switch back yourself if you prefer.

Fedora 45 ships with Linux 7.2, and a few of its changes are easy to appreciate without digging through the changelog. Radeon users get initial HDMI 2.1 support years after the HDMI Forum blocked it from the open source driver, and the new ISP4 driver completes webcam support on the HP ZBook Ultra G1a and other upcoming Ryzen laptops.
Existing laptop users get more hardware support too. The ASUS ROG Strix G16, Zephyrus G14, and TUF Gaming F16 are now supported, Lenovo laptops can limit their battery charge, and Microsoft's 12-inch Surface Pro gets a platform driver.
Though, I must say, it's a bit weird to see Fedora skip out on Linux 7.3, given that Ubuntu 26.10 got it in before the kernel was even officially released. Perhaps the release delay had something to do with the switch, but that's just speculation on my part.


Fedora 45 Workstation and KDE Plasma Desktop.
Fedora Workstation 45 comes with GNOME 51, and its handful of practical upgrades include offline map downloads in the Maps app, a new fingerprint manager in the Users panel of Settings, and monitor brightness that is saved and restored across sessions.
The Files app picks up rename and trash options in the file previewer, and Mutter drops support for legacy NVIDIA drivers.
Fedora KDE Plasma Desktop 45 comes with Plasma 6.7, and the feature to talk about is per-screen virtual desktops. This is a useful thing for multi-monitor setups where your laptop display and external monitor no longer have to be limited to the same set of virtual displays.
Additionally, the classic Oxygen and Air themes from the KDE 4 days are back as full Global Themes, and if you have separate day and night themes set up, a new toggle in the Brightness & Color quick settings lets you switch between them.

Podman is a container tool that lets you run and manage containers and pods using Docker-style commands without needing to run a daemon in the background.
With this Fedora release, Podman moves up to the 6.1.x series, and most of the significant changes come from the major 6.0 release it builds on.
That release retired slirp4netns, CNI, cgroups v1, and iptables in favor of Pasta, Netavark, cgroups v2, and nftables, and it migrates an old BoltDB database to SQLite automatically.
Beyond the removals, network isolation is now on by default, podman volume prune only clears anonymous volumes that aren't in use, and Quadlet files live in their own subdirectories.
Podman 6.1 then adds smaller conveniences like podman volume rename, podman machine restart, and retry options for podman manifest push.
Here are a few additional improvements that didn't make it into the sections earlier:
You can get the stable release from the official website. Pick the image that suits your use case, and expect there to be some minor breakage that could affect your machine.
Fedora 45

Personally, I have never owned an Apple device, mostly due to its pricey nature and how the brand loves to lock people in their walled garden. But that's just me ranting there for a bit.
There are many who do like what Apple has to offer and are willing to see what additional value they can get out of that hardware by breaking free from macOS.
This list covers six such options that ought to awaken the tinkerer inside you. 🧑🔧
📋Every install route here boots directly on Apple Silicon hardware instead of a virtual machine, sitting alongside the macOS installation.
Fedora Asahi Remix is Fedora Linux with the Apple Silicon work from the Asahi Linux project built in. KDE Plasma on Wayland is the default desktop, and GNOME, Minimal, and Server images are there if you want something different.
On M1 and M2 Macs, almost everything works, from the webcam and microphones to Wi-Fi and Bluetooth. The graphics drivers also pass the OpenGL 4.6 and Vulkan 1.4 conformance tests.
M3 owners can try it too, but support is quite new. Sleep does not work, HDMI on MacBooks is unavailable, and 3D graphics don't run well yet. The M3 Ultra Mac Studio is not supported at all.
Installation begins in macOS. Run the following command in the Terminal app and follow the prompts to continue with the installation of Fedora Asahi Remix on your Mac:
curl -L https://alx.sh/ | shM3 owners are recommended to run dnf upgrade --refresh after the install finishes.
If Ubuntu is already familiar to you, then this community project has ported it to M1 and M2 Macs by carrying over the Apple Silicon support from Asahi Linux.
The installer comes in four flavors, covering 26.04 and 26.10 for Ubuntu Desktop and Server. The goal is to provide the same feature set as Fedora Asahi Remix, while new hardware support only arrives after the Fedora base ships it.
As a result, you can expect system updates to be behind by a few weeks.
Like earlier, you get the installer as a script and run it in Terminal. It shrinks the existing macOS partition and lets you pick a release and build, leaving your macOS installation intact:
curl -sL https://ubuntuasahi.org/install | shUbuntu Asahi
Debian doesn't officially run on Apple Silicon yet, but the Bananas Team is working to change that. It packages the missing pieces and ships them from an unofficial archive of its own.
Official support is stuck on the kernel. The Asahi Linux patches it needs aren't upstream yet. Most other pieces, like the m1n1 bootloader and the audio stack, have been in Debian since Trixie.
The team's installer offers GNOME, KDE, or a console-only setup:
curl -L https://bananas.debian.net/install | shThe install page contains the necessary steps.
Debian Bananas
Write the whole system down in a Nix config file, rebuild, and the Mac matches it. That's the NixOS way, and this community port brings it to Apple Silicon. The maintainers keep versions close to Fedora Asahi Remix and turn away changes that stray far from it.
Hardware support follows whatever Asahi Linux supports, and setting it up is quite a hands-on affair. You’ll prep a UEFI environment from macOS with the Asahi Linux installer, boot a NixOS installer from a USB drive, and finish the job from the command line.
NixOS on Apple Silicon
Omarchy M is a dedicated team rather than a separate distro that has been put together to handle Omarchy support on Macs. It's bringing the Arch-based, Hyprland desktop to Apple Silicon while also giving some attention to older Macs.
The first release targets M1 and M2 Macs, along with their Pro and Max variants. On the roadmap are a native installer, full GPU support, USB-C external monitors, Touch ID, MLX, and disk encryption.
Support enablement work for newer Macs will take place alongside this too!
The native installer is a community-built app by team member Marcelo Alcantara, and it sets up Omarchy on a Mac machine without needing a USB stick.
Omarchy M
Gravity Linux is built to go away. It's a Fedora remix with KDE Plasma on Wayland, and the plan is to retire it once the drivers land upstream and any mainstream distro can run on supported Mac devices.
It started as a fork of Asahi Linux over a difference in policy on LLM use. Everything it offers comes from clean-room reverse engineering.
The first alpha release runs on the M4 Mac mini and is meant for developers. The display controller and GPU work, but suspend, USB-C display output, Thunderbolt, and USB4 don't; shutdown and reboot behavior is flaky.
You can install it on macOS with the command below, but do plan a full reinstall when the beta lands, as there's no established upgrade path.
curl -fsSL https://install.gravitylinux.org | shGravity LinuxI will be adding more to this list as I come across reliable new projects. Meanwhile, if you know some, please mention it in the comments.

Adobe charges $60 a month. Microsoft 365 keeps raising its price. Salesforce will take $150 per user without blinking. These are not tools you own. They are subscriptions that expire the moment you stop paying, often taking your files and workflows with them.
The Puter team thinks that is worth fixing. Remember Puter? The folks behind the PuterOS that gives you a workable operating system in a web browser.
Their new project, called everything, is a single GitHub repository with one specific goal and that is to rebuild the world's software from scratch, free and open source.
This is what they are aiming for. Over 50 web-based applications spanning nine categories, including a photo studio, full office suite, CRM, CAD tools, video editor, and circuit design app. Every one of them is open source under the MIT-license. And they can be self-hosted, too.
Basically, it targets all the major Software as a Service (SaaS) companies.
The applications are all listed on the official GitHub page, they're all in a table, and very helpfully, the cell next to the application name states what popular software it is an alternative to. For example, "Notes" is an alternative to Microsoft OneNote, Evernote, Apple Notes. It is all put in well organized categories.

The apps are all hosted online, and can be opened by pressing the "Try it" link. They're completely usable, however, and in case you have a slow system that can't handle some heavy duty tasks such as video editing, this is genuinely a better option. Nevertheless, you have to remember that you'll be uploading your data to this service, and if that is a privacy concern then you may have to reconsider.
📋Several features are only available to you if you make a Puter account and sign in. These include several AI features, such as auto-generation of captions in the video editor, but some applications require a sign-in straight away to use them in the first place, such as the Notes app.On the other hand, you can also host the applications locally, the instructions for which are given on the GitHub page, again.
For example, here I am running the Video Studio locally:
cd everything/src/video-studio/
npm install
npm run devThis returns a link you can open up in your browser and use the application.


HeyPuter launched Puter in 2024 as a self-hostable internet computer: a full desktop environment running in a browser, with cloud storage, apps, and developer tools baked in. It was well received by the community.
With Everything, rather than building one great alternative to one piece of software, the project takes on the entire proprietary stack at once.
The logic is that the vendor lock-in does not come from a single app. It comes from an ecosystem. Adobe keeps you because Lightroom talks to Premiere talks to Acrobat. Microsoft keeps you because Word talks to Excel talks to Teams. Breaking one link does not free you. Everything is trying to break all of them.
The MIT license matters here. Unlike the GPL, MIT places almost no restrictions on use. You can take these apps, modify them, and run them anywhere without obligation. For businesses and developers worried about compliance, that removes the last excuse to keep paying for proprietary software.
I've tested some of the apps to check the quality of the production, and pretty much to see if the job gets done.
🚧A major observation I made was that progress on projects can only be saved if you've logged in with a Puter account. If not, you have to get it all done in one go. Exporting is fine, either way.The PDF editor has great options, adding texts or links, images, stitching PDFs together and so on.
You can even draw diagrams to add to the PDF in the app itself. You can also add sticky notes, highlight text etc. These are quite basic features on a PDF editing menu, but they work seamlessly here, which is great to see.

Since the software is in early stages, there are some bugs. Like when I tried editing the preexisting text in a PDF file, it was not entirely accurate. The text doesn't always get detected in proper blocks, and the formatting gets all over the place as a result of that.

I tried some of the features, such as the AI caption generation, and the film grain effect, with transitions in between clips and it worked quite well.
It also generated captions and allowed me to edit them if a word was incorrect.

The export menu showed options to separately export the audio in a WAV file and captions in an SRT file, which is great.
I had an issue with one of my video clips where it said my browser couldn't decode the video file, but then there was no further information on how to fix it, which essentially rendered the video file uneditable.
Being used to Ableton myself, the interface was different here for me. Don't get me wrong, the app itself is pretty intuitive to navigate through, the major actions are all laid out in a great way.
It has all the effects you might need, such as compression, reverb, delay, parametric EQ, stereo and so on. They work quite well, and the options for each are ample.
Nothing too technical, but just as much as you need.

Even the export showed options to export the stems as well as MIDI files separately, which is a great feature to have. Out of all the three that I tested, the music studio worked most to my satisfaction.
There is a new trend in the developer world these days to reverse engineer everything with AI. Puter's new project is part of the same trend.
The apps on The Everything Projects have their ups and downs but on the larger scale, they work incredibly well for the most part, giving features that almost match the professional level. At least for beginning professionals everywhere, who cannot afford expensive software, these apps are a great way to get things done.
It requires an account to access the AI features and to save the progress on projects unless you have an account, where you will probably need a Puter subscription because 25MB is too small a storage to actually get anything done.
That actually is understandable to avoid the service abuse but the 25 MB could have been 250 MB at least. In any case, self-hosting option is always there.
What do you think about this wave of reverse engineering apps and open sourcing them? Let us know in the comments. Cheers!

govdigital eG has awarded IONOS a four-year framework contract under KoDaS, the abbreviation for a collaboration and file storage system. The service delivered under it is built on Nextcloud and sold as Nextcloud Workspace.
It is meant for schools and school authorities in the German states of Berlin, Hamburg, Bremen, North Rhine-Westphalia, Rhineland-Palatinate, and Hesse. Other German states can join later, and schools are not mandated to implement it.

IONOS is the main contractor. It is tasked with delivering and operating the service, running the cloud infrastructure located in German data centers, and building it all on Nextcloud's open source software.
The tender notice for KoDaS sets a maximum value of 67.5 million euros and a maximum term of 48 months from the award. Nextcloud's announcement names the six states and their schools as the main parties who can order, leaving room for other states to be added later.
The announcement does not say what the contract will actually be worth. 📝
The notice calls for procuring software available under an OSI-approved open source license, citing digital sovereignty, lasting availability, and the ability to switch providers.
Among its asks for bidders are ISO 27001 certification, at least 10 million euros in turnover, liability insurance of at least 5 million euros, and a reference project with at least 10,000 active users and fully separated tenants.
For the features, the notice calls for central file hosting and sharing, a browser-based office suite for working on documents together, calendar and contact management, and an integrated email client.
Pricing depends on how many people actively use the service, and it is split into five tiers that start at the up to 50,000 users mark, ending above 500,000. No school authority has to commit to a set volume up front, so each can begin with its current users and grow from there.
Nextcloud's main argument is that public institutions should have alternatives to proprietary platforms so they keep control of their data. The company also believes students who start out using open source tools are less likely to reach for big-vendor products afterward.
Other German institutions are also reworking their software. Last year, we heard that almost 80% of Schleswig-Holstein's state government workplaces had switched away from Microsoft.
Mecklenburg-Vorpommern is replacing SharePoint with a self-hosted Nextcloud that around 5,000 employees use today, and the state plans to bring that to 50,000 across the public sector.
Then there's the federal Deutschland-Stack, published by the Federal Ministry for Digital Transformation and Government Modernization, which covers all levels of public administration and permits use of only ODF and PDF/UA for documents.
I anticipate more such moves across Europe as governments realize that keeping sensitive data with providers that fall under foreign law can expose it to access they have no say over, irrespective of where the servers are located.
The ongoing US midterms could also shift the conversation depending on who comes out ahead.
Suggested Read 📖: France's absurd per-gigabyte tax could cost VLC over €1 million a year.
Hi internals,
I'd like to start the discussion on a new RFC:
https://wiki.php.net/rfc/grapheme_str_pad
It proposes grapheme_str_pad(), the grapheme cluster counterpart of str_pad() and mb_str_pad(), following the Future Scope of the mb_str_pad
RFC. The length is counted in grapheme clusters, so text in NFD, kana with
a combining dakuten, Indic scripts and emoji sequences are padded to the
same visible length as their single code point equivalents, and the padding
string is only cut on grapheme cluster boundaries.
Semantics and errors mirror mb_str_pad(). For ASCII input the result is
identical to str_pad().
Implementation: https://github.com/php/php-src/pull/25179
Thanks,
Chris Abner Herrera Navarro
Hi
I changed the RFC to reflect this. openssl_get_channel_binding can no
longer return null, but it can throw a (newly introduced)
UnsupportedChannelBindingException.
Thank you. I've given the RFC another read and have some more comments:
The naming of the $channel_binding_type parameter. It seems there
is no current policy and using underscores is consistent with
ext/openssl overall, but from what I see, new parameters are typically
using camelCase. No strong opinion either way from my side, but
potentially worth a discussion.
“Introducing a new Error hierarchy for ext/openssl is a larger API
decision that would affect more than this function, and none of the
existing ext/openssl APIs currently use an Error subclass”
Not really. The “look and feel” of Openssl\OpensslError is already
required by policy, so there's no API design to be resolved here. I
don't disagree with the choice of ValueError (and even suggested it as
one of two alternatives), but that argument in the RFC stood out and
should probably be rephrased or dropped.
Best regards
Tim Düsterhus
Thank you for the thorough review.
An operation that is not applicable sounds like an Exception to me.
I can see the appeal of throwing a specific exception (e.g. UnsupportedChannelBinding extends OpensslExtension). Then if the function returns something the caller knows it is a valid channel binding value.
I changed the RFC to reflect this. openssl_get_channel_binding can no longer return null, but it can throw a (newly introduced) UnsupportedChannelBindingException.
Regards,
Sjoerd
Sorry for the later response and not doing the follow-ups on the previous email, I got incredibly busy with PHP stuff at work... you can guess why.
Content sniffing can't settle this. A bytea or varbinary value can be valid text, and text can contain a NUL, so the driver has to be told. It also doesn't help native prepares: pdo_pgsql sends text-format parameters as C strings, so they truncate at the first NUL regardless of quoting. That's the strongest argument for the RFC imho.
Agreed a binary param type is unavoidable for quoters.
The driver break decides between using a type versus a flag. A new type 6 is a fatal error in pdo_sqlsrv and IM001 in pdo_ibm until each driver ships an update. A flag that core masks before quoting allows fetch to fall back to STR/LOB in any driver that ignores it. I'd go with the flag, and reject combinations with INT/BOOL/NULL with a ValueError.
We have shipped breaking changes in PDO before (i.e. zend_stringification), so expecting these drivers to update for newer releases isn't unreasonable. But easing compatibility is another small point in favour of the flag.
pdo_sqlite already marks blobs in getColumnMeta()'s "flags" array, which is a good precedent for leaving pdo_type alone.
Sounds like we can just make it a standard part of the array's expected values then.
Hi
We have now made the
SystemClocka singleton with a
SystemClock::get()factory / getter. The constructor is private now.
Something I forgot doing then, but I did now: SystemClock is now marked
as @not-serializable, because well, it is not supposed to be
serialized as a singleton.
Best regards
Tim Dsüterhus
Symfony 8.2 connects firewalls and routes more closely: routes can choose their firewall, you can load the routes of all firewalls with a single import, and redirecting anonymous users to a login page no longer requires a custom class.
Contributed by
tilaven
in
#63112
Symfony selects the firewall of a request by checking the pattern or the
request_matcher of each firewall in the security.firewalls configuration.
This keeps the routes and their authentication apart, which is inconvenient in
modular applications where each module defines its own routes. In Symfony 8.2,
routes can define the firewall that handles them using the new firewall
option:
// src/Controller/OrderController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class OrderController
{
#[Route('/api/orders', name: 'api_orders', firewall: 'api_jwt')]
public function orders(): Response
{
// ...
}
}
# config/routes.yaml
api_orders:
path: /api/orders
controller: App\Controller\OrderController::orders
firewall: api_jwt
// config/routes.php
use App\Controller\OrderController;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
return function (RoutingConfigurator $routes): void {
$routes->add('api_orders', '/api/orders')
->controller([OrderController::class, 'orders'])
->firewall('api_jwt');
};
The given firewall is used instead of the ones matching the request, and routes that don't define this option work as before. If the firewall doesn't exist, Symfony throws an exception instead of falling back to another firewall.
The firewall option only changes how users are authenticated: your
access_control rules still apply as usual, regardless of the firewall that
handled the request. To check the firewall of a route, run the debug:router
command, which displays it as the _firewall route default.
Some firewall features need routes to work, like the logout path or the OpenID
Connect callback. Symfony generates these routes from your security
configuration, but your application must import the service that loads them.
Until now, this meant importing security.route_loader.logout, and features
like OpenID Connect login added in Symfony 8.2 also need their own routes.
Symfony 8.2 adds a security.route_loader service that loads the routes of
all firewalls, so your application only needs one import. The
security.route_loader.logout service is deprecated and will be removed in
Symfony 9.0, so update your configuration as follows:
# config/routes/security.yaml
-_security_logout:
- resource: security.route_loader.logout
+_security:
+ resource: security.route_loader
type: service
Some authenticators, like json_login and many custom ones, don't redirect
anonymous users to a login page. Until now, doing that required
creating a class that implements AuthenticationEntryPointInterface just to
return a redirect. In Symfony 8.2, use the new entry_point_path firewall
option instead:
# config/packages/security.yaml
security:
firewalls:
main:
json_login:
check_path: api_login
entry_point_path: app_login
// config/packages/security.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
return App::config([
'security' => [
'firewalls' => [
'main' => [
'json_login' => ['check_path' => 'api_login'],
'entry_point_path' => 'app_login',
],
],
],
]);
Like the login_path option, its value can be a path, an absolute URL or a
route name. In stateful firewalls, Symfony also saves the requested URL so users
can return to it after logging in. This option can't be combined with the
entry_point option in the same firewall.
Join devs from all over at SymfonyCon Warsaw 2026 on November 26-27 for two days of talks, workshops, and shared experiences.
Huge welcome to Volker Dusch, Head of Engineering, Tideways, as he joins our lineup with Fixing PHP2Shell. Excited to see this live on stage!
"This talk reflects on the PHP2Shell vulnerability, telling the full story of what happened and discussing its impact and why it gained so much attention.
We will cover the whole process, from what led to its discovery to testing and validation to remediation and how the PHP team coordinated and rolled out the fix.
Discussion will include how agentic security research combined with human expertise led researchers to the exploit and how LLMs are changing the landscape of security going forward.
We will reflect on lessons learned, share advice for other projects and the wider PHP ecosystem, and provide practical suggestions for organizations and projects."
Click here to see more talks. The full schedule will be unveiled step-by-step over the coming weeks. Stay tuned!
The official conference hotel offers special preferential rates and flexible conditions for our attendees. Make sure to use our dedicated link to book your room and stay right where the action happens!
Because SymfonyCon isn't just about code, we are happy to confirm that our traditional Community Party will take place on the evening of Thursday, November 26. Get ready for a great night of networking, fun, and connecting with peers!
Ready to contribute? The Hackday on Saturday, November 28 (free and open to all!) will take place at "The Brain Embassy - Czackiego" thanks to the support of Baksla.sh. Bring your laptop and your good mood!
Tickets are available here: Secure your ticket today!
💡Follow the "conference" blog posts to not miss anything!
Want the latest Symfony updates? Follow us and tune in from wherever you are 🌎
Sponsor the Symfony project.Heading to Poland this fall? SymfonyCon Warsaw 2026 (Nov 26-27) will feature 3 parallel tracks and plenty of opportunities to meet other community members.
We're happy to confirm Vincent Robert, Technical Enablement Lead, Upsun, for his presentation Zero to production on SymfonyCloud, live. We can't wait to bring his experience to our community!
"You have an idea for a Symfony app. How long until it is in production, safe and observable?
Live on stage, we create a small app and deploy it to SymfonyCloud, the official cloud for Symfony, without writing a single build or deploy script.
Then you use it from your phone.
Next, we add a slow feature on a copy of production, your votes included, find the bottleneck with Blackfire, move the work to a background worker, and ship it safely.
No prior Symfony experience needed."
A special thanks to Upsun for sponsoring this 3rd track on November 27th.
Click here to see more talks. The full schedule will be unveiled step-by-step over the coming weeks. Stay tuned!
The official conference hotel offers special preferential rates and flexible conditions for our attendees. Make sure to use our dedicated link to book your room and stay right where the action happens!
Because SymfonyCon isn't just about code, we are happy to confirm that our traditional Community Party will take place on the evening of Thursday, November 26. Get ready for a great night of networking, fun, and connecting with peers!
Ready to contribute? The Hackday on Saturday, November 28 (free and open to all!) will take place at "The Brain Embassy - Czackiego" thanks to the support of Baksla.sh. Bring your laptop and your good mood!
Tickets are available here: Secure your ticket today!
💡Follow the "conference" blog posts to not miss anything!
Want the latest Symfony updates? Follow us and tune in from wherever you are 🌎
Sponsor the Symfony project.The CollectionType field is the standard way of editing a list of items in a Symfony form, but it has two limitations: all its entries must use the same form type, and submitted rows are matched to entries by their position in the collection. Symfony 8.2 removes both of them.
Consider a CMS page built from a list of blocks, where each block can be a
heading, a paragraph or a footer. Each kind of block needs its own form type, so
a single entry_type option is not enough. The new PolymorphicCollectionType
field lets you declare one form type per kind of entry, and a provider that picks
one of them for each entry:
use App\Form\Block\BlockEntryTypeProvider;
use App\Form\Block\FooterType;
use App\Form\Block\HeadingType;
use App\Form\Block\ParagraphType;
use Symfony\Component\Form\Extension\Core\Type\PolymorphicCollectionType;
// ...
$builder->add('blocks', PolymorphicCollectionType::class, [
'entry_types' => [
'heading' => HeadingType::class,
'paragraph' => ParagraphType::class,
'footer' => FooterType::class,
],
'entry_type_provider' => new BlockEntryTypeProvider(),
'allow_add' => true,
'allow_delete' => true,
]);
When allow_add is enabled, Symfony builds one prototype per entry type and
renders them as data-prototype-<name> HTML attributes (data-prototype-heading,
data-prototype-paragraph, etc.), so your JavaScript code can pick the one to
insert. The entry_options, prototype_options and prototype_data options
work as in CollectionType, but their values are indexed by entry name.
The entry_type_provider option decides which form type each entry uses. The
provider receives the data of an entry in two different shapes, so it defines
two methods:
namespace App\Form\Block;
use App\Entity\Footer;
use App\Entity\Heading;
use Symfony\Component\Form\EntryTypeProviderInterface;
class BlockEntryTypeProvider implements EntryTypeProviderInterface
{
public function forModelData(mixed $data): int|string
{
return match (true) {
$data instanceof Heading => 'heading',
$data instanceof Footer => 'footer',
default => 'paragraph',
};
}
public function forSubmittedData(mixed $data): int|string
{
return $data['type'] ?? 'paragraph';
}
}
The forSubmittedData() method is only needed for entries added in the browser.
Their submitted data only contains the values of their fields, so each entry
type in this example adds a hidden and unmapped type field with its entry name.
The forms of a collection are named after the keys of its entries. If the order
of the entries changes between rendering the form and submitting it (for example,
because another user edited the same data), the values submitted for row 0
are written to whatever entry is now at key 0.
The new entry_name option, available in both CollectionType and
PolymorphicCollectionType, names each form after the entry itself. Its value
can be a property path that is read from each entry:
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
// ...
$builder->add('tags', CollectionType::class, [
'entry_type' => TagType::class,
'entry_name' => 'id',
]);
It can also be a callable that receives the entry and its key, which is useful when some entries don't have an ID yet:
$builder->add('tags', CollectionType::class, [
'entry_type' => TagType::class,
'entry_name' => fn (Tag $tag, int $key) => $tag->getId() ?? 'new_'.$key,
]);
This option only changes how the form identifies each entry, not your data. If
the tag with ID 42 is stored at key 0, its fields are now named
post[tags][42][name] instead of post[tags][0][name], but the submitted
values are still written to that tag and the collection keeps its original keys.
Caution
When using allow_add, a new row whose name matches an existing entry
updates that entry. A numeric counter can match the ID of an entry, so use
names that entries can't have, such as new_1.
Always better when we learn together. SymfonyCon Warsaw 2026 is happening November 26-27, bringing developers together for 3 tracks of presentations and informal networking.
We are delighted to welcome Jonas Kröger, Senior Director, Customer Solutions, Upsun, as he takes the stage with his talk Works on my machine. The agent said so.. We can't wait to share his insights with you!
"What it takes to run coding agents in production across your team.
Every team has a coding agent that ships great code on someone's laptop, and that stops working once the whole team relies on it. Drawing on what we learned running (and building) a software factory at Upsun, we'll dig into a few problems: sandboxing untrusted code, keeping non-deterministic models on a deterministic track, giving agents shared context instead of per-developer prompt files, and evaluating agent work beyond "the tests passed."
Click here to see more talks. The full schedule will be unveiled step-by-step over the coming weeks. Stay tuned!
A special thanks to Upsun for sponsoring this 3rd track on November 27th.
The official conference hotel offers special preferential rates and flexible conditions for our attendees. Make sure to use our dedicated link to book your room and stay right where the action happens!
Because SymfonyCon isn't just about code, we are happy to confirm that our traditional Community Party will take place on the evening of Thursday, November 26. Get ready for a great night of networking, fun, and connecting with peers!
Ready to contribute? The Hackday on Saturday, November 28 (free and open to all!) will take place at "The Brain Embassy - Czackiego" thanks to the support of Baksla.sh. Bring your laptop and your good mood!
Tickets are available here: Secure your ticket today!
💡Follow the "conference" blog posts to not miss anything!
Want the latest Symfony updates? Follow us and tune in from wherever you are 🌎
Sponsor the Symfony project.