Why nano won't save: permission denied
A save that fails in nano has four usual causes. Check the file owner, the parent directory, a read only or full filesystem, then your uid in a container.
Why nano will not save your file
nano will not save your file for one of four reasons: you do not own the file, the parent directory does not allow what nano is trying to do, the filesystem is read only or out of space, or you are inside a container running as a different user ID. The first two are permission problems, and the last two are not. Check them in that order, because the first reason covers most cases, it takes one command to confirm, and the fix for it is sudoedit rather than sudo nano.
Nothing is lost while the editor is still open. Your text sits in memory, so you can leave the file open, write the buffer to a path you do own, and put it in place afterwards. That escape hatch is near the end of this guide.
Run these checks before you change any permissions
Point each command at the real path you are editing. They answer different questions, so run all of them before you touch anything. Changing permissions before you know which check is failing usually creates a second problem on top of the first.
id
ls -l /etc/nginx/nginx.conf
ls -ld /etc/nginx
namei -l /etc/nginx/nginx.conf
findmnt -no SOURCE,FSTYPE,OPTIONS -T /etc/nginx/nginx.conf
df -h /etc/nginx
df -i /etc/nginxid prints the user ID and the group IDs you carry right now. ls -l shows the owner, the group and the permission bits of the file itself. ls -ld shows the same for the directory that holds it, which is a separate question with a separate answer. namei -l walks every part of the path and lists the owner and permissions of each part, so it answers both questions in one output. findmnt names the filesystem under that path and the options it was mounted with. df -h reports free space, and df -i reports free inodes, which run out separately from space. If those permission strings are not yet familiar, start with how to read the permission string that ls -l prints.
Cause 1: the file belongs to root and you do not
Reading and writing are separate permissions, and most files under /etc are readable by everyone. That is why nano opens the file, shows you the contents, and lets you type freely: none of that touches the disk. The refusal comes at save time, when the kernel compares your user ID and your group IDs against the owner, group and other bits on the file. nano is passing on what the kernel told it, so no nano option changes the outcome.
id and ls -l together settle this. The file is owned by root, you are not root, and the other bits do not grant write. Pressing Ctrl-O again will not help.
Why sudoedit is the right way to edit a root-owned file
SUDO_EDITOR=nano sudoedit /etc/nginx/nginx.confsudo makes a temporary copy of the file with the owner set to you, runs nano on that copy as your own user, then copies the result back into place with root privileges once the editor exits. The editor never runs as root. sudo -e is the same command under a different name. The editor is chosen from SUDO_EDITOR, then VISUAL, then EDITOR, so export EDITOR=nano in your shell profile makes this the default everywhere. If your sudoers has the env_editor flag turned off, those variables are ignored and the editor comes from the editor setting in sudoers instead.
sudo nano also saves the file, and that is the problem. It gives a full interactive editor root privileges over the whole filesystem for as long as the session lasts, so one mistyped path at the save prompt writes your text over a different system file, as root. Working as an ordinary user who calls sudo only for the steps that need it is the habit worth building, and sudoedit is what that habit looks like at the moment you edit a config file.
Two sudoedit rules surprise people. It refuses to edit a symbolic link, and it refuses to edit a file inside a directory that you can write to, unless you are root. The second rule exists because anyone who can write to the directory can swap the file while the editor is open. Both behaviours are the sudoers defaults (sudoedit_follow off, sudoedit_checkdir on). A file that does not exist yet is created for you.
Cause 2: what the parent directory actually controls
Advice written for other editors says a save needs write permission on the directory, because many editors save by writing a new file and renaming it over the old one. nano does not work that way. It opens the file you named and writes into that file, so for a file that already exists the directory's write bit is never consulted.
The directory still decides other things, which is why ls -ld is on the check list:
- Creating a file that does not exist yet needs write and execute permission on the directory, because a new name has to be added to it. Your umask decides the permissions that new file starts with.
- Reaching the file at all needs execute permission, also called search permission, on every directory along the path. One directory missing it blocks everything underneath, and
namei -lshows you which one. - Saving with backups or with file locking turned on writes a second file next to the original, so those features do need a writable directory. Backups are the
-Boption orset backupin a nanorc, and locking is-Gorset locking. Both are off unless you or your distribution turned them on.
Directory permissions carry the same weight elsewhere on the system. The SSH server refuses a key when your home directory or your .ssh directory can be written by other users, which is one common cause of SSH turning your key down at login.
Because nano writes into the file that is already there, the file keeps its inode, which is the on-disk identity behind the name. Anything holding the file open keeps tracking it, and a single file bind mounted into a container keeps working. Editors that save by replacing the file break that mount, because the mount follows the inode and not the name.
Cause 3: the filesystem is read only, or it has nothing left
findmnt reporting ro in the options means the write was never going to succeed. Either the filesystem was mounted that way, through /etc/fstab or a read only bind mount, or the kernel remounted it read only after a disk error. The second case is the serious one. sudo dmesg -T | tail -50 shows the input/output and filesystem errors that led to the remount, and the repair is a filesystem check while it is unmounted, which on a VPS means booting the provider's rescue console.
A full filesystem fails the same write for a different reason. df -h covers the ordinary case. df -i covers the case people miss: inodes come from a fixed pool created when the filesystem was made, and a tree of tiny files can use them all while df -h still shows free gigabytes. When space is gone and nothing obvious is holding it, df and du disagreeing about a full disk covers the deleted-but-still-open file that causes it.
One detail explains a confusing symptom here. ext4 reserves a share of its blocks for root when the filesystem is created, so root keeps writing after ordinary users are refused. sudo then looks like the fix, the disk fills the rest of the way, and the problem returns in a worse form.
Because nano truncates the file before writing the new contents, a write that runs out of space partway can leave the file shorter than it was. Copy a config you care about before editing it on a filesystem that is nearly full. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak keeps the owner, group and permissions on the copy.
Cause 4: you are in a container editing a bind mount
File ownership is numeric. The kernel stores a user ID, and the name you see comes from whichever /etc/passwd does the lookup, so one file can show a name on the host and a different name, or a bare number, inside the container. Compare the numbers rather than the names: run id -u inside the container and ls -ln on the file.
A bind mounted file keeps the ownership it has on the host. When the host file belongs to your user and the container process runs as a different user, the write is refused inside the container, and sudo inside the container does not change the owner on the host. Fix it from the host by setting the owner to the ID the container runs as, or run the container as the ID that already owns the files. Images from linuxserver.io and similar projects expose the PUID and PGID variables that set which user the process runs as.
Two more container cases are worth knowing. A mount made read only with :ro, or a container started with --read-only, refuses writes whatever the ownership says, and cat /proc/mounts inside the container shows the flag. With rootless Podman, a user namespace maps container user IDs onto a range of host IDs, so a file that looks like it belongs to root inside the container belongs to your unprivileged account outside it.
There is also the edit that succeeds and then vanishes. A file you change inside a container, on a path that is not a mount, lives in that container's writable layer, and that layer is discarded when the container is recreated. Change the file on the host side of the mount, or in the image build, if the change is meant to last.
The escape hatch: save it to a path you own
Do not try to gain privileges from inside the editor. Press Ctrl-O, clear the path at the prompt, type a path under your home directory such as /home/you/nginx.conf.new, and press Enter. Then Ctrl-X to leave. Your work is on disk now, owned by you, and the rest is an ordinary file copy.
sudo cp /home/you/nginx.conf.new /etc/nginx/nginx.conf
sudo nginx -tUse cp here rather than mv. cp writes through the file that is already in place, so that file keeps its owner, group and permissions. mv on the same filesystem replaces it with your file, which leaves a config in /etc owned by your user account, and that becomes the next permission problem you have to solve.
Check the result with the tool that owns the file before you reload anything. sudo nginx -t parses the nginx configuration, and sudo sshd -t parses the SSH server configuration. Two files have dedicated editors that do this whole procedure for you: sudo visudo for /etc/sudoers and crontab -e for your own cron jobs. Each edits a temporary copy, checks the syntax, and installs the file only if it parses.
FAQ
Should I use sudo nano or sudoedit to edit a system file?
Use sudoedit. It copies the file to a temporary copy owned by you, runs your editor as your own user, and writes the result back as root when the editor exits, so the editor itself never holds root privileges. Set SUDO_EDITOR, VISUAL or EDITOR to nano to pick nano. sudo nano works too, and it hands an interactive editor root access to every path on the system for the length of the session, which turns one mistyped filename at the save prompt into a damaged system file.
Do I need write permission on the directory to save a file with nano?
Not for a file that already exists. nano writes into the file itself, so the kernel checks the write bit on the file and the execute bit on every directory along the path. The directory's write bit matters when the file does not exist yet, since a new name has to be created, and when backups or file locking are turned on, since both write a second file next to the original.
The owner looks right and the disk is not full. What else can block the write?
Four things. The filesystem may be mounted read only, which findmnt -no OPTIONS -T /etc/nginx/nginx.conf shows. The file may carry the immutable attribute, which lsattr shows and sudo chattr -i removes, and not even root can write the file while it is set. The inode pool may be exhausted while free space remains, which df -i shows. SELinux or AppArmor may deny the write even though the permission bits allow it, and the audit log records the denial against the path you tried.
Where do I put my changes when the file will not save at all?
Press Ctrl-O and give a path you own, under your home directory or anywhere else your user can write. The buffer is still in memory, so nothing you typed is lost. Copy the saved file into place afterwards with sudo cp, which keeps the original file's owner and permissions, then check it with the service's own test command before you reload the service.
Why do my edits inside a Docker container disappear?
When the path is not a mount, the edit lands in that container's writable layer, and that layer is thrown away when the container is replaced. Edit the file on the host side of a bind mount or a volume, or build it into the image. When the path is a bind mount and the save is refused instead, compare id -u inside the container with the numeric owner from ls -ln: the file keeps its host ownership, and the container process has to match it.